Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/dsf
diff options
context:
space:
mode:
Diffstat (limited to 'dsf')
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/.classpath7
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/.options10
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/.project34
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/.settings/.api_filters11
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/.settings/org.eclipse.jdt.core.prefs70
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF47
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/about.html24
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/build.properties17
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/disassembly.gifbin0 -> 145 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/library_obj.gifbin0 -> 338 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/library_syms_obj.gifbin0 -> 570 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/refresh.gifbin0 -> 385 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/refreshall.gifbin0 -> 578 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/refreshalways.gifbin0 -> 358 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/refreshmanual.gifbin0 -> 244 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/icons/refreshonbreak.gifbin0 -> 331 bytes
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/plugin.properties13
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/plugin.xml599
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java143
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java185
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyDropAdapter.java121
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyEditor.java111
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyHyperlinkDetector.java101
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyImageRegistry.java69
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java98
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties89
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyPart.java3441
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java985
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java149
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyView.java98
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java283
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java131
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/EditionFinderJob.java105
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java65
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java24
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java102
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/SourceColorerJob.java78
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java63
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java77
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java167
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java65
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java26
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java60
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java82
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java30
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java58
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/Addr2Line.java25
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java66
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java229
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java1423
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java46
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java40
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/LabelPosition.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java117
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java35
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java187
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourcePosition.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java80
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java84
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java313
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourcePresentationCreator.java350
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTag.java207
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTagProvider.java95
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/DisassemblyIPAnnotation.java79
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourcePresentationCreator.java35
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceRange.java30
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTag.java83
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagListener.java24
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagProvider.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourcePresentationCreatorFactory.java25
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourceTagDamagerRepairer.java375
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/IFileRider.java119
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDDocument.java46
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFile.java480
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFileRider.java149
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDRun.java149
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDTextStore.java874
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringRider.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringTextStore.java70
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/HSL.java111
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/StorageEditorInput.java113
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingIntegerFieldEditor.java95
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingStringFieldEditor.java113
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DsfDebugPreferencePage.java109
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/IntegerWithBooleanFieldEditor.java141
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/MessagesForPreferences.java36
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/StringWithBooleanFieldEditor.java146
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/messages.properties16
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/MessagesForVMActions.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshActionDelegate.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshAllRetargetAction.java37
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshHandler.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RetargetDebugContextAction.java151
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesContribution.java110
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesPropertyTester.java78
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesContribution.java110
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesPropertyTester.java78
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/messages.properties16
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthAction.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthDialog.java180
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneWordWrapAction.java54
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/MessagesForDetailPane.java40
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/TextViewerAction.java86
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/messages.properties25
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java1218
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPaneFactory.java71
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/DsfDebugUITools.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/IDsfDebugUIConstants.java113
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/PreferenceInitializer.java65
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfCommandRunnable.java113
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfResumeCommand.java76
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoCommand.java88
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepOverCommand.java88
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepReturnCommand.java75
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSteppingModeTarget.java80
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSuspendCommand.java75
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java121
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/RefreshAction.java77
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/SelectUpdatePolicyAction.java153
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/DsfSourceDisplayAdapter.java855
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java45
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerManager.java264
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/SourceLookupResult.java129
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/AbstractDebugVMAdapter.java76
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/IDebugVMConstants.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/SteppingController.java572
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/AbstractVMProviderActionDelegate.java107
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/DefaultRefreshAllTarget.java51
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/IRefreshAllTarget.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/VMHandlerUtils.java137
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/AbstractExpressionVMNode.java178
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionColumnPresentation.java74
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionManagerVMNode.java307
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java379
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderContentStragegy.java87
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderModelProxyStrategy.java179
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsBreakpointHitUpdatePolicy.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedEvent.java38
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedUpdateTester.java68
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsManualUpdatePolicy.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionUpdate.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionVMNode.java63
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/InvalidExpressionVMContext.java88
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/MessagesForExpressionVM.java37
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/VMExpressionUpdate.java79
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionCellModifier.java80
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionDelegate.java33
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/messages.properties21
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java191
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java294
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java328
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java154
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java175
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java130
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java724
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java223
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java87
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMNode.java180
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMProvider.java75
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPane.java525
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPaneFactory.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesAbstractDetailPane.java172
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.java37
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.properties25
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValuePreferenceStore.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValuePreferenceStore.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValueVMContext.java20
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/MessagesForNumberFormat.java35
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsContribution.java126
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsPropertyTester.java88
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/messages.properties19
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/MessagesForRegisterVM.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldCellModifier.java199
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java901
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterCellModifier.java158
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterColumnPresentation.java73
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterGroupVMNode.java586
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterRootDMVMNode.java51
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java960
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMProvider.java271
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/SyncRegisterDataAccess.java813
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/messages.properties15
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/BreakpointHitUpdatePolicy.java45
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/MessagesForVMUpdate.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/messages.properties12
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/MessagesForVariablesVM.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java543
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableCellModifier.java138
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableColumnPresentation.java71
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java995
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java140
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/messages.properties16
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java151
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/DisplayDsfExecutor.java258
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/SimpleDisplayExecutor.java74
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerCountingRequestMonitor.java58
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerDataRequestMonitor.java53
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMAdapter.java275
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMContext.java68
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMNode.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMProvider.java722
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java379
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java673
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IRootVMNode.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapter.java36
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapterExtension.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMContext.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMEventListener.java40
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxyExtension.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMNode.java116
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMProvider.java114
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/ModelProxyInstalledEvent.java52
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/RootVMNode.java71
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenCountUpdate.java59
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenUpdate.java122
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMDelta.java358
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMHasChildrenUpdate.java59
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMViewerUpdate.java186
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMAdapter.java102
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMNode.java411
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMProvider.java66
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/CompositeDMVMContext.java70
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/IDMVMContext.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/RootDMVMNode.java92
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/package.html32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IElementPropertiesProvider.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/ILabelAttributeChangedListener.java19
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelAttribute.java109
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColor.java71
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColumnInfo.java158
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelFont.java57
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelImage.java53
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelText.java86
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertyBasedLabelProvider.java268
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/messages.properties11
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java1090
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AllUpdateScope.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AutomaticUpdatePolicy.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProvider.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IElementUpdateTester.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicy.java53
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdateScope.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ManualUpdatePolicy.java106
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/MultiLevelUpdateHandler.java233
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UpdatePolicyDecorator.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UserEditEvent.java37
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.properties14
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/VisibleUpdateScope.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf/.classpath7
-rw-r--r--dsf/org.eclipse.cdt.dsf/.cvsignore1
-rw-r--r--dsf/org.eclipse.cdt.dsf/.options3
-rw-r--r--dsf/org.eclipse.cdt.dsf/.project34
-rw-r--r--dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.core.prefs70
-rw-r--r--dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.ui.prefs3
-rw-r--r--dsf/org.eclipse.cdt.dsf/META-INF/MANIFEST.MF23
-rw-r--r--dsf/org.eclipse.cdt.dsf/about.html24
-rw-r--r--dsf/org.eclipse.cdt.dsf/buckminster.cspex32
-rw-r--r--dsf/org.eclipse.cdt.dsf/build.properties17
-rw-r--r--dsf/org.eclipse.cdt.dsf/make/build.xml10
-rw-r--r--dsf/org.eclipse.cdt.dsf/make/dsf.jardesc16
-rw-r--r--dsf/org.eclipse.cdt.dsf/plugin.properties13
-rw-r--r--dsf/org.eclipse.cdt.dsf/plugin.xml5
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java38
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java99
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java374
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java139
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java23
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java48
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java59
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java108
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java220
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java401
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java682
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java35
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java43
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java141
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java92
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java157
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java60
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java22
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java21
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java42
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html26
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java634
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java505
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java69
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java886
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java36
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java140
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java91
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java22
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java231
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java118
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java51
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java118
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java181
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java208
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java127
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java25
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java39
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java111
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java42
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java54
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java248
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java549
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java45
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java72
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java67
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java64
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java23
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java19
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java39
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java229
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java222
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java43
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java169
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java431
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java99
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/.classpath7
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/.cvsignore1
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/.project28
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/.settings/org.eclipse.jdt.core.prefs65
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/META-INF/MANIFEST.MF24
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/about.html28
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/build.properties22
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/icons/full/obj16/pda.gifbin0 -> 182 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml106
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAAdapterFactory.java266
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAUIPlugin.java155
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/actions/PDATerminateCommand.java130
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDABreakpointAdapter.java225
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDAEditorAdapterFactory.java52
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/AnnotationHover.java50
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistProcessor.java103
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistant.java43
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditor.java49
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditorMessages.properties15
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAScanner.java93
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDASourceViewerConfiguration.java64
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PopFrameActionDelegate.java90
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/TextHover.java83
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/WordFinder.java80
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDAMainTab.java190
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDATabGroup.java44
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/PDAVMAdapter.java54
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDALaunchVMProvider.java71
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAThreadsVMNode.java163
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java187
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/.classpath8
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/.cvsignore1
-rwxr-xr-xdsf/org.eclipse.cdt.examples.dsf.pda/.options1
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/.project28
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/.settings/org.eclipse.jdt.core.prefs70
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/META-INF/MANIFEST.MF21
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/about.html28
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/build.properties22
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/docs/protocol.html308
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/src/org/eclipse/cdt/examples/pdavm/PDAVirtualMachine.java1378
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest10.pda38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest2.pda48
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest3.pda13
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest6.pda31
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest8.pda14
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest9.pda23
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest_children.pda8
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/plugin.xml72
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/readme.html11
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/counter.pda11
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/drop.pda12
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/example.pda35
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/fibonacci.pda32
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/registers.pda72
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/stack.pda21
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/samples/structures.pda23
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/PDAPlugin.java212
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDALineBreakpoint.java83
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDAWatchpoint.java173
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunch.java258
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunchDelegate.java161
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java137
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesShutdownSequence.java142
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABackend.java320
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java135
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpoints.java403
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDACommandControl.java520
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java554
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARegisters.java556
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARunControl.java672
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java478
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStartedEvent.java26
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDATerminatedEvent.java26
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAThreadDMContext.java48
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAVirtualMachineDMContext.java92
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/AbstractPDACommand.java71
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDABitField.java44
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAChildrenCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAClearBreakpointCommand.java36
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDACommandResult.java49
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADataCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADropFrameCommand.java47
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEvalCommand.java45
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEventStopCommand.java44
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAExitCommand.java35
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrame.java47
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommandResult.java31
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAGroupsCommand.java35
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAListResult.java45
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPopDataCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPushDataCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegister.java45
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommand.java35
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommandResult.java41
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAResumeCommand.java42
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetBreakpointCommand.java49
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetDataCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetVarCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommandResult.java42
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommand.java38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommandResult.java32
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepCommand.java47
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepReturnCommand.java47
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASuspendCommand.java42
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMResumeCommand.java39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMSuspendCommand.java39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVarCommand.java39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAWatchCommand.java53
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourceLookupDirector.java25
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourcePathComputerDelegate.java62
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/BasicTests.java134
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/CommandControlTestsBase.java165
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestCommand.java29
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestEvent.java21
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test1.java46
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test10.java82
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test2.java199
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test3.java90
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test6.java84
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test8.java94
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test9.java192
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/util/Launching.java58
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/.classpath8
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/.externalToolBuilders/PreProcessor.launch15
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/.project38
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/.settings/org.eclipse.jdt.core.prefs71
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/META-INF/MANIFEST.MF18
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/about.html24
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/build.properties17
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/build_preprocess.xml54
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/alarm.gifbin0 -> 85 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/alarm_triggered.gifbin0 -> 206 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/layout.gifbin0 -> 857 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/remove.gifbin0 -> 163 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/sample.gifbin0 -> 983 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/icons/timer.gifbin0 -> 153 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/plugin.properties13
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/plugin.xml39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java92
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java39
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java113
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java62
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java99
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java41
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java314
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java197
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html127
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java252
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java107
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java100
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java60
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java184
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java58
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java41
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java169
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java121
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java325
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java61
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java258
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java201
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.pngbin0 -> 14399 bytes
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_ant/org/eclipse/cdt/examples/ant/tasks/PreProcessor.java292
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java276
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java438
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java242
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java70
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java195
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/Async2Plus2.java44
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncHelloWorld.java62
-rw-r--r--dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncQuicksort.java146
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/.classpath7
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/.cvsignore1
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/.project28
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.core.prefs70
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.ui.prefs3
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/META-INF/MANIFEST.MF17
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/about.html24
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/build.properties7
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/plugin.properties13
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/plugin.xml18
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/DsfTestPlugin.java69
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/TestDsfExecutor.java50
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ValueHolder.java28
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfQueryTests.java216
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceProgressTests.java271
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceTests.java315
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/dm/DMContextsTest.java185
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/AbstractService.java110
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event1.java16
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event2.java15
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/EventTest.java147
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service1.java42
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service2.java43
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service3.java50
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/ShutdownSequence.java75
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/StartupSequence.java39
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/MultiInstanceTestService.java59
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/ServiceTests.java277
-rw-r--r--dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/SimpleTestService.java53
546 files changed, 69954 insertions, 0 deletions
diff --git a/dsf/org.eclipse.cdt.dsf.ui/.classpath b/dsf/org.eclipse.cdt.dsf.ui/.classpath
new file mode 100644
index 00000000000..304e86186aa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/.options b/dsf/org.eclipse.cdt.dsf.ui/.options
new file mode 100644
index 00000000000..cda9510d97c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/.options
@@ -0,0 +1,10 @@
+org.eclipse.cdt.dsf.ui/debug = false
+
+org.eclipse.cdt.dsf.ui/debug/vm/contentProvider = false
+org.eclipse.cdt.dsf.ui/debug/vm/delta = false
+org.eclipse.cdt.dsf.ui/debug/vm/cache = false
+org.eclipse.cdt.dsf.ui/debug/vm/presentationId =
+org.eclipse.cdt.dsf.ui/debug/vm/atomicUpdate = false
+
+org.eclipse.cdt.dsf.ui/debug/stepping = false
+org.eclipse.cdt.dsf.ui/debug/disassembly = false
diff --git a/dsf/org.eclipse.cdt.dsf.ui/.project b/dsf/org.eclipse.cdt.dsf.ui/.project
new file mode 100644
index 00000000000..984545aa7a1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.dsf.ui</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>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/.settings/.api_filters b/dsf/org.eclipse.cdt.dsf.ui/.settings/.api_filters
new file mode 100644
index 00000000000..cc3e1bff31e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/.settings/.api_filters
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<component id="org.eclipse.cdt.dsf.ui" version="2">
+ <resource path="src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMAdapter.java" type="org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter">
+ <filter id="338792546">
+ <message_arguments>
+ <message_argument value="org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter"/>
+ <message_argument value="getVMProviderIterable()"/>
+ </message_arguments>
+ </filter>
+ </resource>
+</component>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.dsf.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..5d20faf6545
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Mon Jun 23 15:02:26 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=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=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..78d85557a07
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,47 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Vendor: %providerName
+Bundle-SymbolicName: org.eclipse.cdt.dsf.ui;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.core.variables,
+ org.eclipse.debug.ui,
+ org.eclipse.ui.ide,
+ org.eclipse.jface.text,
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.cdt.dsf,
+ org.eclipse.cdt.dsf.ui,
+ org.eclipse.cdt.core,
+ org.eclipse.cdt.debug.core,
+ org.eclipse.cdt.debug.ui,
+ org.eclipse.jface.text;bundle-version="3.4.0",
+ org.eclipse.ui.editors;bundle-version="3.4.0",
+ org.eclipse.ui.workbench.texteditor;bundle-version="3.4.0",
+ org.eclipse.ui.ide;bundle-version="3.4.0",
+ org.eclipse.cdt.ui;bundle-version="5.0.0",
+ org.eclipse.core.expressions;bundle-version="3.4.0",
+ org.eclipse.core.filesystem;bundle-version="1.2.0"
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.cdt.dsf.debug.ui,
+ org.eclipse.cdt.dsf.debug.ui.actions,
+ org.eclipse.cdt.dsf.debug.ui.contexts,
+ org.eclipse.cdt.dsf.debug.ui.sourcelookup,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.actions,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.expression,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.launch,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.modules,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.register,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.update,
+ org.eclipse.cdt.dsf.debug.ui.viewmodel.variable,
+ org.eclipse.cdt.dsf.ui.concurrent,
+ org.eclipse.cdt.dsf.ui.viewmodel,
+ org.eclipse.cdt.dsf.ui.viewmodel.datamodel,
+ org.eclipse.cdt.dsf.ui.viewmodel.properties,
+ org.eclipse.cdt.dsf.ui.viewmodel.update
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.dsf.ui/about.html b/dsf/org.eclipse.cdt.dsf.ui/about.html
new file mode 100644
index 00000000000..cb740ae8bc8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/about.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>About</title></head><body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/build.properties b/dsf/org.eclipse.cdt.dsf.ui/build.properties
new file mode 100644
index 00000000000..e061b4e53d0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/build.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ about.html
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/disassembly.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/disassembly.gif
new file mode 100644
index 00000000000..34f5290474b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/disassembly.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/library_obj.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/library_obj.gif
new file mode 100644
index 00000000000..dd994fdbe69
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/library_obj.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/library_syms_obj.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/library_syms_obj.gif
new file mode 100644
index 00000000000..7da17d4194e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/library_syms_obj.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/refresh.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/refresh.gif
new file mode 100644
index 00000000000..b6b8dc6836d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/refresh.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/refreshall.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshall.gif
new file mode 100644
index 00000000000..74d1cc35b7c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshall.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/refreshalways.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshalways.gif
new file mode 100644
index 00000000000..2c508633881
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshalways.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/refreshmanual.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshmanual.gif
new file mode 100644
index 00000000000..b4b031e58d9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshmanual.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/icons/refreshonbreak.gif b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshonbreak.gif
new file mode 100644
index 00000000000..f16fbb072f8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/icons/refreshonbreak.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.dsf.ui/plugin.properties b/dsf/org.eclipse.cdt.dsf.ui/plugin.properties
new file mode 100644
index 00000000000..7bed11abaf6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2006 Wind River Systems 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=Debugger Services Framework UI
+providerName=Eclipse.org
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/plugin.xml b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml
new file mode 100644
index 00000000000..8bafbeb2921
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/plugin.xml
@@ -0,0 +1,599 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension point="org.eclipse.debug.core.watchExpressionDelegates">
+ <watchExpressionDelegate
+ debugModel="org.eclipse.cdt.dsf.debug.ui"
+ delegateClass="org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.WatchExpressionDelegate"/>
+ </extension>
+
+ <extension point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.cdt.dsf.debug.ui.PreferenceInitializer"/>
+ </extension>
+
+ <extension point="org.eclipse.ui.editors.annotationTypes">
+ <type
+ name="org.eclipse.cdt.dsf.debug.currentIP">
+ </type>
+ <type
+ name="org.eclipse.cdt.dsf.debug.secondaryIP">
+ </type>
+ </extension>
+
+ <extension point="org.eclipse.ui.editors.markerAnnotationSpecification">
+ <specification
+ annotationImageProvider="org.eclipse.cdt.dsf.debug.ui.sourcelookup.InstructionPointerImageProvider"
+ annotationType="org.eclipse.cdt.dsf.debug.currentIP"
+ colorPreferenceKey="currentIPColor"
+ colorPreferenceValue="198,219,174"
+ highlightPreferenceKey="currentIPHighlight"
+ highlightPreferenceValue="true"
+ label="%debugCurrentInstructionPointer"
+ overviewRulerPreferenceKey="currentIPOverviewRuler"
+ overviewRulerPreferenceValue="true"
+ presentationLayer="6"
+ textPreferenceKey="currentIPIndication"
+ textPreferenceValue="false"
+ verticalRulerPreferenceKey="currentIPVerticalRuler"
+ verticalRulerPreferenceValue="true">
+ </specification>
+ <specification
+ annotationImageProvider="org.eclipse.cdt.dsf.debug.ui.sourcelookup.InstructionPointerImageProvider"
+ annotationType="org.eclipse.cdt.dsf.debug.secondaryIP"
+ colorPreferenceKey="secondaryIPColor"
+ colorPreferenceValue="219,235,204"
+ highlightPreferenceKey="secondaryIPHighlight"
+ highlightPreferenceValue="true"
+ label="%debugCallStack"
+ overviewRulerPreferenceKey="secondaryIPOverviewRuler"
+ overviewRulerPreferenceValue="true"
+ presentationLayer="6"
+ textPreferenceKey="secondaryIPIndication"
+ textPreferenceValue="false"
+ verticalRulerPreferenceKey="secondaryIPVerticalRuler"
+ verticalRulerPreferenceValue="true">
+ </specification>
+ </extension>
+
+ <extension point="org.eclipse.ui.viewActions">
+ <!-- Variables View menu contributions -->
+ <viewContribution
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.Refresh"
+ targetID="org.eclipse.debug.ui.VariableView">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshActionDelegate"
+ icon="icons/refresh.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.actions.Refresh"
+ label="%action.refresh.label"
+ toolbarPath="additions">
+ </action>
+ </viewContribution>
+
+ <!-- Registers View menu contributions -->
+ <viewContribution
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.Refresh"
+ targetID="org.eclipse.debug.ui.RegisterView">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshActionDelegate"
+ icon="icons/refresh.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.actions.Refresh"
+ label="%action.refresh.label"
+ toolbarPath="additions">
+ </action>
+ </viewContribution>
+
+ <!-- Expressions View menu contributions -->
+ <viewContribution
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.Refresh"
+ targetID="org.eclipse.debug.ui.ExpressionView">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshActionDelegate"
+ icon="icons/refresh.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.actions.Refresh"
+ label="%action.refresh.label"
+ toolbarPath="additions">
+ </action>
+ </viewContribution>
+
+ <!-- Debug View menu contributions -->
+ <viewContribution
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.debugView.Refresh"
+ targetID="org.eclipse.debug.ui.DebugView">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshActionDelegate"
+ icon="icons/refresh.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.update.actions.Refresh"
+ label="%action.refresh.label"
+ toolbarPath="additions">
+ </action>
+ </viewContribution>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.menus">
+ <!-- Debug view menu commands -->
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.DebugView?after=additions">
+ <separator name="additions" visible="false"/>
+ <separator name="updatePolicy" visible="true"/>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.DebugView?after=updatePolicy">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.debugView_updatePolicies"
+ label="%menu.threadsUpdatePolicy">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.UpdatePolicies"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesContribution">
+ </dynamic>
+ </menu>
+ </menuContribution>
+
+ <!-- Registers view menu commands -->
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.RegisterView?after=additions">
+ <separator name="additions" visible="false"/>
+ <separator name="formatting" visible="true"/>
+ <separator name="updatePolicy" visible="true"/>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.RegisterView?after=updatePolicy">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.registersView_updatePolicies"
+ label="%menu.updatePolicy">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.registersUpdatePolicies"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesContribution">
+ </dynamic>
+ </menu>
+ <!-- bug 251769 Hide update scopes in 1.1
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.registersView_updateScopes"
+ label="%menu.updateScope">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.registersUpdateScopes"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdateScopesContribution">
+ </dynamic>
+ </menu>
+ -->
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.RegisterView?after=formatting">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.registersView_numberFormats"
+ label="%menu.numberFormat">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testAreNumberFormatsSupported"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.registersNumberFormats"
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.NumberFormatsContribution">
+ </dynamic>
+ </menu>
+ </menuContribution>
+
+ <!-- Variables view menu commands -->
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.VariableView?after=additions">
+ <separator name="additions" visible="false"/>
+ <separator name="formatting" visible="true"/>
+ <separator name="updatePolicy" visible="true"/>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.VariableView?after=updatePolicy">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.variablesView_updatePolicies"
+ label="%menu.updatePolicy">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.variablesUpdatePolicies"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesContribution">
+ </dynamic>
+ </menu>
+ <!-- bug 251769 Hide update scopes in 1.1
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.variablesView_updateScopes"
+ label="%menu.updateScope">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.variablesUpdateScopes"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdateScopesContribution">
+ </dynamic>
+ </menu>
+ -->
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.VariableView?after=formatting">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.variablesView_numberFormats"
+ label="%menu.numberFormat">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testAreNumberFormatsSupported"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.variablesNumberFormats"
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.NumberFormatsContribution">
+ </dynamic>
+ </menu>
+ </menuContribution>
+
+ <!-- Expressions view menu commands -->
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.ExpressionView?after=additions">
+ <separator name="additions" visible="false"/>
+ <separator name="formatting" visible="true"/>
+ <separator name="updatePolicy" visible="true"/>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.ExpressionView?after=updatePolicy">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.expressionsView_updatePolicies"
+ label="%menu.updatePolicy">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.expressionUpdatePolicies"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesContribution">
+ </dynamic>
+ </menu>
+ <!-- bug 251769 Hide update scopes in 1.1
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.expressionsView_updateScopes"
+ label="%menu.updateScope">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.expressionUpdateScopes"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdateScopesContribution">
+ </dynamic>
+ </menu>
+ -->
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:org.eclipse.debug.ui.ExpressionView?after=formatting">
+ <menu
+ id="org.eclipse.cdt.dsf.debug.ui.expressionsView_numberFormats"
+ label="%menu.numberFormat">
+ <visibleWhen checkEnabled="false">
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testAreNumberFormatsSupported"/>
+ </visibleWhen>
+ <dynamic
+ id="org.eclipse.cdt.dsf.debug.ui.expressionNumberFormats"
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.NumberFormatsContribution">
+ </dynamic>
+ </menu>
+ </menuContribution>
+ </extension>
+
+ <extension point="org.eclipse.ui.handlers">
+ <handler
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshHandler"
+ commandId="org.eclipse.ui.file.refresh">
+ <activeWhen>
+ <reference definitionId="org.eclipse.cdt.dsf.debug.ui.testAreUpdatePoliciesSupported"/>
+ </activeWhen>
+ </handler>
+ </extension>
+
+ <extension point="org.eclipse.core.expressions.definitions">
+ <definition id="org.eclipse.cdt.dsf.debug.ui.testIsUpdateModesActionSetActive">
+ <and>
+ <with variable="activeContexts">
+ <iterate operator="or">
+ <equals value="org.eclipse.cdt.dsf.debug.ui.updateModes"/>
+ </iterate>
+ </with>
+ </and>
+ </definition>
+ <definition id="org.eclipse.cdt.dsf.debug.ui.testAreUpdatePoliciesSupported">
+ <and>
+ <with variable="org.eclipse.core.runtime.Platform">
+ <test property="org.eclipse.core.runtime.bundleState"
+ args="org.eclipse.cdt.dsf.debug.ui"
+ value="ACTIVE"/>
+ </with>
+ <or>
+ <with variable="activePart">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areUpdatePoliciesSupported"/>
+ </with>
+ <with variable="selection">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areUpdatePoliciesSupported"/>
+ </with>
+ </or>
+ </and>
+ </definition>
+ <definition id="org.eclipse.cdt.dsf.debug.ui.testAreUpdateScopesSupported">
+ <and>
+ <with variable="org.eclipse.core.runtime.Platform">
+ <test property="org.eclipse.core.runtime.bundleState"
+ args="org.eclipse.cdt.dsf.debug.ui"
+ value="ACTIVE"/>
+ </with>
+ <or>
+ <with variable="activePart">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areUpdateScopesSupported"/>
+ </with>
+ <with variable="selection">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areUpdateScopesSupported"/>
+ </with>
+ </or>
+ </and>
+ </definition>
+ <definition
+ id="org.eclipse.cdt.dsf.debug.ui.testAreNumberFormatsSupported">
+ <and>
+ <with variable="org.eclipse.core.runtime.Platform">
+ <test property="org.eclipse.core.runtime.bundleState"
+ args="org.eclipse.cdt.dsf.debug.ui"
+ value="ACTIVE"/>
+ </with>
+ <or>
+ <with variable="activePart">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areNumberFormatsSupported"/>
+ </with>
+ <with variable="selection">
+ <test property="org.eclipse.cdt.dsf.debug.ui.areNumberFormatsSupported"/>
+ </with>
+ </or>
+ </and>
+ </definition>
+ </extension>
+
+ <extension
+ point="org.eclipse.core.expressions.propertyTesters">
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.selectionUpdatePoliciesTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areUpdatePoliciesSupported,isUpdatePolicyAvailable,isUpdatePolicyActive"
+ type="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
+ </propertyTester>
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdatePoliciesPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.partUpdatePoliciesTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areUpdatePoliciesSupported,isUpdatePolicyAvailable,isUpdatePolicyActive"
+ type="org.eclipse.debug.ui.IDebugView">
+ </propertyTester>
+
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdateScopesPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.selectionUpdateScopesTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areUpdateScopesSupported,isUpdateScopeAvailable,isUpdateScopeActive"
+ type="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
+ </propertyTester>
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.UpdateScopesPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.partUpdateScopesTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areUpdateScopesSupported,isUpdateScopeAvailable,isUpdateScopeActive"
+ type="org.eclipse.debug.ui.IDebugView">
+ </propertyTester>
+
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.NumberFormatsPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.selectionNumberFormatsTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areNumberFormatsSupported,isNumberFormatAvailable,isNumberFormatActive"
+ type="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
+ </propertyTester>
+ <propertyTester
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.NumberFormatsPropertyTester"
+ id="org.eclipse.cdt.dsf.debug.ui.partNumberFormatsTester"
+ namespace="org.eclipse.cdt.dsf.debug.ui"
+ properties="areNumberFormatsSupported,isNumberFormatAvailable,isNumberFormatActive"
+ type="org.eclipse.debug.ui.IDebugView">
+ </propertyTester>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.detailPaneFactories">
+ <detailFactories
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.numberformat.detail.NumberFormatDetailPaneFactory"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.detailPaneFactory">
+ <enablement>
+ <with variable="selection">
+ <iterate>
+ <instanceof value="org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext"/>
+ </iterate>
+ </with>
+ </enablement>
+ </detailFactories>
+ <detailFactories
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail.ModuleDetailPaneFactory"
+ id="org.eclipse.cdt.dsf.debug.ui.viewmodel.moduleDetailPaneFactory">
+ <enablement>
+ <with variable="selection">
+ <iterate>
+ <instanceof value="org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.ModulesVMNode$ModuleVMContext"/>
+ </iterate>
+ </with>
+ </enablement>
+ </detailFactories>
+ </extension>
+
+ <extension point="org.eclipse.ui.commands">
+ <command
+ categoryId="org.eclipse.debug.ui.category.run"
+ description="%command.gotoPC.description"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoPC"
+ name="%command.gotoPC.name"/>
+ <command
+ categoryId="org.eclipse.debug.ui.category.run"
+ description="%command.gotoAddress.description"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoAddress"
+ name="%command.gotoAddress.name"/>
+ <command
+ categoryId="org.eclipse.debug.ui.category.run"
+ description="%command.gotoSymbol.description"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoSymbol"
+ name="%command.gotoSymbol.name"/>
+ </extension>
+
+ <extension point="org.eclipse.ui.bindings">
+ <key sequence="HOME"
+ contextId="org.eclipse.cdt.dsf.debug.ui.disassembly.context"
+ commandId="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoPC"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
+ <key sequence="M1+G"
+ contextId="org.eclipse.cdt.dsf.debug.ui.disassembly.context"
+ commandId="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoAddress"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
+ <key sequence="M1+M2+G"
+ contextId="org.eclipse.cdt.dsf.debug.ui.disassembly.context"
+ commandId="org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoSymbol"
+ schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.contexts">
+ <context
+ description="%commandContext.description"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.context"
+ name="%commandContext.name"
+ parentId="org.eclipse.debug.ui.debugging">
+ </context>
+ </extension>
+
+ <extension
+ point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.cdt.dsf.debug.internal.ui.disassembly.preferences.DisassemblyPreferenceConstants$Initializer"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ category="org.eclipse.debug.ui"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyView"
+ icon="icons/disassembly.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.view"
+ name="%disassemblyView.name">
+ </view>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.preferencePages">
+ <page
+ category="org.eclipse.debug.ui.DebugPreferencePage"
+ class="org.eclipse.cdt.dsf.debug.internal.ui.preferences.DsfDebugPreferencePage"
+ id="org.eclipse.cdt.dsf.debug.ui.preferences"
+ name="%preferencePage.name">
+ </page>
+ <page
+ class="org.eclipse.cdt.dsf.debug.internal.ui.disassembly.preferences.DisassemblyPreferencePage"
+ category="org.eclipse.cdt.dsf.debug.ui.preferences"
+ name="%disassemblyPreferencePage.name"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.preferencePage"/>
+ </extension>
+ <extension
+ point="org.eclipse.ui.popupMenus">
+ <viewerContribution
+ id="org.eclipse.cdt.dsf.debug.ui.disassemblyRulerActions"
+ targetID="#DisassemblyPartRulerContext">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.BreakpointPropertiesRulerActionDelegate"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.breakpointProperties"
+ label="%action.breakpointProperties.label"
+ menubarPath="debug">
+ </action>
+ </viewerContribution>
+ </extension>
+
+
+ <!-- memory update policy -->
+ <extension
+ point="org.eclipse.ui.viewActions">
+ <viewContribution
+ targetID="org.eclipse.debug.ui.MemoryView"
+ id="org.eclipse.debug.ui.memoryView.toolbar">
+ <action
+ class="org.eclipse.cdt.dsf.debug.ui.memory.RefreshAction"
+ enablesFor="1"
+ icon="icons/refresh.gif"
+ id="org.eclipse.debug.ui.MemoryView.memoryViewRefresh"
+ label="Refresh"
+ toolbarPath="additions">
+ </action>
+ </viewContribution>
+ </extension>
+ <extension
+ point="org.eclipse.ui.viewActions">
+ <viewContribution
+ id="org.eclipse.debug.ui.MemoryView.updatepolicy"
+ targetID="org.eclipse.debug.ui.MemoryView">
+ <action
+ class="org.eclipse.cdt.dsf.debug.ui.memory.SelectUpdatePolicyAction"
+ id="org.eclipse.debug.ui.MemoryView.updatepolicy"
+ label="Update Policy"
+ menubarPath="additions">
+ </action>
+ </viewContribution>
+ </extension>
+
+ <!-- Debug view context menu contributions -->
+ <extension point="org.eclipse.ui.popupMenus">
+ <objectContribution
+ adaptable="false"
+ id="org.eclipse.cdt.dsf.debug.ui.objectContribution.incompleteStack"
+ objectClass="org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode$IncompleteStackVMContext">
+ <action
+ class="org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.actions.ExpandStackAction"
+ id="org.eclipse.cdt.dsf.debug.ui.action.expandStack"
+ label="%action.expandStack.label"
+ menubarPath="renderGroup">
+ </action>
+ </objectContribution>
+ </extension>
+ <extension
+ point="org.eclipse.ui.actionSets">
+ <actionSet
+ id="org.eclipse.cdt.dsf.debug.ui.updateModes"
+ label="Debug Update Modes">
+ <action
+ class="org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.RefreshAllRetargetAction"
+ definitionId="org.eclipse.cdt.dsf.debug.ui.refreshAll"
+ helpContextId="org.eclipse.cdt.dsf.debug.ui.refreshAll_context"
+ icon="icons/refreshall.gif"
+ id="org.eclipse.cdt.dsf.debug.ui.refreshAll"
+ label="%action.refreshAll.name"
+ menubarPath="window/additions"
+ toolbarPath="org.eclipse.ui.dd.dsf.debug.ui.actionSet.update_modes/debugUpdateModes">
+ </action>
+ </actionSet>
+ </extension>
+
+ <!-- Debug perspective extension -->
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension
+ targetID="org.eclipse.debug.ui.DebugPerspective">
+ <view
+ relative="org.eclipse.ui.views.ContentOutline"
+ visible="false"
+ relationship="stack"
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.view">
+ </view>
+ <viewShortcut
+ id="org.eclipse.cdt.dsf.debug.ui.disassembly.view">
+ </viewShortcut>
+ </perspectiveExtension>
+ </extension>
+
+
+</plugin>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java
new file mode 100644
index 00000000000..8150df5b347
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AbstractImageRegistry.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Image;
+import org.osgi.framework.Bundle;
+
+
+/**
+ * Abstract image registry that allows for defining fallback paths for images.
+ */
+public abstract class AbstractImageRegistry extends ImageRegistry {
+ private HashMap<String, String> fPlugins = new HashMap<String, String>();
+ private HashMap<String, String[]> fLocations = new HashMap<String, String[]>();
+ private URL fBaseUrl;
+
+ protected AbstractImageRegistry(Plugin plugin) {
+ fBaseUrl = plugin.getBundle().getEntry("/"); //$NON-NLS-1$
+ }
+
+ /**
+ * Defines the key for a local image, that must be found below the icons directory
+ * in the plugin.
+ * @param key Key by which the image can be referred by.
+ * @param dir Directory relative to icons/
+ * @param name The name of the file defining the icon. The name will be used as
+ * key.
+ */
+ protected void localImage(String key, String dir, String name) {
+ if (dir== null || dir.equals(""))//$NON-NLS-1$
+ fLocations.put(key, new String[] {"icons/" + name}); //$NON-NLS-1$
+ else
+ fLocations.put(key, new String[] {"icons/" + dir + "/" + name}); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Defines the key for a non-local image, that must be found below the icons directory
+ * of some plugin.
+ * @param key Key by which the image can be referred by.
+ * @param plugin The plugin id, where the icon is searched.
+ * @param dirs A couple of directories below icons/ in the plugin. If loading fails,
+ * the next dir will be taken as fallback.
+ * @param name The name of the file defining the icon. The name will be used as
+ * key.
+ */
+ protected void externalImage(String key, String plugin, String[] dirs, String name) {
+ if (plugin != null) {
+ fPlugins.put(key, plugin);
+ }
+ String[] locations = new String[dirs.length];
+ for (int i = 0; i < dirs.length; i++) {
+ String dir = dirs[i];
+ if (dir== null || dir.equals(""))//$NON-NLS-1$
+ locations[i] = "icons/" + name; //$NON-NLS-1$
+ else
+ locations[i] = "icons/" + dir + "/" + name; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ fLocations.put(key, locations);
+ }
+
+ // overrider
+ @Override
+ final public Image get(String key) {
+ Image i = super.get(key);
+ if (i != null) {
+ return i;
+ }
+
+ ImageDescriptor d = createFileImageDescriptor(key);
+ if (d != null) {
+ put(key, d);
+ return super.get(key);
+ }
+ return null;
+ }
+
+ // overrider
+ @Override
+ final public ImageDescriptor getDescriptor(String key) {
+ ImageDescriptor d = super.getDescriptor(key);
+ if (d != null) {
+ return d;
+ }
+
+ d = createFileImageDescriptor(key);
+ if (d != null) {
+ put(key, d);
+ return d;
+ }
+ return null;
+ }
+
+ private ImageDescriptor createFileImageDescriptor(String key) {
+ URL url = fBaseUrl;
+ String pluginId = fPlugins.get(key);
+ if (pluginId != null) {
+ Bundle bundle= Platform.getBundle(pluginId);
+ if (bundle != null) {
+ url = bundle.getEntry("/"); //$NON-NLS-1$
+ }
+ }
+ String[] locations= fLocations.get(key);
+ if (locations != null) {
+ for (int i = 0; i < locations.length; i++) {
+ String loc = locations[i];
+ URL full;
+ try {
+ full = new URL(url, loc);
+ ImageDescriptor candidate = ImageDescriptor.createFromURL(full);
+ if (candidate != null && candidate.getImageData() != null) {
+ return candidate;
+ }
+ } catch (MalformedURLException e) {
+ DsfUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, "Malformed Icon URL", e)); //$NON-NLS-1$
+ } catch (SWTException e) {
+ // try the next one.
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java
new file mode 100644
index 00000000000..54a4c31bc87
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/AddressRulerColumn.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.AddressRangePosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourceFileInfo;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourcePosition;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.text.source.IVerticalRulerInfoExtension;
+import org.eclipse.jface.text.source.IVerticalRulerListener;
+import org.eclipse.swt.SWT;
+
+/**
+ * A vertical ruler column to display the instruction address.
+ */
+public class AddressRulerColumn extends DisassemblyRulerColumn implements IVerticalRulerInfo, IVerticalRulerInfoExtension, IAnnotationHover {
+
+ private int fRadix;
+ private boolean fShowRadixPrefix;
+ private String fRadixPrefix;
+ private int fNumberOfDigits;
+ private int fAddressSize;
+
+ /**
+ * Default constructor.
+ */
+ public AddressRulerColumn() {
+ super(SWT.LEFT);
+ setShowRadixPrefix(true);
+ setAddressSize(32);
+ setRadix(16);
+ }
+
+ @Override
+ protected String createDisplayString(int line) {
+ DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument();
+ int offset;
+ try {
+ offset = doc.getLineOffset(line);
+ AddressRangePosition pos = doc.getDisassemblyPosition(offset);
+ if (pos != null && pos.length > 0 && pos.offset == offset) {
+ if (pos.fValid) {
+ return getAddressText(pos.fAddressOffset);
+ } else {
+ return DOTS.substring(0, computeNumberOfCharacters());
+ }
+ }
+ SourcePosition srcPos = doc.getSourcePosition(offset);
+ if (srcPos != null && srcPos.fValid && srcPos.length > 0) {
+ int srcLine;
+ int nLines;
+ if (srcPos.fFileInfo.fSource == null) {
+ srcLine = srcPos.fLine;
+ nLines = srcLine+1;
+ } else {
+ int delta = offset-srcPos.offset;
+ int baseOffset = srcPos.fFileInfo.fSource.getLineOffset(srcPos.fLine);
+ srcLine = srcPos.fFileInfo.fSource.getLineOfOffset(baseOffset+delta);
+ nLines = srcPos.fFileInfo.fSource.getNumberOfLines();
+ }
+ String digitStr = Integer.toString(srcLine+1);
+ int maxDigits = (int)(Math.log(nLines)/Math.log(10))+1;
+ return SPACES.substring(0, maxDigits-digitStr.length())+digitStr;
+ }
+ } catch (BadLocationException e) {
+ // silently ignored
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ protected int computeNumberOfCharacters() {
+ return fNumberOfDigits + (fRadixPrefix != null ? fRadixPrefix.length() : 0) + 1;
+ }
+
+ public void setAddressSize(int bits) {
+ fAddressSize= bits;
+ calculateNumberOfDigits();
+ }
+
+ public void setRadix(int radix) {
+ fRadix= radix;
+ calculateNumberOfDigits();
+ setShowRadixPrefix(fShowRadixPrefix);
+ }
+
+ private void calculateNumberOfDigits() {
+ fNumberOfDigits= BigInteger.ONE.shiftLeft(fAddressSize).subtract(BigInteger.ONE).toString(fRadix).length();
+ }
+
+ public void setShowRadixPrefix(boolean showRadixPrefix) {
+ fShowRadixPrefix = showRadixPrefix;
+ if (!fShowRadixPrefix) {
+ fRadixPrefix = null;
+ } else if (fRadix == 16) {
+ fRadixPrefix = "0x"; //$NON-NLS-1$
+ } else if (fRadix == 8) {
+ fRadixPrefix = "0"; //$NON-NLS-1$
+ } else {
+ fRadixPrefix = null;
+ }
+ }
+
+ private String getAddressText(BigInteger address) {
+ StringBuffer buf = new StringBuffer(fNumberOfDigits + 3);
+ if (fRadixPrefix != null) {
+ buf.append(fRadixPrefix);
+ }
+ String str = address.toString(fRadix);
+ for (int i=str.length(); i<fNumberOfDigits; ++i)
+ buf.append('0');
+ buf.append(str);
+ buf.append(':');
+ return buf.toString();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfo#getLineOfLastMouseButtonActivity()
+ */
+ public int getLineOfLastMouseButtonActivity() {
+ return getParentRuler().getLineOfLastMouseButtonActivity();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfo#toDocumentLineNumber(int)
+ */
+ public int toDocumentLineNumber(int y_coordinate) {
+ return getParentRuler().toDocumentLineNumber(y_coordinate);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfoExtension#getHover()
+ */
+ public IAnnotationHover getHover() {
+ return this;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfoExtension#getModel()
+ */
+ public IAnnotationModel getModel() {
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfoExtension#addVerticalRulerListener(org.eclipse.jface.text.source.IVerticalRulerListener)
+ */
+ public void addVerticalRulerListener(IVerticalRulerListener listener) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IVerticalRulerInfoExtension#removeVerticalRulerListener(org.eclipse.jface.text.source.IVerticalRulerListener)
+ */
+ public void removeVerticalRulerListener(IVerticalRulerListener listener) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IAnnotationHover#getHoverInfo(org.eclipse.jface.text.source.ISourceViewer, int)
+ */
+ public String getHoverInfo(ISourceViewer sourceViewer, int line) {
+ DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument();
+ BigInteger address = doc.getAddressOfLine(line);
+ SourceFileInfo info = doc.getSourceInfo(address);
+ if (info != null) {
+ return info.fFile.getFullPath().toOSString();
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyDropAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyDropAdapter.java
new file mode 100644
index 00000000000..cf6f4de052c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyDropAdapter.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.swt.dnd.*;
+
+/**
+ * DisassemblyDropAdapter
+ */
+public class DisassemblyDropAdapter extends DropTargetAdapter {
+
+ private DisassemblyPart fDisassembly;
+
+ /**
+ * New DisassemblyDropAdapter.
+ */
+ public DisassemblyDropAdapter(DisassemblyPart disassembly) {
+ super();
+ fDisassembly = disassembly;
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#drop(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void drop(final DropTargetEvent event) {
+ TransferData dataType = event.currentDataType;
+ if (isFileDataType(dataType)) {
+ // event.data is an array of strings which represent the absolute file pathes
+ assert event.data instanceof String[];
+ String fileNames[] = (String[])event.data;
+ dropFiles(fileNames);
+ } else if (isTextDataType(dataType)) {
+ // event.data is a string
+ assert event.data instanceof String;
+ String text = (String)event.data;
+ if (text.indexOf('/') != -1 || text.indexOf('.') != -1) {
+ dropFiles(new String[] { text });
+ } else {
+ dropText(text);
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#dragEnter(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ event.detail = DND.DROP_COPY;
+ event.feedback = DND.FEEDBACK_NONE;
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#dragOver(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void dragOver(DropTargetEvent event) {
+ event.detail = DND.DROP_COPY;
+ event.feedback = DND.FEEDBACK_NONE;
+ }
+
+ private static boolean isFileDataType(TransferData dataType) {
+ return FileTransfer.getInstance().isSupportedType(dataType);
+ }
+ private static boolean isTextDataType(TransferData dataType) {
+ return TextTransfer.getInstance().isSupportedType(dataType);
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#dropAccept(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void dropAccept(DropTargetEvent event) {
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#dragOperationChanged(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void dragOperationChanged(DropTargetEvent event) {
+ event.detail = DND.DROP_COPY;
+ event.feedback = DND.FEEDBACK_NONE;
+ }
+
+ /*
+ * @see org.eclipse.swt.dnd.DropTargetListener#dragLeave(org.eclipse.swt.dnd.DropTargetEvent)
+ */
+ @Override
+ public void dragLeave(DropTargetEvent event) {
+ }
+
+ /**
+ * Drop files.
+ * @param fileNames
+ */
+ private void dropFiles(String[] fileNames) {
+ // open all the files
+ for (int i = 0; i < fileNames.length; i++) {
+ // get disassembly for file
+ fDisassembly.retrieveDisassembly(fileNames[i], 100, true);
+ }
+ }
+
+ /**
+ * Drop text.
+ * @param text
+ */
+ private void dropText(String text) {
+ fDisassembly.gotoSymbol(text.trim());
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyEditor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyEditor.java
new file mode 100644
index 00000000000..8db2f6a9b83
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyEditor.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * DisassemblyEditor
+ */
+public class DisassemblyEditor extends DisassemblyPart implements IEditorPart {
+
+ private IEditorInput fInput;
+
+ /**
+ *
+ */
+ public DisassemblyEditor() {
+ super();
+ }
+
+ @Override
+ protected IActionBars getActionBars() {
+ return getEditorSite().getActionBars();
+ }
+
+ /*
+ * @see org.eclipse.ui.IEditorPart#getEditorInput()
+ */
+ public IEditorInput getEditorInput() {
+ return fInput;
+ }
+
+ /*
+ * @see org.eclipse.ui.IEditorPart#getEditorSite()
+ */
+ public IEditorSite getEditorSite() {
+ return (IEditorSite)getSite();
+ }
+
+ /*
+ * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
+ */
+ public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+ setSite(site);
+ setInput(input);
+ }
+
+ /*
+ * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ public void doSave(IProgressMonitor monitor) {
+ }
+
+ /*
+ * @see org.eclipse.ui.ISaveablePart#doSaveAs()
+ */
+ public void doSaveAs() {
+ }
+
+ /*
+ * @see org.eclipse.ui.ISaveablePart#isDirty()
+ */
+ public boolean isDirty() {
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
+ */
+ public boolean isSaveAsAllowed() {
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.ui.ISaveablePart#isSaveOnCloseNeeded()
+ */
+ public boolean isSaveOnCloseNeeded() {
+ return false;
+ }
+
+ //
+ // IReusableEditor interface
+ //
+
+ /*
+ * @see org.eclipse.ui.IReusableEditor#setInput(org.eclipse.ui.IEditorInput)
+ */
+ public void setInput(IEditorInput input) {
+ fInput = input;
+ // TLETODO [disassembly] initialization based on input
+ }
+
+ @Override
+ protected void closePart() {
+ getEditorSite().getPage().closeEditor(this, false);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyHyperlinkDetector.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyHyperlinkDetector.java
new file mode 100644
index 00000000000..8e9a126ac20
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyHyperlinkDetector.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.cdt.internal.ui.text.CWordFinder;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.hyperlink.AbstractHyperlinkDetector;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+
+/**
+ * A hyperlink detector detecting words and numbers to support navigation
+ * to a symbolic address.
+ */
+@SuppressWarnings("restriction")
+class DisassemblyHyperlinkDetector extends AbstractHyperlinkDetector {
+
+ public class DisassemblyHyperlink implements IHyperlink {
+
+ private String fSymbol;
+ private IRegion fRegion;
+
+ /**
+ * @param symbol
+ * @param region
+ */
+ public DisassemblyHyperlink(String symbol, IRegion region) {
+ fSymbol= symbol;
+ fRegion= region;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkRegion()
+ */
+ public IRegion getHyperlinkRegion() {
+ return fRegion;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getHyperlinkText()
+ */
+ public String getHyperlinkText() {
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#getTypeLabel()
+ */
+ public String getTypeLabel() {
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlink#open()
+ */
+ public void open() {
+ if (fPart != null) {
+ fPart.gotoSymbol(fSymbol);
+ }
+ }
+
+ }
+
+ private DisassemblyPart fPart;
+
+ public DisassemblyHyperlinkDetector(DisassemblyPart part) {
+ fPart= part;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean)
+ */
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer,
+ IRegion region, boolean canShowMultipleHyperlinks) {
+ IDocument document= textViewer.getDocument();
+ if (document == null) {
+ return null;
+ }
+ IRegion wordRegion = CWordFinder.findWord(document, region.getOffset());
+ if (wordRegion != null && wordRegion.getLength() != 0) {
+ String word;
+ try {
+ word= document.get(wordRegion.getOffset(), wordRegion.getLength());
+ return new IHyperlink[] { new DisassemblyHyperlink(word, wordRegion) };
+ } catch (BadLocationException e) {
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyImageRegistry.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyImageRegistry.java
new file mode 100644
index 00000000000..c6bf4e5668e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyImageRegistry.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * DisassemblyImageRegistry
+ */
+public class DisassemblyImageRegistry extends AbstractImageRegistry {
+ private static List<Object[]> fStore = new ArrayList<Object[]>();
+
+ private static String add(String plugin, String[] dirs, String name) {
+ String key = plugin+'/'+dirs[0]+'/'+name;
+ fStore.add(new Object[] {key, plugin, dirs, name});
+ return key;
+ }
+
+ private static final String ORG_ECLIPSE_DEBUG_UI_PLUGIN_ID = "org.eclipse.debug.ui"; //$NON-NLS-1$
+ private static final String ORG_ECLIPSE_UI_PLUGIN_ID = "org.eclipse.ui"; //$NON-NLS-1$
+
+ public static final String ICON_ToggleBreakpoint = add(ORG_ECLIPSE_DEBUG_UI_PLUGIN_ID, new String[] { "full/obj16"}, "brkp_obj.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String ICON_Refresh_enabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/elcl16"}, "refresh_nav.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String ICON_Refresh_disabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/dlcl16"}, "refresh_nav.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String ICON_Copy_enabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/etool16"}, "copy_edit.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ public static final String ICON_Copy_disabled = add(ORG_ECLIPSE_UI_PLUGIN_ID, new String[] {"full/dtool16"}, "copy_edit.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ private static DisassemblyImageRegistry INSTANCE= new DisassemblyImageRegistry(DsfUIPlugin.getDefault());
+
+ DisassemblyImageRegistry(Plugin plugin) {
+ super(plugin);
+ initialize();
+ }
+
+ void initialize() {
+ for (Iterator<Object[]> iter = fStore.iterator(); iter.hasNext();) {
+ Object[] element = iter.next();
+ if (element.length == 2) {
+ String dir= (String) element[0];
+ String name= (String) element[1];
+ localImage(name, dir, name);
+ } else {
+ String key = (String) element[0];
+ String plugin= (String) element[1];
+ String[] dirs= (String[]) element[2];
+ String name= (String) element[3];
+ externalImage(key, plugin, dirs, name);
+ }
+ }
+ }
+
+ public static ImageDescriptor getImageDescriptor(String key) {
+ return INSTANCE.getDescriptor(key);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java
new file mode 100644
index 00000000000..3091a363909
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.osgi.util.NLS;
+
+public final class DisassemblyMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages";//$NON-NLS-1$
+
+ private DisassemblyMessages() {
+ // Do not instantiate
+ }
+
+ public static String Disassembly_action_ShowAddresses_label;
+ public static String Disassembly_action_ShowFunctionOffsets_label;
+ public static String Disassembly_action_ShowDisassembly_label;
+ public static String Disassembly_action_ShowSource_label;
+ public static String Disassembly_action_ShowSymbols_label;
+ public static String Disassembly_action_ShowSimplified_label;
+ public static String Disassembly_action_SourceSteppingMode_error;
+ public static String Disassembly_action_SourceSteppingMode_label;
+ public static String Disassembly_action_AssemblySteppingMode_label;
+ public static String Disassembly_action_RunToHere_label;
+ public static String Disassembly_action_SetPCToHere_label;
+ public static String Disassembly_action_GotoPC_label;
+ public static String Disassembly_action_GotoPC_tooltip;
+ public static String Disassembly_action_GotoAddress_label;
+ public static String Disassembly_action_GotoSymbol_label;
+ public static String Disassembly_action_Copy_label;
+ public static String Disassembly_action_SelectAll_label;
+ public static String Disassembly_action_BreakpointProperties_label;
+ public static String Disassembly_action_RemoveBreakpoint_label;
+ public static String Disassembly_action_AddBreakpoint_label;
+ public static String Disassembly_action_AddHWBreakpoint_label;
+ public static String Disassembly_action_AddTracepoint_label;
+ public static String Disassembly_action_DisableBreakpoint_label;
+ public static String Disassembly_action_EnableBreakpoint_label;
+ public static String Disassembly_action_WatchExpression_label;
+ public static String Disassembly_action_ShowInMemory_label;
+ public static String Disassembly_action_RefreshView_label;
+ public static String Disassembly_action_OpenPreferences_label;
+ public static String Disassembly_GotoAddressDialog_title;
+ public static String Disassembly_GotoAddressDialog_label;
+ public static String Disassembly_GotoAddressDialog_error_invalid_address;
+ public static String Disassembly_GotoAddressDialog_error_not_a_number;
+ public static String Disassembly_GotoSymbolDialog_title;
+ public static String Disassembly_GotoSymbolDialog_label;
+ public static String Disassembly_message_notConnected;
+ public static String Disassembly_log_error_retrieveFrameAddress;
+ public static String Disassembly_log_error_locateFile;
+ public static String Disassembly_log_error_accessLineInfo;
+ public static String Disassembly_log_error_noFileInfo;
+ public static String Disassembly_log_error_fileTooLarge;
+ public static String Disassembly_log_error_readFile;
+ public static String Disassembly_log_error_createVersion;
+ public static String Disassembly_log_error_retrieveDisassembly;
+ public static String Disassembly_log_error_showDisassembly;
+ public static String Disassembly_log_error_invalidSymbol;
+ public static String DisassemblyPreferencePage_startAddress;
+ public static String DisassemblyPreferencePage_endAddress;
+ public static String DisassemblyPreferencePage_addressRadix;
+ public static String DisassemblyPreferencePage_instructionRadix;
+ public static String DisassemblyPreferencePage_showAddressRadix;
+ public static String DisassemblyPreferencePage_showSource;
+ public static String DisassemblyPreferencePage_showSymbols;
+ public static String DisassemblyPreferencePage_simplifiedMnemonics;
+ public static String DisassemblyPreferencePage_error_not_a_number;
+ public static String DisassemblyPreferencePage_error_negative_number;
+ public static String DisassemblyPreferencePage_radix_octal;
+ public static String DisassemblyPreferencePage_radix_decimal;
+ public static String DisassemblyPreferencePage_radix_hexadecimal;
+ public static String DisassemblyPreferencePage_showFunctionOffsets;
+ public static String DisassemblyPreferencePage_showAddress;
+ public static String DisassemblyPreferencePage_useSourceOnlyMode;
+ public static String DisassemblyPreferencePage_useSourceOnlyMode_noteTtitle;
+ public static String DisassemblyPreferencePage_useSourceOnlyMode_noteMessage;
+ public static String DisassemblyPreferencePage_avoidReadBeforePC;
+ public static String DisassemblyIPAnnotation_primary;
+ public static String DisassemblyIPAnnotation_secondary;
+ public static String SourceReadingJob_name;
+ public static String SourceColorerJob_name;
+ public static String EditionFinderJob_name;
+ public static String EditionFinderJob_task_get_timestamp;
+ public static String EditionFinderJob_task_search_history;
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, DisassemblyMessages.class);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties
new file mode 100644
index 00000000000..479808236de
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyMessages.properties
@@ -0,0 +1,89 @@
+##########################################################################
+# Copyright (c) 2007, 2008 Wind River Systems 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
+##########################################################################
+
+Disassembly_action_ShowAddresses_label=Show Addresses
+Disassembly_action_ShowFunctionOffsets_label=Show Function Offsets
+Disassembly_action_ShowDisassembly_label=Show Disassembly of Source
+Disassembly_action_ShowSource_label=Show Source
+Disassembly_action_ShowSymbols_label=Show Symbols
+Disassembly_action_ShowSimplified_label=Show Simplified Instructions
+Disassembly_action_SourceSteppingMode_error=Cannot open editor for file
+Disassembly_action_SourceSteppingMode_label=Source Stepping Mode
+Disassembly_action_AssemblySteppingMode_label=Assembly Stepping Mode
+Disassembly_action_RunToHere_label=Run to Here
+Disassembly_action_SetPCToHere_label=Set PC to Here
+Disassembly_action_GotoPC_label=Go to Program Counter
+Disassembly_action_GotoPC_tooltip=Go to Current Program Counter
+Disassembly_action_GotoAddress_label=Go to Address...
+Disassembly_action_GotoSymbol_label=Go to Symbol...
+Disassembly_action_Copy_label=&Copy
+Disassembly_action_SelectAll_label=Select &All
+Disassembly_action_BreakpointProperties_label=Breakpoint Properties...
+Disassembly_action_RemoveBreakpoint_label=Remove Breakpoint
+Disassembly_action_AddBreakpoint_label=Add Breakpoint
+Disassembly_action_AddHWBreakpoint_label=Add Hardware Breakpoint
+Disassembly_action_AddTracepoint_label=Add Tracepoint...
+Disassembly_action_DisableBreakpoint_label=Disable Breakpoint
+Disassembly_action_EnableBreakpoint_label=Enable Breakpoint
+Disassembly_action_WatchExpression_label=Watch Expression
+Disassembly_action_ShowInMemory_label=Show In Memory View
+Disassembly_action_RefreshView_label=Re&fresh View
+Disassembly_action_OpenPreferences_label=&Preferences...
+
+Disassembly_GotoAddressDialog_title=Go to Address
+Disassembly_GotoAddressDialog_label=Address:
+Disassembly_GotoAddressDialog_error_invalid_address=Invalid address
+Disassembly_GotoAddressDialog_error_not_a_number=Not a valid number format
+
+Disassembly_GotoSymbolDialog_title=Go to Symbol
+Disassembly_GotoSymbolDialog_label=Symbol:
+
+Disassembly_message_notConnected=No debug context
+
+Disassembly_log_error_retrieveFrameAddress=Error retrieving frame address
+Disassembly_log_error_locateFile=Unable to locate file:\
+Disassembly_log_error_accessLineInfo=Error accessing line information for:\
+Disassembly_log_error_noFileInfo=Debug information not found for:\
+Disassembly_log_error_fileTooLarge=Source file is too large to retrieve line information:\
+Disassembly_log_error_readFile=Cannot read source file:\
+Disassembly_log_error_createVersion=Cannot create version
+Disassembly_log_error_retrieveDisassembly=Cannot retrieve disassembly for:\
+Disassembly_log_error_showDisassembly=Error opening Disassembly
+Disassembly_log_error_invalidSymbol=Cannot evaluate symbolic address ''{0}''
+
+DisassemblyPreferencePage_startAddress=Start address
+DisassemblyPreferencePage_endAddress=End address
+DisassemblyPreferencePage_addressRadix=Address display format
+DisassemblyPreferencePage_instructionRadix=Instruction display format
+DisassemblyPreferencePage_showAddressRadix=Force radix prefixes
+DisassemblyPreferencePage_showSource=Show source
+DisassemblyPreferencePage_showSymbols=Show symbols
+DisassemblyPreferencePage_simplifiedMnemonics=Use simplified instruction mnemonics
+DisassemblyPreferencePage_error_not_a_number=Not a valid number format
+DisassemblyPreferencePage_error_negative_number=Address cannot be negative
+DisassemblyPreferencePage_radix_octal=Octal
+DisassemblyPreferencePage_radix_decimal=Decimal
+DisassemblyPreferencePage_radix_hexadecimal=Hexadecimal
+DisassemblyPreferencePage_showFunctionOffsets=Show function offsets
+DisassemblyPreferencePage_showAddress=Show instruction address
+DisassemblyPreferencePage_useSourceOnlyMode=Use Disassembly Viewer when debugging in source stepping mode
+DisassemblyPreferencePage_useSourceOnlyMode_noteTtitle=Note:
+DisassemblyPreferencePage_useSourceOnlyMode_noteMessage=When this option is enabled, the Disassembly Viewer will be used to display source locations in a special "source-only" mode, instead of using the normal Source Editor.
+DisassemblyPreferencePage_avoidReadBeforePC=Do not disassemble code before current program counter
+
+DisassemblyIPAnnotation_primary=Debug Current Instruction Pointer
+DisassemblyIPAnnotation_secondary=Debug Call Stack
+
+SourceReadingJob_name=Reading source file
+SourceColorerJob_name=Coloring source file
+EditionFinderJob_name=Finding best match for source file
+EditionFinderJob_task_get_timestamp=Retrieving module timestamp
+EditionFinderJob_task_search_history=Searching local history
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyPart.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyPart.java
new file mode 100644
index 00000000000..a8076def62c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyPart.java
@@ -0,0 +1,3441 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.io.File;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.debug.core.CDIDebugModel;
+import org.eclipse.cdt.debug.core.model.ICBreakpoint;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyAction;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.ActionGotoAddress;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.ActionGotoProgramCounter;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.ActionGotoSymbol;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.ActionOpenPreferences;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.TextOperationAction;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.Addr2Line;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.AddressRangePosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.BreakpointsAnnotationModel;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.ErrorPosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.LabelPosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourceFileInfo;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourcePosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.preferences.DisassemblyPreferenceConstants;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.DisassemblyIPAnnotation;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.util.HSL;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IInstruction;
+import org.eclipse.cdt.dsf.debug.service.IMixedInstruction;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IDisassembly.IDisassemblyDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.ISourceLookup.ISourceLookupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.DsfSession.SessionEndedListener;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.internal.ui.dnd.TextViewerDragAdapter;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ISuspendResume;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.actions.IRunToLineTarget;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.GroupMarker;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.commands.ActionHandler;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextPresentationListener;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewerExtension;
+import org.eclipse.jface.text.IViewportListener;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.jface.text.source.AnnotationRulerColumn;
+import org.eclipse.jface.text.source.CompositeRuler;
+import org.eclipse.jface.text.source.IAnnotationAccess;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IAnnotationModelExtension;
+import org.eclipse.jface.text.source.IOverviewRuler;
+import org.eclipse.jface.text.source.ISharedTextColors;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.IVerticalRulerColumn;
+import org.eclipse.jface.text.source.IVerticalRulerExtension;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.text.source.OverviewRuler;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.FileTransfer;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IPartListener2;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartReference;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.contexts.IContextActivation;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.ide.IGotoMarker;
+import org.eclipse.ui.part.WorkbenchPart;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.AnnotationPreference;
+import org.eclipse.ui.texteditor.ChainedPreferenceStore;
+import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.eclipse.ui.texteditor.IUpdate;
+import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
+import org.eclipse.ui.texteditor.MarkerAnnotationPreferences;
+import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
+import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
+
+/**
+ * DisassemblyPart
+ */
+@SuppressWarnings("restriction")
+public abstract class DisassemblyPart extends WorkbenchPart implements IDisassemblyPart, IViewportListener, ITextPresentationListener, SessionEndedListener {
+
+ private final static boolean DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/disassembly")); //$NON-NLS-1$//$NON-NLS-2$
+
+ /**
+ * Annotation model attachment key for breakpoint annotations.
+ */
+ private final static String BREAKPOINT_ANNOTATIONS= "breakpoints"; //$NON-NLS-1$
+
+ private final static BigInteger PC_UNKNOWN = BigInteger.valueOf(-1);
+ private final static BigInteger PC_RUNNING = BigInteger.valueOf(-2);
+
+ /** Preference key for highlighting current line. */
+ private final static String CURRENT_LINE = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE;
+ /** Preference key for highlight color of current line. */
+ private final static String CURRENT_LINE_COLOR = AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR;
+
+ /** The width of the vertical ruler. */
+ protected final static int VERTICAL_RULER_WIDTH = 12;
+
+ /** High water mark for cache */
+ private final static int fgHighWaterMark = 500;
+ /** Low water mark for cache */
+ private final static int fgLowWaterMark = 100;
+
+ private static final String COMMAND_ID_GOTO_ADDRESS = "org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoAddress"; //$NON-NLS-1$
+ private static final String COMMAND_ID_GOTO_PC = "org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoPC"; //$NON-NLS-1$
+ private static final String COMMAND_ID_GOTO_SYMBOL = "org.eclipse.cdt.dsf.debug.ui.disassembly.commands.gotoSymbol"; //$NON-NLS-1$
+// private static final String COMMAND_ID_TOGGLE_BREAKPOINT = "org.eclipse.debug.ui.commands.ToggleBreakpoint"; //$NON-NLS-1$
+// private static final String COMMAND_ID_RUN_TO_LINE = "org.eclipse.debug.ui.commands.RunToLine"; //$NON-NLS-1$
+// private static final String COMMAND_ID_TOGGLE_STEPPING_MODE = "org.eclipse.cdt.dsf.debug.ui.debug.ui.menu.showDisassemblyAction"; //$NON-NLS-1$
+
+ private static final String KEY_BINDING_CONTEXT_DISASSEMBLY = "org.eclipse.cdt.dsf.debug.ui.disassembly.context"; //$NON-NLS-1$
+
+ protected DisassemblyViewer fViewer;
+
+ protected AbstractDisassemblyAction fActionGotoPC;
+ protected AbstractDisassemblyAction fActionGotoAddress;
+ private AbstractDisassemblyAction fActionGotoSymbol;
+ private AbstractDisassemblyAction fActionToggleBreakpoint;
+ protected AbstractDisassemblyAction fActionToggleSource;
+ private AbstractDisassemblyAction fActionToggleFunctionColumn;
+ private AbstractDisassemblyAction fActionToggleSymbols;
+ private AbstractDisassemblyAction fActionRefreshView;
+ private Action fActionOpenPreferences;
+ private AbstractDisassemblyAction fActionToggleAddressColumn;
+ private AbstractDisassemblyAction fActionToggleBreakpointEnablement;
+
+ protected DisassemblyDocument fDocument;
+ private IAnnotationAccess fAnnotationAccess;
+ private AnnotationRulerColumn fAnnotationRulerColumn;
+ private MarkerAnnotationPreferences fAnnotationPreferences;
+ private IPreferenceStore fPreferenceStore;
+ private IOverviewRuler fOverviewRuler;
+ private final ListenerList fRulerContextMenuListeners= new ListenerList(ListenerList.IDENTITY);
+ private SourceViewerDecorationSupport fDecorationSupport;
+ private Font fFont;
+ private IVerticalRuler fVerticalRuler;
+ private IFindReplaceTarget fFindReplaceTarget;
+ private IPropertyChangeListener fPropertyChangeListener= new PropertyChangeListener();
+ private Color fInstructionColor;
+ private Color fErrorColor;
+ private Color fSourceColor;
+ private Color fLabelColor;
+ private Control fRedrawControl;
+ private RGB fPCAnnotationRGB;
+ private Composite fComposite;
+
+ private DropTarget fDropTarget;
+ private DragSource fDragSource;
+ private TextViewerDragAdapter fDragSourceAdapter;
+ private DisassemblyDropAdapter fDropTargetAdapter;
+
+ private FunctionOffsetRulerColumn fOpcodeRulerColumn;
+ private AddressRulerColumn fAddressRulerColumn;
+
+ private BigInteger fStartAddress;
+ private BigInteger fEndAddress;
+ private int fAddressSize= 32;
+
+ private volatile boolean fUpdatePending;
+ private BigInteger fPCAddress;
+ private BigInteger fGotoAddressPending= PC_UNKNOWN;
+ private BigInteger fFocusAddress= PC_UNKNOWN;
+ private int fBufferZone;
+ private IExecutionDMContext fTargetContext;
+ private String fDebugSessionId;
+ private int fTargetFrame;
+ private DisassemblyIPAnnotation fPCAnnotation;
+ private DisassemblyIPAnnotation fSecondaryPCAnnotation;
+ private boolean fPCAnnotationUpdatePending;
+ private ArrayList<BigInteger> fPendingPCUpdates = new ArrayList<BigInteger>(5);
+ private Position fScrollPos;
+ private int fScrollLine;
+ private Position fFocusPos;
+ private BigInteger fFrameAddress= PC_UNKNOWN;
+ protected Map<String, Action> fGlobalActions = new HashMap<String, Action>();
+ private List<Action> fSelectionActions = new ArrayList<Action>();
+ private List<AbstractDisassemblyAction> fStateDependentActions = new ArrayList<AbstractDisassemblyAction>();
+ private boolean fSourceOnlyMode;
+ private boolean fShowSource;
+ private boolean fShowOpcodes;
+ private boolean fShowSymbols;
+ private Map<String, Object> fFile2Storage = new HashMap<String, Object>();
+ private boolean fShowDisassembly;
+ private LinkedList<AddressRangePosition> fPCHistory = new LinkedList<AddressRangePosition>();
+ private int fPCHistorySizeMax = 4;
+ private boolean fGotoFramePending;
+
+ private String fPCAnnotationColorKey;
+
+ private ArrayList<Runnable> fRunnableQueue = new ArrayList<Runnable>();
+
+ protected IPartListener2 fPartListener =
+ new IPartListener2() {
+ public void partActivated(IWorkbenchPartReference partRef) {
+ }
+ public void partBroughtToTop(IWorkbenchPartReference partRef) {
+ }
+ public void partClosed(IWorkbenchPartReference partRef) {
+ }
+ public void partDeactivated(IWorkbenchPartReference partRef) {
+ }
+ public void partOpened(IWorkbenchPartReference partRef) {
+ }
+ public void partHidden(IWorkbenchPartReference partRef) {
+ if (partRef.getPart(false) == DisassemblyPart.this) {
+ setActive(false);
+ }
+ }
+ public void partVisible(IWorkbenchPartReference partRef) {
+ if (partRef.getPart(false) == DisassemblyPart.this) {
+ setActive(true);
+ }
+ }
+ public void partInputChanged(IWorkbenchPartReference partRef) {
+ }
+ };
+
+ private boolean fActive = true;
+ private boolean fDoPendingPosted;
+ private boolean fUpdateBeforeFocus;
+
+ private boolean fRefreshAll;
+ private IMarker fGotoMarkerPending;
+ private boolean fUpdateTitlePending;
+ private boolean fRefreshViewPending;
+ private boolean fUpdateSourcePending;
+
+ private ArrayList<IHandlerActivation> fHandlerActivations;
+ private IContextActivation fContextActivation;
+
+ private DsfServicesTracker fServicesTracker;
+ private IFrameDMContext fTargetFrameContext;
+ protected IFrameDMData fTargetFrameData;
+
+
+ private final class ActionRefreshView extends AbstractDisassemblyAction {
+ public ActionRefreshView() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_RefreshView_label);
+ setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Refresh_enabled));
+ setDisabledImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Refresh_disabled));
+ }
+ @Override
+ public void run() {
+ refreshView(10);
+ }
+ }
+
+ private final class ActionToggleAddressColumn extends AbstractDisassemblyAction {
+ ActionToggleAddressColumn () {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_ShowAddresses_label);
+ }
+ @Override
+ public void run() {
+ IPreferenceStore store = DsfUIPlugin.getDefault().getPreferenceStore();
+ store.setValue(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER, !isAddressRulerVisible());
+ }
+ @Override
+ public void update() {
+ setChecked(isAddressRulerVisible());
+ }
+ }
+
+ private final class ActionToggleFunctionColumn extends AbstractDisassemblyAction {
+ ActionToggleFunctionColumn() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_ShowFunctionOffsets_label);
+ }
+ @Override
+ public void run() {
+ IPreferenceStore store = DsfUIPlugin.getDefault().getPreferenceStore();
+ store.setValue(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS, !isOpcodeRulerVisible());
+ }
+ @Override
+ public void update() {
+ setChecked(isOpcodeRulerVisible());
+ }
+ }
+
+ private final class ActionToggleBreakpoint extends AbstractDisassemblyAction {
+ private IBreakpoint fBreakpoint;
+ private int fLine;
+ public ActionToggleBreakpoint() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_AddBreakpoint_label);
+ setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_ToggleBreakpoint));
+ }
+ @Override
+ public void run() {
+ try {
+ if (fBreakpoint != null) {
+ fBreakpoint.delete();
+ } else {
+ insertBreakpoint(fLine, false);
+ }
+ } catch (CoreException e) {
+ DsfUIPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+ @Override
+ public void update() {
+ super.update();
+ if (isEnabled()) {
+ fLine = fVerticalRuler.getLineOfLastMouseButtonActivity();
+ IBreakpoint[] bps = getBreakpointsAtLine(fLine);
+ if (bps == null) {
+ fBreakpoint = null;
+ setText(DisassemblyMessages.Disassembly_action_AddBreakpoint_label);
+ } else {
+ fBreakpoint = bps[0];
+ setText(DisassemblyMessages.Disassembly_action_RemoveBreakpoint_label);
+ }
+ }
+ }
+ }
+
+ private final class ActionToggleBreakpointEnablement extends AbstractDisassemblyAction {
+ private IBreakpoint fBreakpoint;
+ public ActionToggleBreakpointEnablement() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_EnableBreakpoint_label);
+ }
+ @Override
+ public void run() {
+ try {
+ fBreakpoint.setEnabled(!fBreakpoint.isEnabled());
+ } catch (CoreException e) {
+ internalError(e);
+ }
+ }
+ @Override
+ public void update() {
+ super.update();
+ if (isEnabled()) {
+ int line = fVerticalRuler.getLineOfLastMouseButtonActivity();
+ IBreakpoint[] bps = getBreakpointsAtLine(line);
+ if (bps == null || bps.length == 0) {
+ setEnabled(false);
+ } else {
+ fBreakpoint = bps[0];
+ try {
+ if (fBreakpoint.isEnabled()) {
+ setText(DisassemblyMessages.Disassembly_action_DisableBreakpoint_label);
+ } else {
+ setText(DisassemblyMessages.Disassembly_action_EnableBreakpoint_label);
+ }
+ } catch (CoreException e) {
+ setEnabled(false);
+ }
+ }
+ }
+ }
+ }
+
+ private final class ActionToggleSource extends AbstractDisassemblyAction {
+ public ActionToggleSource() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_ShowSource_label);
+ }
+ @Override
+ public void run() {
+ IPreferenceStore store = DsfUIPlugin.getDefault().getPreferenceStore();
+ boolean showSourceEnabled = store.getBoolean(DisassemblyPreferenceConstants.SHOW_SOURCE);
+ if (showSourceEnabled == fShowSource) {
+ store.setValue(DisassemblyPreferenceConstants.SHOW_SOURCE, !fShowSource);
+ } else {
+ sourceModeChanged(!fShowSource);
+ }
+ }
+ @Override
+ public void update() {
+ super.update();
+ if (isEnabled()) {
+ setEnabled(fShowDisassembly);
+ }
+ setChecked(fShowSource);
+ }
+ }
+
+ private final class ActionToggleSymbols extends AbstractDisassemblyAction {
+ public ActionToggleSymbols() {
+ super(DisassemblyPart.this);
+ setText(DisassemblyMessages.Disassembly_action_ShowSymbols_label);
+ }
+ @Override
+ public void run() {
+ IPreferenceStore store = DsfUIPlugin.getDefault().getPreferenceStore();
+ store.setValue(DisassemblyPreferenceConstants.SHOW_SYMBOLS, !fShowSymbols);
+ }
+ @Override
+ public void update() {
+ super.update();
+ setChecked(fShowSymbols);
+ }
+ }
+
+ /**
+ * Internal property change listener for handling changes in the
+ * preferences.
+ */
+ class PropertyChangeListener implements IPropertyChangeListener {
+ /*
+ * @see IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ handlePreferenceStoreChanged(event);
+ }
+ }
+
+
+ /**
+ * The constructor.
+ */
+ public DisassemblyPart() {
+ fAnnotationPreferences = new MarkerAnnotationPreferences();
+ setPreferenceStore(new ChainedPreferenceStore(new IPreferenceStore[] {
+ DsfUIPlugin.getDefault().getPreferenceStore(), EditorsUI.getPreferenceStore() }));
+ fPCAddress = fFrameAddress = PC_UNKNOWN;
+ fTargetFrame = -1;
+ fBufferZone = 32;
+ fPCAnnotation = new DisassemblyIPAnnotation(true, 0);
+ fSecondaryPCAnnotation = new DisassemblyIPAnnotation(false, 0);
+ IPreferenceStore prefs = getPreferenceStore();
+ fStartAddress = new BigInteger(prefs.getString(DisassemblyPreferenceConstants.START_ADDRESS));
+ String endAddressString = prefs.getString(DisassemblyPreferenceConstants.END_ADDRESS);
+ if(endAddressString.startsWith("0x")) //$NON-NLS-1$
+ fEndAddress = new BigInteger(endAddressString.substring(2), 16);
+ else
+ fEndAddress = new BigInteger(endAddressString, 16);
+ // TLETODO [disassembly[ source only mode
+ fSourceOnlyMode = false; //prefs.getBoolean(DisassemblyPreferenceConstants.USE_SOURCE_ONLY_MODE);
+ fShowSource = fSourceOnlyMode || prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_SOURCE);
+ fShowDisassembly = !fSourceOnlyMode || !fShowSource;
+ fShowOpcodes = prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS);
+ fShowSymbols = prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_SYMBOLS);
+ fUpdateBeforeFocus = !prefs.getBoolean(DisassemblyPreferenceConstants.AVOID_READ_BEFORE_PC);
+ fPCHistorySizeMax = prefs.getInt(DisassemblyPreferenceConstants.PC_HISTORY_SIZE);
+ }
+
+ public void logWarning(String message, Throwable error) {
+ DsfUIPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, message, error));
+ }
+
+ /*
+ * @see IAdaptable#getAdapter(java.lang.Class)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class required) {
+ if (IVerticalRulerInfo.class.equals(required)) {
+ if (fVerticalRuler != null) {
+ return fVerticalRuler;
+ }
+ } else if (IDisassemblyPart.class.equals(required)) {
+ return this;
+ } else if (IFindReplaceTarget.class.equals(required)) {
+ if (fFindReplaceTarget == null) {
+ fFindReplaceTarget = (fViewer == null ? null : fViewer.getFindReplaceTarget());
+ }
+ return fFindReplaceTarget;
+ } else if (ITextOperationTarget.class.equals(required)) {
+ return (fViewer == null ? null : fViewer.getTextOperationTarget());
+ } else if (Control.class.equals(required)) {
+ return fViewer != null ? fViewer.getTextWidget() : null;
+ } else if (IGotoMarker.class.equals(required)) {
+ return new IGotoMarker() {
+ public void gotoMarker(IMarker marker) {
+ DisassemblyPart.this.gotoMarker(marker);
+ }};
+ } else if (IToggleBreakpointsTarget.class.equals(required)) {
+ return new IToggleBreakpointsTarget() {
+ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ ITextSelection textSelection = (ITextSelection)selection;
+ int line = textSelection.getStartLine();
+ IBreakpoint[] bp = getBreakpointsAtLine(line);
+ if (bp == null || bp.length == 0) {
+ insertBreakpoint(line, false);
+ } else {
+ for (int i = 0; i < bp.length; i++) {
+ bp[i].delete();
+ }
+ }
+ }
+ public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
+ return fDebugSessionId != null;
+ }
+ public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ }
+ public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
+ return false;
+ }
+ public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ }
+ public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
+ return false;
+ }};
+ } else if (IRunToLineTarget.class.equals(required)) {
+ return new IRunToLineTarget() {
+ public void runToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) throws CoreException {
+// ITextSelection textSelection = (ITextSelection)selection;
+// int line = textSelection.getStartLine();
+// BigInteger address = getAddressOfLine(line);
+ // TLETODO [disassembly] run to line
+// getRunControl().runUntil(...);
+ }
+ public boolean canRunToLine(IWorkbenchPart part, ISelection selection, ISuspendResume target) {
+ return fTargetContext != null && isSuspended(fTargetContext) ;
+ }};
+ }
+ return super.getAdapter(required);
+ }
+
+ private void setPreferenceStore(IPreferenceStore store) {
+ if (fPreferenceStore != null) {
+ fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
+ }
+
+ fPreferenceStore = store;
+
+ if (fPreferenceStore != null) {
+ fPreferenceStore.addPropertyChangeListener(fPropertyChangeListener);
+ }
+ }
+
+ /**
+ * Handles a property change event describing a change of the editor's
+ * preference store and updates the preference related editor properties.
+ * <p>
+ * Subclasses may extend.
+ * </p>
+ *
+ * @param event
+ * the property change event
+ */
+ protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
+
+ if (fViewer == null)
+ return;
+
+ String property = event.getProperty();
+ IPreferenceStore store = getPreferenceStore();
+
+ if (getFontPropertyPreferenceKey().equals(property)) {
+ initializeViewerFont(fViewer);
+ } else if (property.equals(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER)) {
+ fActionToggleAddressColumn.update();
+ if (isAddressRulerVisible()) {
+ showAddressRuler();
+ } else {
+ hideAddressRuler();
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.ADDRESS_RADIX)) {
+ if (fAddressRulerColumn != null) {
+ hideAddressRuler();
+ showAddressRuler();
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.SHOW_ADDRESS_RADIX)) {
+ if (fAddressRulerColumn != null) {
+ hideAddressRuler();
+ showAddressRuler();
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.SHOW_SOURCE)) {
+ sourceModeChanged(store.getBoolean(property));
+ } else if (property.equals(DisassemblyPreferenceConstants.INSTRUCTION_RADIX)) {
+ Runnable doit = new Runnable() {
+ public void run() {
+ fDocument.invalidateAddressRange(fStartAddress, fEndAddress, true);
+ if (!fShowDisassembly) {
+ fDocument.invalidateDisassemblyWithSource(true);
+ }
+ fDocument.setMaxOpcodeLength(0);
+ fGotoFramePending = true;
+ }};
+ doScrollLocked(doit);
+ } else if (property.equals(DisassemblyPreferenceConstants.SHOW_SYMBOLS)) {
+ boolean showSymbols = store.getBoolean(property);
+ if (fShowSymbols == showSymbols) {
+ return;
+ }
+ fShowSymbols = showSymbols;
+ Runnable doit = new Runnable() {
+ public void run() {
+ fDocument.invalidateAddressRange(fStartAddress, fEndAddress, true);
+ if (!fShowDisassembly) {
+ fDocument.invalidateDisassemblyWithSource(true);
+ }
+ fGotoFramePending = true;
+ }};
+ doScrollLocked(doit);
+ } else if (property.equals(DisassemblyPreferenceConstants.USE_SOURCE_ONLY_MODE)) {
+ fSourceOnlyMode = store.getBoolean(property);
+ if (fDebugSessionId != null) {
+ disassemblyModeChanged(isDissemblyMixedModeOn());
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS)) {
+ fShowOpcodes = store.getBoolean(property);
+ fActionToggleFunctionColumn.update();
+ if (isOpcodeRulerVisible()) {
+ showOpcodeRuler();
+ } else {
+ hideOpcodeRuler();
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.AVOID_READ_BEFORE_PC)) {
+ fUpdateBeforeFocus = !store.getBoolean(property);
+ updateVisibleArea();
+ } else if (property.equals(fPCAnnotationColorKey)) {
+ fPCAnnotationRGB = PreferenceConverter.getColor(store, fPCAnnotationColorKey);
+ // redraw
+ for (Iterator<AddressRangePosition> it=fPCHistory.iterator(); it.hasNext();) {
+ AddressRangePosition pos = it.next();
+ fViewer.invalidateTextPresentation(pos.offset, pos.length);
+ }
+ } else if (property.equals(DisassemblyPreferenceConstants.PC_HISTORY_SIZE)) {
+ fPCHistorySizeMax = store.getInt(property);
+ }
+ }
+
+ /**
+ * This is a callback that will allow us to create the viewer and initialize
+ * it.
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ fComposite = parent;
+ FillLayout layout = new FillLayout();
+ layout.marginHeight = 2;
+ parent.setLayout(layout);
+ fVerticalRuler = createVerticalRuler();
+ int styles = SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION;
+ fViewer = new DisassemblyViewer(parent, fVerticalRuler, getOverviewRuler(), true, styles);
+ SourceViewerConfiguration sourceViewerConfig = new DisassemblyViewerConfiguration(this);
+ fViewer.addTextPresentationListener(this);
+ fViewer.configure(sourceViewerConfig);
+ fDecorationSupport = new SourceViewerDecorationSupport(fViewer, getOverviewRuler(), getAnnotationAccess(),
+ getSharedColors());
+ configureSourceViewerDecorationSupport(fDecorationSupport);
+ fDecorationSupport.install(getPreferenceStore());
+ if (fPCAnnotationColorKey != null) {
+ fPCAnnotationRGB = PreferenceConverter.getColor(getPreferenceStore(), fPCAnnotationColorKey);
+ } else {
+ fPCAnnotationRGB = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION).getRGB();
+ }
+
+ initializeViewerFont(fViewer);
+ createActions();
+ hookRulerContextMenu();
+ hookContextMenu();
+ contributeToActionBars();
+
+ fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateSelectionDependentActions();
+ }
+ });
+
+ fDocument = createDocument();
+ fViewer.setDocument(fDocument, new AnnotationModel());
+ JFaceResources.getFontRegistry().addListener(fPropertyChangeListener);
+
+ fErrorColor = getSharedColors().getColor(new RGB(96, 0, 0));
+ fInstructionColor = getSharedColors().getColor(new RGB(0, 0, 96));
+ fSourceColor = getSharedColors().getColor(new RGB(64, 0, 80));
+ fLabelColor = getSharedColors().getColor(new RGB(0, 0, 96));
+
+ if (isAddressRulerVisible()) {
+ showAddressRuler();
+ }
+ if (isOpcodeRulerVisible()) {
+ showOpcodeRuler();
+ }
+ initDragAndDrop();
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(fViewer.getControl(), IDisassemblyHelpContextIds.DISASSEMBLY_VIEW);
+ updateTitle();
+ updateStateDependentActions();
+
+ if (fDebugSessionId != null) {
+ debugContextChanged();
+ } else {
+ updateDebugContext();
+ }
+ DsfSession.addSessionEndedListener(this);
+ }
+
+ /*
+ * @see org.eclipse.ui.part.WorkbenchPart#setSite(org.eclipse.ui.IWorkbenchPartSite)
+ */
+ @Override
+ protected void setSite(IWorkbenchPartSite site) {
+ super.setSite(site);
+ site.getPage().addPartListener(fPartListener);
+ }
+
+ private DisassemblyDocument createDocument() {
+ DisassemblyDocument doc = new DisassemblyDocument();
+ return doc;
+ }
+
+ /*
+ * @see org.eclipse.ui.IWorkbenchPart#dispose()
+ */
+ @Override
+ public void dispose() {
+ IWorkbenchPartSite site = getSite();
+ site.setSelectionProvider(null);
+ site.getPage().removePartListener(fPartListener);
+ if (fHandlerActivations != null) {
+ IHandlerService handlerService = (IHandlerService)site.getService(IHandlerService.class);
+ handlerService.deactivateHandlers(fHandlerActivations);
+ fHandlerActivations = null;
+ }
+ if (fContextActivation != null) {
+ IContextService ctxService = (IContextService)site.getService(IContextService.class);
+ ctxService.deactivateContext(fContextActivation);
+ }
+ fViewer = null;
+ setDebugContext(null);
+ DsfSession.removeSessionEndedListener(this);
+
+ fAnnotationAccess = null;
+ fAnnotationPreferences = null;
+ fAnnotationRulerColumn = null;
+ fComposite = null;
+ if (fDecorationSupport != null) {
+ fDecorationSupport.uninstall();
+ fDecorationSupport = null;
+ }
+ if (fFont != null) {
+ fFont.dispose();
+ fFont = null;
+ }
+ if (fDropTarget != null) {
+ fDropTarget.dispose();
+ fDropTarget = null;
+ fDragSource.dispose();
+ fDragSource = null;
+ }
+ if (fPropertyChangeListener != null) {
+ if (fPreferenceStore != null) {
+ fPreferenceStore.removePropertyChangeListener(fPropertyChangeListener);
+ fPreferenceStore = null;
+ }
+ fPropertyChangeListener = null;
+ }
+
+ fDocument.dispose();
+ fDocument = null;
+ super.dispose();
+ }
+
+ private void initDragAndDrop() {
+ if (fDropTarget == null) {
+ Transfer[] dropTypes = new Transfer[] { FileTransfer.getInstance(), TextTransfer.getInstance() };
+ Transfer[] dragTypes = new Transfer[] { TextTransfer.getInstance() };
+ Control dropControl = getSourceViewer().getTextWidget();
+ Control dragControl = dropControl;
+ int dropOps = DND.DROP_COPY | DND.DROP_DEFAULT;
+ int dragOps = DND.DROP_COPY | DND.DROP_DEFAULT;
+
+ fDropTarget = new DropTarget(dropControl, dropOps);
+ fDropTarget.setTransfer(dropTypes);
+ fDropTargetAdapter = new DisassemblyDropAdapter(this);
+ fDropTarget.addDropListener(fDropTargetAdapter);
+
+ fDragSource = new DragSource(dragControl, dragOps);
+ fDragSource.setTransfer(dragTypes);
+ fDragSourceAdapter = new TextViewerDragAdapter(getSourceViewer());
+ fDragSource.addDragListener(fDragSourceAdapter);
+ }
+ }
+
+ private ISourceViewer getSourceViewer() {
+ return fViewer;
+ }
+
+ protected void configureSourceViewerDecorationSupport(SourceViewerDecorationSupport support) {
+ Iterator<?> e = fAnnotationPreferences.getAnnotationPreferences().iterator();
+ while (e.hasNext()) {
+ AnnotationPreference pref = (AnnotationPreference)e.next();
+ support.setAnnotationPreference(pref);
+ if (pref.getAnnotationType().equals(fPCAnnotation.getType())) {
+ fPCAnnotationColorKey = pref.getColorPreferenceKey();
+ }
+ }
+ support.setCursorLinePainterPreferenceKeys(CURRENT_LINE, CURRENT_LINE_COLOR);
+ support.setSymbolicFontName(getFontPropertyPreferenceKey());
+ }
+
+ /**
+ * Returns the symbolic font name for this view as defined in XML.
+ *
+ * @return a String with the symbolic font name or <code>null</code> if
+ * none is defined
+ */
+ private String getSymbolicFontName() {
+ if (getConfigurationElement() != null)
+ return getConfigurationElement().getAttribute("symbolicFontName"); //$NON-NLS-1$
+ else
+ return null;
+ }
+
+ protected final String getFontPropertyPreferenceKey() {
+ String symbolicFontName = getSymbolicFontName();
+
+ if (symbolicFontName != null)
+ return symbolicFontName;
+ else
+ return JFaceResources.TEXT_FONT;
+ }
+
+ /**
+ * Initializes the given viewer's font.
+ *
+ * @param viewer
+ * the viewer
+ */
+ private void initializeViewerFont(ISourceViewer viewer) {
+
+ boolean isSharedFont = true;
+ Font font = null;
+ String symbolicFontName = getSymbolicFontName();
+
+ if (symbolicFontName != null)
+ font = JFaceResources.getFont(symbolicFontName);
+ else if (fPreferenceStore != null) {
+ // Backward compatibility
+ if (fPreferenceStore.contains(JFaceResources.TEXT_FONT)
+ && !fPreferenceStore.isDefault(JFaceResources.TEXT_FONT)) {
+ FontData data = PreferenceConverter.getFontData(fPreferenceStore, JFaceResources.TEXT_FONT);
+
+ if (data != null) {
+ isSharedFont = false;
+ font = new Font(viewer.getTextWidget().getDisplay(), data);
+ }
+ }
+ }
+ if (font == null)
+ font = JFaceResources.getTextFont();
+
+ setFont(viewer, font);
+
+ if (fFont != null) {
+ fFont.dispose();
+ fFont = null;
+ }
+
+ if (!isSharedFont)
+ fFont = font;
+ }
+
+ /**
+ * Sets the font for the given viewer sustaining selection and scroll
+ * position.
+ *
+ * @param sourceViewer
+ * the source viewer
+ * @param font
+ * the font
+ */
+ private void setFont(ISourceViewer sourceViewer, Font font) {
+ if (sourceViewer.getDocument() != null) {
+
+ Point selection = sourceViewer.getSelectedRange();
+ int topIndex = sourceViewer.getTopIndex();
+
+ StyledText styledText = sourceViewer.getTextWidget();
+ Control parent = styledText;
+ if (sourceViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension extension = (ITextViewerExtension) sourceViewer;
+ parent = extension.getControl();
+ }
+
+ parent.setRedraw(false);
+
+ styledText.setFont(font);
+
+ if (fVerticalRuler instanceof IVerticalRulerExtension) {
+ IVerticalRulerExtension e = (IVerticalRulerExtension) fVerticalRuler;
+ e.setFont(font);
+ }
+
+ sourceViewer.setSelectedRange(selection.x, selection.y);
+ sourceViewer.setTopIndex(topIndex);
+
+ if (parent instanceof Composite) {
+ Composite composite = (Composite) parent;
+ composite.layout(true);
+ }
+
+ parent.setRedraw(true);
+
+ } else {
+
+ StyledText styledText = sourceViewer.getTextWidget();
+ styledText.setFont(font);
+
+ if (fVerticalRuler instanceof IVerticalRulerExtension) {
+ IVerticalRulerExtension e = (IVerticalRulerExtension) fVerticalRuler;
+ e.setFont(font);
+ }
+ }
+ }
+
+ protected IVerticalRuler createVerticalRuler() {
+ CompositeRuler ruler = createCompositeRuler();
+ IPreferenceStore store = getPreferenceStore();
+ if (ruler != null && store != null) {
+ for (Iterator<?> iter = ruler.getDecoratorIterator(); iter.hasNext();) {
+ IVerticalRulerColumn column = (IVerticalRulerColumn) iter.next();
+ if (column instanceof AnnotationRulerColumn) {
+ fAnnotationRulerColumn = (AnnotationRulerColumn) column;
+ for (Iterator<?> iter2 = fAnnotationPreferences.getAnnotationPreferences().iterator(); iter2.hasNext();) {
+ AnnotationPreference preference = (AnnotationPreference) iter2.next();
+ String key = preference.getVerticalRulerPreferenceKey();
+ boolean showAnnotation = true;
+ if (key != null && store.contains(key))
+ showAnnotation = store.getBoolean(key);
+ if (showAnnotation)
+ fAnnotationRulerColumn.addAnnotationType(preference.getAnnotationType());
+ }
+ fAnnotationRulerColumn.addAnnotationType(Annotation.TYPE_UNKNOWN);
+ break;
+ }
+ }
+ }
+ return ruler;
+ }
+
+ /**
+ * Returns the vertical ruler.
+ *
+ * @return the vertical ruler
+ */
+ protected IVerticalRuler getVerticalRuler() {
+ return fVerticalRuler;
+ }
+
+ /**
+ * Returns the overview ruler.
+ *
+ * @return the overview ruler
+ */
+ protected IOverviewRuler getOverviewRuler() {
+ if (fOverviewRuler == null)
+ fOverviewRuler = createOverviewRuler(getSharedColors());
+ return fOverviewRuler;
+ }
+
+ protected ISharedTextColors getSharedColors() {
+ return EditorsUI.getSharedTextColors();
+ }
+
+ protected IOverviewRuler createOverviewRuler(ISharedTextColors sharedColors) {
+ IOverviewRuler ruler = new OverviewRuler(getAnnotationAccess(), VERTICAL_RULER_WIDTH, sharedColors);
+ Iterator<?> e = fAnnotationPreferences.getAnnotationPreferences().iterator();
+ while (e.hasNext()) {
+ AnnotationPreference preference = (AnnotationPreference) e.next();
+ if (preference.contributesToHeader())
+ ruler.addHeaderAnnotationType(preference.getAnnotationType());
+ }
+ return ruler;
+ }
+
+ /**
+ * Creates a new address ruler column that is appropriately initialized.
+ *
+ * @return the created line number column
+ */
+ protected IVerticalRulerColumn createAddressRulerColumn() {
+ fAddressRulerColumn= new AddressRulerColumn();
+ initializeRulerColumn(fAddressRulerColumn, DisassemblyPreferenceConstants.ADDRESS_COLOR);
+ IPreferenceStore prefs = getPreferenceStore();
+ fAddressRulerColumn.setRadix(prefs.getInt(DisassemblyPreferenceConstants.ADDRESS_RADIX));
+ fAddressRulerColumn.setShowRadixPrefix(prefs.getBoolean(DisassemblyPreferenceConstants.SHOW_ADDRESS_RADIX));
+ return fAddressRulerColumn;
+ }
+
+ /**
+ * Creates a new ruler column that is appropriately initialized.
+ *
+ * @return the created line number column
+ */
+ protected IVerticalRulerColumn createOpcodeRulerColumn() {
+ fOpcodeRulerColumn= new FunctionOffsetRulerColumn();
+ initializeRulerColumn(fOpcodeRulerColumn, DisassemblyPreferenceConstants.OPCODE_COLOR);
+ return fOpcodeRulerColumn;
+ }
+
+ /**
+ * Initializes the given address ruler column from the preference store.
+ *
+ * @param rulerColumn the ruler column to be initialized
+ */
+ protected void initializeRulerColumn(DisassemblyRulerColumn rulerColumn, String colorPrefKey) {
+ ISharedTextColors sharedColors= getSharedColors();
+ IPreferenceStore store= getPreferenceStore();
+ if (store != null) {
+
+ RGB rgb= null;
+ // foreground color
+ if (store.contains(colorPrefKey)) {
+ if (store.isDefault(colorPrefKey))
+ rgb= PreferenceConverter.getDefaultColor(store, colorPrefKey);
+ else
+ rgb= PreferenceConverter.getColor(store, colorPrefKey);
+ }
+ if (rgb == null)
+ rgb= new RGB(0, 0, 0);
+ rulerColumn.setForeground(sharedColors.getColor(rgb));
+
+ rgb= null;
+
+ rulerColumn.redraw();
+ }
+ }
+
+
+ /**
+ * @return the preference store
+ */
+ private IPreferenceStore getPreferenceStore() {
+ return fPreferenceStore;
+ }
+
+ /**
+ * Creates a composite ruler to be used as the vertical ruler by this
+ * editor. Subclasses may re-implement this method.
+ *
+ * @return the vertical ruler
+ */
+ protected CompositeRuler createCompositeRuler() {
+ CompositeRuler ruler = new CompositeRuler();
+ ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH, getAnnotationAccess()));
+ return ruler;
+ }
+
+ private boolean isAddressRulerVisible() {
+ return getPreferenceStore().getBoolean(DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER);
+ }
+
+ /**
+ * Shows the address ruler column.
+ */
+ private void showAddressRuler() {
+ if (fAddressRulerColumn == null) {
+ IVerticalRuler v= getVerticalRuler();
+ if (v instanceof CompositeRuler) {
+ CompositeRuler c= (CompositeRuler) v;
+ c.addDecorator(1, createAddressRulerColumn());
+ }
+ }
+ }
+
+ /**
+ * Hides the address ruler column.
+ */
+ private void hideAddressRuler() {
+ if (fAddressRulerColumn != null) {
+ IVerticalRuler v= getVerticalRuler();
+ if (v instanceof CompositeRuler) {
+ CompositeRuler c= (CompositeRuler) v;
+ c.removeDecorator(fAddressRulerColumn);
+ }
+ fAddressRulerColumn = null;
+ }
+ }
+
+ private boolean isOpcodeRulerVisible() {
+ return fShowOpcodes;
+ }
+
+ /**
+ * Shows the opcode ruler column.
+ */
+ private void showOpcodeRuler() {
+ if (fOpcodeRulerColumn == null) {
+ IVerticalRuler v= getVerticalRuler();
+ if (v instanceof CompositeRuler) {
+ CompositeRuler c= (CompositeRuler) v;
+ c.addDecorator(2, createOpcodeRulerColumn());
+ }
+ }
+ }
+
+ /**
+ * Hides the opcode ruler column.
+ */
+ private void hideOpcodeRuler() {
+ if (fOpcodeRulerColumn != null) {
+ IVerticalRuler v= getVerticalRuler();
+ if (v instanceof CompositeRuler) {
+ CompositeRuler c= (CompositeRuler) v;
+ c.removeDecorator(fOpcodeRulerColumn);
+ }
+ fOpcodeRulerColumn = null;
+ }
+ }
+
+ /**
+ * Returns the annotation access.
+ *
+ * @return the annotation access
+ */
+ protected IAnnotationAccess getAnnotationAccess() {
+ if (fAnnotationAccess == null)
+ fAnnotationAccess = createAnnotationAccess();
+ return fAnnotationAccess;
+ }
+
+ /**
+ * Creates the annotation access for this editor.
+ *
+ * @return the created annotation access
+ */
+ protected IAnnotationAccess createAnnotationAccess() {
+ return new DefaultMarkerAnnotationAccess();
+ }
+
+ private void hookContextMenu() {
+ String id = "#DisassemblyPartContext"; //$NON-NLS-1$
+ MenuManager menuMgr = new MenuManager(id, id);
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ DisassemblyPart.this.fillContextMenu(manager);
+ }
+ });
+ Menu menu = menuMgr.createContextMenu(fViewer.getTextWidget());
+ fViewer.getTextWidget().setMenu(menu);
+ getSite().registerContextMenu(id, menuMgr, fViewer);
+ }
+
+ private void hookRulerContextMenu() {
+ String id = "#DisassemblyPartRulerContext"; //$NON-NLS-1$
+ MenuManager menuMgr = new MenuManager(id, id);
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager manager) {
+ DisassemblyPart.this.fillRulerContextMenu(manager);
+ }
+ });
+ Menu menu = menuMgr.createContextMenu(fVerticalRuler.getControl());
+ fVerticalRuler.getControl().setMenu(menu);
+ getSite().registerContextMenu(id, menuMgr, fViewer);
+ }
+
+ private void contributeToActionBars() {
+ IWorkbenchPartSite site = getSite();
+ site.setSelectionProvider(fViewer);
+ IContextService ctxService = (IContextService)site.getService(IContextService.class);
+ fContextActivation = ctxService.activateContext(KEY_BINDING_CONTEXT_DISASSEMBLY);
+ contributeToActionBars(getActionBars());
+ }
+
+ protected abstract IActionBars getActionBars();
+
+ protected void contributeToActionBars(IActionBars bars) {
+ for (Iterator<String> iter = fGlobalActions.keySet().iterator(); iter.hasNext();) {
+ String key = iter.next();
+ IAction action = fGlobalActions.get(key);
+ bars.setGlobalActionHandler(key, action);
+ }
+ IMenuManager menu = bars.getMenuManager();
+ IMenuManager navigateMenu= menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE);
+ if (navigateMenu != null) {
+ navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoPC);
+ navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoAddress);
+ navigateMenu.appendToGroup(IWorkbenchActionConstants.MB_ADDITIONS, fActionGotoSymbol);
+ }
+ bars.updateActionBars();
+ }
+
+ protected void fillContextMenu(IMenuManager manager) {
+ Point cursorLoc = getSite().getShell().getDisplay().getCursorLocation();
+ fViewer.getTextWidget().toControl(cursorLoc);
+ fActionToggleSource.update();
+ fActionToggleSymbols.update();
+ manager.add(new GroupMarker("group.top")); // ICommonMenuConstants.GROUP_TOP //$NON-NLS-1$
+ manager.add(new Separator("group.breakpoints")); //$NON-NLS-1$
+ manager.add(new Separator(IWorkbenchActionConstants.GO_TO));
+ manager.add(fActionGotoPC);
+ manager.add(fActionGotoAddress);
+ manager.add(fActionGotoSymbol);
+ manager.add(new Separator("group.debug")); //$NON-NLS-1$
+ manager.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
+ manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.COPY));
+ manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));
+ manager.add(new Separator(ITextEditorActionConstants.GROUP_SETTINGS));
+ manager.add(fActionToggleSource);
+ manager.add(fActionToggleSymbols);
+ manager.add(fActionOpenPreferences);
+ manager.add(new Separator());
+ manager.add(fActionRefreshView);
+ // Other plug-ins can contribute their actions here
+ manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ }
+
+ protected void fillRulerContextMenu(IMenuManager manager) {
+ fActionToggleBreakpoint.update();
+ fActionToggleBreakpointEnablement.update();
+ fActionToggleAddressColumn.update();
+ fActionToggleFunctionColumn.update();
+
+ manager.add(new GroupMarker("group.top")); // ICommonMenuConstants.GROUP_TOP //$NON-NLS-1$
+ manager.add(new Separator("group.breakpoints")); //$NON-NLS-1$
+ manager.add(fActionToggleBreakpoint);
+ manager.add(fActionToggleBreakpointEnablement);
+ manager.add(new GroupMarker("debug")); //$NON-NLS-1$
+ manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ manager.add(new GroupMarker(ITextEditorActionConstants.GROUP_RESTORE));
+ manager.add(new Separator("add")); //$NON-NLS-1$
+ manager.add(new Separator(ITextEditorActionConstants.GROUP_RULERS));
+ manager.add(fActionToggleAddressColumn);
+ manager.add(fActionToggleFunctionColumn);
+ manager.add(new Separator(ITextEditorActionConstants.GROUP_REST));
+
+ for (Object listener : fRulerContextMenuListeners.getListeners())
+ ((IMenuListener) listener).menuAboutToShow(manager);
+
+ manager.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
+ manager.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, fGlobalActions.get(ITextEditorActionConstants.COPY));
+ }
+
+ protected void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(fActionGotoPC);
+ manager.add(fActionGotoAddress);
+ }
+
+ protected void updateSelectionDependentActions() {
+ Iterator<Action> iterator= fSelectionActions.iterator();
+ while (iterator.hasNext()) {
+ IUpdate action = (IUpdate)iterator.next();
+ action.update();
+ }
+ }
+
+ protected void updateStateDependentActions() {
+ Iterator<AbstractDisassemblyAction> iterator= fStateDependentActions.iterator();
+ while (iterator.hasNext()) {
+ IUpdate action = iterator.next();
+ action.update();
+ }
+ }
+
+ protected void createActions() {
+ Action action;
+ action= new TextOperationAction(fViewer, ITextOperationTarget.COPY);
+ action.setText(DisassemblyMessages.Disassembly_action_Copy_label);
+ action.setImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Copy_enabled));
+ action.setDisabledImageDescriptor(DisassemblyImageRegistry.getImageDescriptor(DisassemblyImageRegistry.ICON_Copy_disabled));
+ action.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
+ fGlobalActions.put(ITextEditorActionConstants.COPY, action);
+ fSelectionActions.add(action);
+
+ action= new TextOperationAction(fViewer, ITextOperationTarget.SELECT_ALL);
+ action.setText(DisassemblyMessages.Disassembly_action_SelectAll_label);
+ action.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
+ fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);
+
+ action= new TextOperationAction(fViewer, ITextOperationTarget.PRINT);
+ action.setActionDefinitionId(IWorkbenchActionDefinitionIds.PRINT);
+ fGlobalActions.put(ITextEditorActionConstants.PRINT, action);
+
+ fActionGotoPC = new ActionGotoProgramCounter(this);
+ fActionGotoPC.setActionDefinitionId(COMMAND_ID_GOTO_PC);
+ fStateDependentActions.add(fActionGotoPC);
+ registerWithHandlerService(fActionGotoPC);
+
+ fActionGotoAddress = new ActionGotoAddress(this);
+ fActionGotoAddress.setActionDefinitionId(COMMAND_ID_GOTO_ADDRESS);
+ fStateDependentActions.add(fActionGotoAddress);
+ registerWithHandlerService(fActionGotoAddress);
+
+ fActionGotoSymbol = new ActionGotoSymbol(this);
+ fActionGotoSymbol.setActionDefinitionId(COMMAND_ID_GOTO_SYMBOL);
+ fStateDependentActions.add(fActionGotoSymbol);
+ registerWithHandlerService(fActionGotoSymbol);
+
+ fActionToggleSource = new ActionToggleSource();
+ fStateDependentActions.add(fActionToggleSource);
+ fActionToggleBreakpoint = new ActionToggleBreakpoint();
+// fActionToggleBreakpoint.setActionDefinitionId(COMMAND_ID_TOGGLE_BREAKPOINT);
+// registerWithHandlerService(fActionToggleBreakpoint);
+ fVerticalRuler.getControl().addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ fActionToggleBreakpoint.update();
+ if (fActionToggleBreakpoint.isEnabled()) {
+ fActionToggleBreakpoint.run();
+ }
+ }
+ });
+ fActionToggleBreakpointEnablement = new ActionToggleBreakpointEnablement();
+ fActionToggleAddressColumn = new ActionToggleAddressColumn();
+ fActionToggleFunctionColumn = new ActionToggleFunctionColumn();
+ fActionToggleSymbols = new ActionToggleSymbols();
+// fActionSourceSteppingMode.setActionDefinitionId(COMMAND_ID_TOGGLE_STEPPING_MODE);
+// registerWithHandlerService(fActionSourceSteppingMode);
+ fActionRefreshView = new ActionRefreshView();
+ fStateDependentActions.add(fActionRefreshView);
+ fGlobalActions.put(ActionFactory.REFRESH.getId(), fActionRefreshView);
+ fActionOpenPreferences = new ActionOpenPreferences(getSite().getShell());
+ }
+
+ /**
+ * Register given action with the handler service for key bindings.
+ *
+ * @param action
+ */
+ private void registerWithHandlerService(IAction action) {
+ if (fHandlerActivations == null) {
+ fHandlerActivations = new ArrayList<IHandlerActivation>(5);
+ }
+ IHandlerService handlerService = (IHandlerService)getSite().getService(IHandlerService.class);
+ fHandlerActivations.add(handlerService.activateHandler(action.getActionDefinitionId(), new ActionHandler(action)));
+ }
+
+ private void gotoFrame(IFrameDMContext frame) {
+ if (fActive) {
+ gotoFrame(frame.getLevel(), PC_UNKNOWN);
+ }
+ }
+
+ private void gotoFrame(int frame) {
+ if (fActive) {
+ gotoFrame(frame, PC_UNKNOWN);
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoProgramCounter()
+ */
+ public final void gotoProgramCounter() {
+ if (fPCAddress != PC_RUNNING) {
+ updatePC(fPCAddress);
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoAddress(java.math.BigInteger)
+ */
+ public final void gotoAddress(BigInteger address) {
+ fFocusAddress = address;
+ if (fDebugSessionId == null) {
+ return;
+ }
+ if (DEBUG) System.out.println("gotoAddress " + getAddressText(address)); //$NON-NLS-1$
+ if (fGotoAddressPending == PC_UNKNOWN) {
+ fGotoAddressPending = address;
+ }
+ if (fUpdatePending) {
+ return;
+ }
+ AddressRangePosition pos = getPositionOfAddress(address);
+ if (pos != null) {
+ if (pos.fValid) {
+ AddressRangePosition previousPos = /* fUpdateBeforeFocus ? getPositionOfAddress(pos.fAddressOffset-1): */ null;
+ if (previousPos == null || previousPos.fValid) {
+ if (fGotoAddressPending.equals(address)) {
+ fGotoAddressPending = PC_UNKNOWN;
+ }
+ gotoPosition(pos, false);
+ } else {
+ int lines = fBufferZone+3;
+ BigInteger endAddress = pos.fAddressOffset;
+ BigInteger startAddress = previousPos.fAddressOffset.max(
+ endAddress.subtract(BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions())));
+ retrieveDisassembly(startAddress, endAddress, lines);
+ }
+ } else {
+ int lines = fBufferZone+3;
+ BigInteger endAddress = pos.fAddressOffset.add(pos.fAddressLength).min(
+ address.add(BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions())));
+ retrieveDisassembly(address, endAddress, lines);
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#gotoSymbol(java.lang.String)
+ */
+ public final void gotoSymbol(final String symbol) {
+ if (!fActive || !isSuspended() || fTargetFrameContext == null) {
+ return;
+ }
+ final IExpressions expressions= getService(IExpressions.class);
+ if (expressions == null) {
+ return;
+ }
+ IExpressionDMContext exprDmc= expressions.createExpression(fTargetContext, '&'+symbol);
+ final FormattedValueDMContext valueDmc= expressions.getFormattedValueContext(exprDmc, IFormattedValues.HEX_FORMAT);
+ final DsfExecutor executor= getSession().getExecutor();
+ executor.submit(new Runnable() {
+ public void run() {
+ expressions.getFormattedExpressionValue(valueDmc, new DataRequestMonitor<FormattedValueDMData>(executor, null) {
+ @Override
+ protected void handleSuccess() {
+ FormattedValueDMData data= getData();
+ final String value= data.getFormattedValue();
+ final BigInteger address= decodeAddress(value);
+ if (address != null) {
+ asyncExec(new Runnable() {
+ public void run() {
+ gotoAddress(address);
+ }});
+ }
+ }
+ @Override
+ protected void handleError() {
+ asyncExec(new Runnable() {
+ public void run() {
+ ErrorDialog.openError(getSite().getShell(), "Error", null, getStatus()); //$NON-NLS-1$
+ }});
+ }
+ });
+ }});
+ }
+
+ private void gotoPosition(Position pos, boolean select) {
+ if (fViewer == null) {
+ return;
+ }
+ setFocusPosition(pos);
+ fViewer.setSelectedRange(pos.offset, select ? Math.max(pos.length-1, 0) : 0);
+ int revealOffset = pos.offset;
+ boolean onTop = false;
+ if (/* !fUpdateBeforeFocus && */ pos.offset > 0) {
+ try {
+ AddressRangePosition previousPos = fDocument.getModelPosition(pos.offset - 1);
+ if (previousPos instanceof LabelPosition) {
+ revealOffset = previousPos.offset;
+ onTop = true;
+ } else if (!previousPos.fValid) {
+ onTop = true;
+ }
+ } catch (BadLocationException e) {
+ // cannot happen
+ }
+ }
+ fViewer.revealOffset(revealOffset, onTop);
+ }
+
+ private void gotoMarker(final IMarker marker) {
+ if (marker == null) {
+ return;
+ }
+ if (fDebugSessionId == null || fUpdatePending) {
+ fGotoMarkerPending = marker;
+ return;
+ }
+ fGotoMarkerPending = null;
+
+ //TLETODO [disassembly] goto (breakpoint) marker
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IViewportListener#viewportChanged(int)
+ */
+ public void viewportChanged(int verticalOffset) {
+ if (fDebugSessionId != null && fGotoAddressPending == PC_UNKNOWN && fScrollPos == null && !fUpdatePending && !fRefreshViewPending) {
+ fUpdatePending = true;
+ invokeLater(new Runnable() {
+ public void run() {
+ assert fUpdatePending;
+ if (fUpdatePending) {
+ fUpdatePending = false;
+ updateVisibleArea();
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Update lines of currently visible area + one page buffer zone below.
+ */
+ private void updateVisibleArea() {
+ if (!fActive || fUpdatePending || fViewer == null || fDebugSessionId == null) {
+ return;
+ }
+ if (fTargetContext == null || !isSuspended(fTargetContext) || fFrameAddress == PC_UNKNOWN) {
+ return;
+ }
+ StyledText styledText = fViewer.getTextWidget();
+ Rectangle clientArea = styledText.getClientArea();
+ fBufferZone = Math.max(8, clientArea.height / styledText.getLineHeight());
+ int topIndex = fViewer.getTopIndex();
+ int bottomIndex = fViewer.getBottomIndex();
+ int focusIndex = -1;
+ boolean focusVisible = false;
+ boolean isScrollingUp = fViewer.isUserTriggeredScrolling() && fViewer.getLastTopPixel() >= styledText.getTopPixel();
+ if (fFocusPos != null) {
+ try {
+ int focusOffset = fFocusPos.offset;
+ focusIndex = fDocument.getLineOfOffset(focusOffset);
+ focusVisible = focusIndex >= topIndex && focusIndex <= bottomIndex;
+ // workaround for: Clicking the IP annotation in the right ruler has no effect.
+ // we deselect the IP location if it is scrolled outside the visible area
+ if (!focusVisible) {
+ Point selection = fViewer.getSelectedRange();
+ if (selection.x == focusOffset && selection.y > 0) {
+ fViewer.setSelectedRange(selection.x, 0);
+ }
+ }
+ } catch (BadLocationException e) {
+ setFocusPosition(null);
+ }
+ }
+ if (!focusVisible) {
+ focusIndex = topIndex + fScrollLine;
+ }
+ BigInteger focusAddress = getAddressOfLine(focusIndex);
+ bottomIndex += 2;
+ AddressRangePosition bestPosition = null;
+ int bestLine = -1;
+ BigInteger bestDistance = null;
+ Iterator<AddressRangePosition> it = fDocument.getInvalidAddressRanges().iterator();
+ while (it.hasNext()) {
+ AddressRangePosition p = it.next();
+ try {
+ int line = fDocument.getLineOfOffset(p.offset);
+ if (line >= topIndex && line <= bottomIndex) {
+ if (p instanceof DisassemblyPosition || p.fAddressLength.compareTo(
+ BigInteger.valueOf(fBufferZone * 2)) <= 0) {
+ // small areas and known areas are OK to update
+ } else if (!isScrollingUp && !fUpdateBeforeFocus
+ && p.fAddressOffset.compareTo(focusAddress) < 0) {
+ continue;
+ }
+ BigInteger distance = p.fAddressOffset.subtract(focusAddress).abs();
+ if (bestDistance == null || distance.compareTo(bestDistance) < 0) {
+ bestPosition = p;
+ bestLine = line;
+ bestDistance = distance;
+ if (bestDistance.compareTo(BigInteger.valueOf(fBufferZone * 2)) <= 0) {
+ break;
+ }
+ }
+ }
+ } catch (BadLocationException e) {
+ continue;
+ }
+ }
+ if (bestPosition != null) {
+ int lines = fBufferZone+3;
+ BigInteger startAddress = bestPosition.fAddressOffset;
+ BigInteger endAddress = bestPosition.fAddressOffset.add(bestPosition.fAddressLength);
+ BigInteger addressRange = BigInteger.valueOf(lines * fDocument.getMeanSizeOfInstructions());
+ if (bestLine > focusIndex || bestLine == focusIndex && startAddress.compareTo(focusAddress) >= 0) {
+ // insert at start of range
+ if (endAddress.subtract(startAddress).compareTo(addressRange) < 0) {
+ // try to increase range to reduce number of requests
+ Iterator<?> iter = fDocument.getModelPositionIterator(endAddress);
+ while (iter.hasNext()) {
+ AddressRangePosition p = (AddressRangePosition)iter.next();
+ if (p.fValid) {
+ endAddress = endAddress.add(p.fAddressLength);
+ if (endAddress.subtract(startAddress).compareTo(addressRange) >= 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ } else {
+ // insert at end of range
+ startAddress = startAddress.max(endAddress.subtract(addressRange));
+ // make sure we get all disassembly lines until endAddress
+ lines = endAddress.subtract(startAddress).intValue();
+ }
+ retrieveDisassembly(startAddress, endAddress, lines);
+ }
+ scheduleDoPending();
+ }
+
+ private void asyncExec(Runnable runnable) {
+ if (fViewer != null) {
+ fViewer.getControl().getDisplay().asyncExec(runnable);
+ }
+ }
+ private void invokeLater(Runnable runnable) {
+ invokeLater(10, runnable);
+ }
+ private void invokeLater(int delay, Runnable runnable) {
+ if (fViewer != null) {
+ fViewer.getControl().getDisplay().timerExec(delay, runnable);
+ }
+ }
+
+ /**
+ * Insert sourcelines if available.
+ */
+ /*default*/ void updateInvalidSource() {
+ if (fViewer == null) {
+ return;
+ }
+ boolean unlock = false;
+ try {
+ if (fScrollPos == null) {
+ if (fUpdatePending) {
+ fUpdateSourcePending= true;
+ return;
+ }
+ fUpdateSourcePending= false;
+ unlock = true;
+ fUpdatePending = true;
+ lockScroller();
+ }
+ ArrayList<SourcePosition> copy = new ArrayList<SourcePosition>(fDocument.getInvalidSource());
+ Iterator<SourcePosition> it = copy.iterator();
+ while (it.hasNext()) {
+ SourcePosition p = it.next();
+ if (!p.fValid) {
+ insertSource(p);
+ } else if (DEBUG && fDocument.getInvalidSource().remove(p)) {
+ System.err.println("!!! valid source position in invalid source list at "+getAddressText(p.fAddressOffset)); //$NON-NLS-1$
+ }
+ }
+ } finally {
+ if (unlock) {
+ fUpdatePending = false;
+ unlockScroller();
+ doPending();
+ }
+ }
+ }
+
+ /**
+ * Show disassembly for given (source) file.
+ *
+ * @param file
+ * @param lines
+ */
+ void retrieveDisassembly(final String file, final int lines, final boolean mixed) {
+ if (fDebugSessionId == null) {
+ return;
+ }
+ if (fUpdatePending) {
+ invokeLater(new Runnable() {
+ public void run() {
+ retrieveDisassembly(file, lines, mixed);
+ }});
+ return;
+ }
+ if (DEBUG) System.out.println("retrieveDisassembly "+file); //$NON-NLS-1$
+ String debuggerPath= file;
+
+ // try reverse lookup
+ final ISourceLookup lookup= getService(ISourceLookup.class);
+ final ISourceLookupDMContext ctx= DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class);
+ final DsfExecutor executor= getSession().getExecutor();
+ Query<String> query= new Query<String>() {
+ @Override
+ protected void execute(final DataRequestMonitor<String> rm) {
+ final DataRequestMonitor<String> request= new DataRequestMonitor<String>(executor, rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData());
+ rm.done();
+ }
+ };
+ lookup.getDebuggerPath(ctx, file, request);
+ }
+ };
+ try {
+ getSession().getExecutor().execute(query);
+ debuggerPath= query.get();
+ } catch (InterruptedException exc) {
+ internalError(exc);
+ } catch (ExecutionException exc) {
+ internalError(exc);
+ }
+
+ final IDisassembly disassembly= fServicesTracker.getService(IDisassembly.class);
+ final IDisassemblyDMContext context= DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class);
+
+ final String finalFile= debuggerPath;
+ final DataRequestMonitor<IMixedInstruction[]> disassemblyRequest= new DataRequestMonitor<IMixedInstruction[]>(executor, null) {
+ @Override
+ public void handleCompleted() {
+ final IMixedInstruction[] data= getData();
+ if (!isCanceled() && data != null) {
+ asyncExec(new Runnable() {
+ public void run() {
+ if (!insertDisassembly(null, data)) {
+ // retry in non-mixed mode
+ retrieveDisassembly(file, lines, false);
+ }
+ }});
+ } else {
+ final IStatus status= getStatus();
+ if (status != null && !status.isOK()) {
+ asyncExec(new Runnable() {
+ public void run() {
+ ErrorDialog.openError(getSite().getShell(), "Error", null, getStatus()); //$NON-NLS-1$
+ }
+ });
+ }
+ fUpdatePending= false;
+ }
+ }
+ };
+ assert !fUpdatePending;
+ fUpdatePending = true;
+ executor.submit(new Runnable() {
+ public void run() {
+ disassembly.getMixedInstructions(context, finalFile, 1, lines, disassemblyRequest);
+ }});
+ }
+
+ private void retrieveDisassembly(BigInteger startAddress, BigInteger endAddress, int lines) {
+ if (fDebugSessionId == null) {
+ return;
+ }
+ if (DEBUG) System.out.println("retrieveDisassembly "+getAddressText(startAddress)+" "+lines+" lines"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ retrieveDisassembly(startAddress, endAddress, lines, true);
+ }
+
+ private void retrieveDisassembly(final BigInteger startAddress, BigInteger endAddress, final int linesHint, boolean mixed) {
+ assert !fUpdatePending;
+ fUpdatePending = true;
+ final int lines= linesHint + 2;
+ final BigInteger addressLength= BigInteger.valueOf(lines * 4);
+ if (endAddress.subtract(startAddress).compareTo(addressLength) > 0) {
+ endAddress= startAddress.add(addressLength);
+ }
+ boolean insideActiveFrame= startAddress.equals(fFrameAddress);
+ String file= null;
+ int lineNumber= -1;
+ if (insideActiveFrame && fTargetFrameData != null) {
+ file= fTargetFrameData.getFile();
+ if (file != null && file.trim().length() == 0) {
+ file= null;
+ }
+ lineNumber= fTargetFrameData.getLine();
+ }
+ final String finalFile= file;
+ final int finalLineNumber= lineNumber;
+ final BigInteger finalEndAddress= endAddress;
+
+ final DsfExecutor executor= getSession().getExecutor();
+ final IDisassembly disassembly= fServicesTracker.getService(IDisassembly.class);
+ final IDisassemblyDMContext context= DMContexts.getAncestorOfType(fTargetContext, IDisassemblyDMContext.class);
+
+ if (mixed) {
+ final DataRequestMonitor<IMixedInstruction[]> disassemblyRequest= new DataRequestMonitor<IMixedInstruction[]>(executor, null) {
+ @Override
+ public void handleCompleted() {
+ final IMixedInstruction[] data= getData();
+ if (!isCanceled() && data != null) {
+ asyncExec(new Runnable() {
+ public void run() {
+ if (!insertDisassembly(startAddress, data)) {
+ // retry in non-mixed mode
+ retrieveDisassembly(startAddress, finalEndAddress, linesHint, false);
+ }
+ }});
+ } else {
+ final IStatus status= getStatus();
+ if (status != null && !status.isOK()) {
+ asyncExec(new Runnable() {
+ public void run() {
+ doScrollLocked(new Runnable() {
+ public void run() {
+ insertError(startAddress, status.getMessage());
+ }
+ });
+ }});
+ }
+ fUpdatePending= false;
+ }
+ }
+ };
+ if (file != null) {
+ executor.submit(new Runnable() {
+ public void run() {
+ disassembly.getMixedInstructions(context, finalFile, finalLineNumber, lines*2, disassemblyRequest);
+ }});
+ } else {
+ executor.submit(new Runnable() {
+ public void run() {
+ disassembly.getMixedInstructions(context, startAddress, finalEndAddress, disassemblyRequest);
+ }});
+ }
+ } else {
+ final DataRequestMonitor<IInstruction[]> disassemblyRequest= new DataRequestMonitor<IInstruction[]>(executor, null) {
+ @Override
+ public void handleCompleted() {
+ if (!isCanceled() && getData() != null) {
+ asyncExec(new Runnable() {
+ public void run() {
+ insertDisassembly(startAddress, getData());
+ }});
+ } else {
+ final IStatus status= getStatus();
+ if (status != null && !status.isOK()) {
+ asyncExec(new Runnable() {
+ public void run() {
+ doScrollLocked(new Runnable() {
+ public void run() {
+ insertError(startAddress, status.getMessage());
+ }
+ });
+ }});
+ }
+ fUpdatePending= false;
+ }
+ }
+ };
+ if (file != null) {
+ executor.submit(new Runnable() {
+ public void run() {
+ disassembly.getInstructions(context, finalFile, finalLineNumber, lines, disassemblyRequest);
+ }});
+ } else {
+ executor.submit(new Runnable() {
+ public void run() {
+ disassembly.getInstructions(context, startAddress, finalEndAddress, disassemblyRequest);
+ }});
+ }
+ }
+ }
+
+ private void insertError(BigInteger address, String message) {
+ AddressRangePosition p = null;
+ p = getPositionOfAddress(address);
+ if (p.fValid) {
+ return;
+ }
+ try {
+ fDocument.insertErrorLine(p, address, BigInteger.ONE, message);
+ } catch (BadLocationException exc) {
+ internalError(exc);
+ }
+ }
+
+ private void insertDisassembly(BigInteger startAddress, IInstruction[] instructions) {
+ if (fViewer == null || fDebugSessionId == null) {
+ return;
+ }
+ if (DEBUG) System.out.println("insertDisassembly "+getAddressText(startAddress)); //$NON-NLS-1$
+ assert fUpdatePending;
+ if (!fUpdatePending) {
+ // safe-guard in case something weird is going on
+ return;
+ }
+ try {
+ lockScroller();
+
+ AddressRangePosition p= null;
+ for (int j = 0; j < instructions.length; j++) {
+ IInstruction instruction = instructions[j];
+ BigInteger address= instruction.getAdress();
+ if (startAddress == null || startAddress.compareTo(BigInteger.ZERO) < 0) {
+ fGotoAddressPending = startAddress = address;
+ }
+ if (p == null || !p.containsAddress(address)) {
+ p = getPositionOfAddress(address);
+ }
+ if (p instanceof ErrorPosition && p.fValid) {
+ p.fValid = false;
+ fDocument.getInvalidAddressRanges().add(p);
+ } else if (p == null || p.fValid) {
+ if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$
+ return;
+ }
+ boolean hasSource= false;
+ String compilationPath= null;
+ // insert symbol label
+ final String functionName= instruction.getFuntionName();
+ if (functionName != null && functionName.length() > 0 && instruction.getOffset() == 0) {
+ p = fDocument.insertLabel(p, address, functionName, fShowSymbols && (!hasSource || fShowDisassembly));
+ }
+ // determine instruction byte length
+ BigInteger instrLength= null;
+ if (j < instructions.length - 1) {
+ instrLength= instructions[j+1].getAdress().subtract(instruction.getAdress()).abs();
+ } else if (instructions.length == 1) {
+ if (p.fAddressLength.compareTo(BigInteger.valueOf(8)) <= 0) {
+ instrLength= p.fAddressLength;
+ }
+ }
+ if (instrLength == null) {
+ // cannot determine length of last instruction
+ break;
+ }
+ final String opCode;
+ // insert function name+offset instead of opcode bytes
+ if (functionName != null && functionName.length() > 0) {
+ opCode= functionName + '+' + instruction.getOffset();
+ } else {
+ opCode= ""; //$NON-NLS-1$
+ }
+ p = fDocument.insertDisassemblyLine(p, address, instrLength.intValue(), opCode, instruction.getInstruction(), compilationPath, -1);
+ if (p == null) {
+ break;
+ }
+ }
+
+ } catch (BadLocationException e) {
+ // should not happen
+ internalError(e);
+ } finally {
+ fUpdatePending = false;
+ updateInvalidSource();
+ unlockScroller();
+ doPending();
+ updateVisibleArea();
+ }
+ }
+
+ private boolean insertDisassembly(BigInteger startAddress, IMixedInstruction[] mixedInstructions) {
+ if (fViewer == null || fDebugSessionId == null) {
+ return true;
+ }
+ if (DEBUG) System.out.println("insertDisassembly "+getAddressText(startAddress)); //$NON-NLS-1$
+ assert fUpdatePending;
+ if (!fUpdatePending) {
+ // safe-guard in case something weird is going on
+ return true;
+ }
+ // indicates whether disassembly for the start address was inserted
+ boolean success= false;
+ try {
+ lockScroller();
+
+ AddressRangePosition p= null;
+ for (int i = 0; i < mixedInstructions.length; ++i) {
+ IMixedInstruction mixedInstruction= mixedInstructions[i];
+ final String file= mixedInstruction.getFileName();
+ final int lineNumber= mixedInstruction.getLineNumber() - 1;
+ IInstruction[] instructions= mixedInstruction.getInstructions();
+ for (int j = 0; j < instructions.length; ++j) {
+ IInstruction instruction = instructions[j];
+ BigInteger address= instruction.getAdress();
+ if (startAddress == null || startAddress.compareTo(BigInteger.ZERO) < 0) {
+ fGotoAddressPending = startAddress = address;
+ }
+ if (p == null || !p.containsAddress(address)) {
+ p = getPositionOfAddress(address);
+ }
+ if (p instanceof ErrorPosition && p.fValid) {
+ p.fValid = false;
+ fDocument.getInvalidAddressRanges().add(p);
+ } else if (p == null) {
+ if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$
+ return success;
+ } else if (p.fValid) {
+ if (DEBUG) System.out.println("Excess disassembly lines at " + getAddressText(address)); //$NON-NLS-1$
+ if (file != null && lineNumber >= 0 || p.fAddressLength == BigInteger.ONE) {
+ // override probably unaligned disassembly
+ p.fValid = false;
+ fDocument.getInvalidAddressRanges().add(p);
+ } else {
+ return success;
+ }
+ }
+ boolean hasSource= false;
+ if (file != null && lineNumber >= 0) {
+ p = insertSource(p, address, file, lineNumber);
+ hasSource = fFile2Storage.get(file) != null;
+ }
+ // insert symbol label
+ final String functionName= instruction.getFuntionName();
+ if (functionName != null && functionName.length() > 0 && instruction.getOffset() == 0) {
+ p = fDocument.insertLabel(p, address, functionName, fShowSymbols && (!hasSource || fShowDisassembly));
+ }
+ // determine instruction byte length
+ BigInteger instrLength= null;
+ if (j < instructions.length - 1) {
+ instrLength= instructions[j+1].getAdress().subtract(instruction.getAdress()).abs();
+ } else if (i < mixedInstructions.length - 1) {
+ int nextSrcLineIdx= i+1;
+ while (nextSrcLineIdx < mixedInstructions.length) {
+ IInstruction[] nextInstrs= mixedInstructions[nextSrcLineIdx].getInstructions();
+ if (nextInstrs.length > 0) {
+ instrLength= nextInstrs[0].getAdress().subtract(instruction.getAdress()).abs();
+ break;
+ }
+ ++nextSrcLineIdx;
+ }
+ if (nextSrcLineIdx >= mixedInstructions.length) {
+ break;
+ }
+ } else if (instructions.length == 1) {
+ if (p.fAddressLength.compareTo(BigInteger.valueOf(8)) <= 0) {
+ instrLength= p.fAddressLength;
+ }
+ }
+ if (instrLength == null) {
+ // cannot determine length of last instruction
+ break;
+ }
+ final String opCode;
+ // insert function name+offset instead of opcode bytes
+ if (functionName != null && functionName.length() > 0) {
+ opCode= functionName + '+' + instruction.getOffset();
+ } else {
+ opCode= ""; //$NON-NLS-1$
+ }
+ success= success || address.compareTo(startAddress) == 0;
+ p = fDocument.insertDisassemblyLine(p, address, instrLength.intValue(), opCode, instruction.getInstruction(), file, lineNumber);
+ if (p == null && success) {
+ break;
+ }
+ }
+ }
+
+ } catch (BadLocationException e) {
+ // should not happen
+ internalError(e);
+ } finally {
+ fUpdatePending = false;
+ if (success) {
+ updateInvalidSource();
+ unlockScroller();
+ doPending();
+ updateVisibleArea();
+ } else {
+ unlockScroller();
+ }
+ }
+ return success;
+ }
+
+ private void retrieveFrameAddress(final IExecutionDMContext targetContext, final int frame) {
+ if (targetContext != null && isSuspended(targetContext)) {
+ if (fUpdatePending) {
+ gotoFrame(frame);
+ return;
+ }
+ if (DEBUG) System.out.println("retrieveFrameAddress "+frame); //$NON-NLS-1$
+ fUpdatePending = true;
+ final IStack stack= fServicesTracker.getService(IStack.class);
+ final DsfExecutor executor= getSession().getExecutor();
+ if (fTargetFrameContext == null) {
+ if (frame == 0) {
+ final DataRequestMonitor<IFrameDMContext> request= new DataRequestMonitor<IFrameDMContext>(executor, null) {
+ @Override
+ protected void handleCompleted() {
+ fUpdatePending= false;
+ fTargetFrameContext= getData();
+ if (fTargetFrameContext != null) {
+ retrieveFrameAddress(targetContext, frame);
+ }
+ }
+ };
+ executor.submit(new Runnable() {
+ public void run() {
+ stack.getTopFrame(targetContext, request);
+ }});
+ } else {
+ // TODO retrieve other stack frame
+ }
+ return;
+ }
+ final DataRequestMonitor<IFrameDMData> request= new DataRequestMonitor<IFrameDMData>(executor, null) {
+ @Override
+ protected void handleCompleted() {
+ if (!isCanceled()) {
+ fUpdatePending= false;
+ final IFrameDMData frameData= getData();
+ fTargetFrameData= frameData;
+ final IAddress address= frameData.getAddress();
+ final BigInteger addressValue= address.getValue();
+ if (DEBUG) System.out.println("retrieveFrameAddress done "+getAddressText(addressValue)); //$NON-NLS-1$
+ asyncExec(new Runnable() {
+ public void run() {
+ if (address.getSize() * 4 > fAddressSize) {
+ addressSizeChanged(address.getSize() * 4);
+ }
+ if (frame == 0) {
+ updatePC(addressValue);
+ } else {
+ gotoFrame(frame, addressValue);
+ }
+ }
+
+ });
+ }
+ }
+ };
+ executor.submit(new Runnable() {
+ public void run() {
+ stack.getFrameData(fTargetFrameContext, request);
+ }});
+ }
+ }
+
+ private void addressSizeChanged(int addressSize) {
+ BigInteger oldEndAddress= fEndAddress;
+ fEndAddress= BigInteger.ONE.shiftLeft(addressSize);
+ int oldAddressSize= fAddressSize;
+ fAddressSize= addressSize;
+ if (addressSize < oldAddressSize) {
+ fDocument.deleteDisassemblyRange(fEndAddress, oldEndAddress, true, true);
+ List<AddressRangePosition> positions= fDocument.getInvalidAddressRanges();
+ List<AddressRangePosition> toRemove= new ArrayList<AddressRangePosition>();
+ for (AddressRangePosition position : positions) {
+ if (position.fAddressOffset.compareTo(fEndAddress) >= 0) {
+ try {
+ fDocument.replace(position, position.length, ""); //$NON-NLS-1$
+ fDocument.removeModelPosition(position);
+ toRemove.add(position);
+ } catch (BadLocationException exc) {
+ internalError(exc);
+ }
+ } else if (position.containsAddress(fEndAddress)){
+ position.fAddressLength= fEndAddress.subtract(position.fAddressOffset);
+ }
+ }
+ positions.removeAll(toRemove);
+ } else if (addressSize > oldAddressSize) {
+ fDocument.insertInvalidAddressRange(fDocument.getLength(), 0, oldEndAddress, fEndAddress);
+ } else {
+ return;
+ }
+ if (fAddressRulerColumn != null) {
+ fAddressRulerColumn.setAddressSize(addressSize);
+ if (fComposite != null) {
+ fComposite.layout(true);
+ }
+ }
+ }
+
+ private AddressRangePosition getPositionOfAddress(BigInteger address) {
+ if (address == null || address.compareTo(BigInteger.ZERO) < 0) {
+ return null;
+ }
+ AddressRangePosition pos = fDocument.getPositionOfAddress(address);
+ assert !(pos instanceof SourcePosition);
+ assert pos != null || address.compareTo(fStartAddress) < 0|| address.compareTo(fEndAddress) >= 0;
+ return pos;
+ }
+
+ private BigInteger getAddressOfLine(int line) {
+ return fDocument.getAddressOfLine(line);
+ }
+
+ /**
+ * Passing the focus request to the viewer's control.
+ */
+ @Override
+ public void setFocus() {
+ fViewer.getControl().setFocus();
+ }
+
+ protected void setActive(boolean active) {
+ if (DEBUG) System.out.println("setActive("+ active +")"); //$NON-NLS-1$ //$NON-NLS-2$
+ fActive = active;
+ if (fActive) {
+ if (fRefreshAll) {
+ fRefreshAll = false;
+ refreshView(0);
+ } else {
+ doPendingPCUpdates();
+ if (fTargetContext != null) {
+ int frame = getActiveStackFrame();
+ if (frame < 0 && isSuspended(fTargetContext)) {
+ frame= 0;
+ }
+ if (frame != fTargetFrame) {
+ gotoFrame(frame);
+ }
+ }
+ }
+ } else {
+ fGotoAddressPending= fFocusAddress= PC_UNKNOWN;
+ }
+ firePropertyChange(PROP_ACTIVE);
+ }
+
+ private int getActiveStackFrame() {
+ if (fTargetFrameContext != null) {
+ return fTargetFrameContext.getLevel();
+ }
+ return -1;
+ }
+
+ /**
+ *
+ */
+ protected void updateDebugContext() {
+ IAdaptable debugContext= DebugUITools.getDebugContext();
+ if (debugContext instanceof IDMVMContext) {
+ setDebugContext((IDMVMContext)debugContext);
+ }
+ }
+
+ protected void setDebugContext(IDMVMContext vmContext) {
+ if (vmContext != null) {
+ IDMContext dmContext= vmContext.getDMContext();
+ String sessionId= dmContext.getSessionId();
+ if (!sessionId.equals(fDebugSessionId)) {
+ // switch to different session or initiate session
+ if (DEBUG) System.out.println("DisassemblyPart.setDebugContext() " + sessionId); //$NON-NLS-1$
+ fTargetContext= null;
+ if (dmContext instanceof IFrameDMContext) {
+ IFrameDMContext frame= (IFrameDMContext) dmContext;
+ IExecutionDMContext executionContext= DMContexts.getAncestorOfType(frame, IExecutionDMContext.class);
+ if (executionContext != null) {
+ fTargetContext= executionContext;
+ fTargetFrameContext= frame;
+ fTargetFrame= frame.getLevel();
+ }
+ }
+ if (fTargetContext != null) {
+ if (fDebugSessionId != null) {
+ if (getSession() != null) {
+ getSession().removeServiceEventListener(this);
+ }
+ }
+ fDebugSessionId= sessionId;
+ if (fServicesTracker != null) {
+ fServicesTracker.dispose();
+ }
+ fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), sessionId);
+ if (fViewer != null) {
+ debugContextChanged();
+ }
+ }
+ } else if (dmContext instanceof IFrameDMContext) {
+ // switch to different frame
+ IFrameDMContext frame= (IFrameDMContext) dmContext;
+ final IDMContext[] parents= frame.getParents();
+ for (IDMContext context : parents) {
+ if (context instanceof IExecutionDMContext) {
+ fTargetContext= (IExecutionDMContext) context;
+ fTargetFrameContext= frame;
+ gotoFrame(frame);
+ break;
+ }
+ }
+ }
+ } else if (fDebugSessionId != null) {
+ if (getSession() != null) {
+ getSession().removeServiceEventListener(this);
+ }
+ fDebugSessionId= null;
+ fTargetContext= null;
+ if (fServicesTracker != null) {
+ fServicesTracker.dispose();
+ fServicesTracker= null;
+ }
+ if (fViewer != null) {
+ debugContextChanged();
+ }
+ }
+ }
+
+ private void debugContextChanged() {
+ if (DEBUG) System.out.println("DisassemblyPart.debugContextChanged()"); //$NON-NLS-1$
+ fRunnableQueue.clear();
+ fUpdatePending = false;
+ resetViewer();
+ if (fDebugSessionId != null) {
+ final DsfSession session= getSession();
+ session.addServiceEventListener(this, null);
+ updatePC(PC_UNKNOWN);
+
+ if (fGotoAddressPending != PC_UNKNOWN) {
+ gotoAddress(fGotoAddressPending);
+ }
+ if (fGotoMarkerPending != null) {
+ gotoMarker(fGotoMarkerPending);
+ }
+ fViewer.addViewportListener(this);
+ } else {
+ fViewer.removeViewportListener(this);
+ fGotoMarkerPending = null;
+// invokeLater(new Runnable() {
+// public void run() {
+// closePart();
+// }});
+ }
+ updateTitle();
+ updateStateDependentActions();
+ firePropertyChange(PROP_CONNECTED);
+ firePropertyChange(PROP_SUSPENDED);
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.service.DsfSession.SessionEndedListener#sessionEnded(org.eclipse.cdt.dsf.service.DsfSession)
+ */
+ public void sessionEnded(DsfSession endedSsession) {
+ if (endedSsession.getId().equals(fDebugSessionId)) {
+ asyncExec(new Runnable() {
+ public void run() {
+ setDebugContext(null);
+ }});
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void handleEvent(IExitedDMEvent event) {
+ final IExecutionDMContext context= event.getDMContext();
+ if (context.equals(fTargetContext)
+ || DMContexts.isAncestorOf(fTargetContext, context)) {
+ asyncExec(new Runnable() {
+ public void run() {
+ setDebugContext(null);
+ }});
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void handleEvent(ISuspendedDMEvent event) {
+ final IExecutionDMContext context= event.getDMContext();
+ if (context.equals(fTargetContext)
+ || DMContexts.isAncestorOf(fTargetContext, context)) {
+ asyncExec(new Runnable() {
+ public void run() {
+ updatePC(PC_UNKNOWN);
+ firePropertyChange(PROP_SUSPENDED);
+ }
+ });
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void handleEvent(IResumedDMEvent event) {
+ final IExecutionDMContext context= event.getDMContext();
+ if (context.equals(fTargetContext)
+ || DMContexts.isAncestorOf(fTargetContext, context)) {
+ asyncExec(new Runnable() {
+ public void run() {
+ updatePC(PC_RUNNING);
+ firePropertyChange(PROP_SUSPENDED);
+ }
+ });
+ }
+ }
+
+ private void attachBreakpointsAnnotationModel() {
+ IAnnotationModel annotationModel = fViewer.getAnnotationModel();
+ if (annotationModel instanceof IAnnotationModelExtension) {
+ IAnnotationModelExtension ame= (IAnnotationModelExtension) annotationModel;
+ ame.addAnnotationModel(BREAKPOINT_ANNOTATIONS, new BreakpointsAnnotationModel());
+ }
+ }
+
+ private void refreshView(int delay) {
+ if (fViewer == null || fRefreshViewPending || fRefreshAll) {
+ return;
+ }
+ fRunnableQueue.clear();
+ fRefreshViewPending = true;
+ final long refreshViewScheduled = System.currentTimeMillis() + delay;
+ final Runnable refresh = new Runnable() {
+ public void run() {
+ fRefreshViewPending = false;
+ long now = System.currentTimeMillis();
+ if (now >= refreshViewScheduled) {
+ if (DEBUG) System.err.println("*** refreshing view ***"); //$NON-NLS-1$
+ fFocusAddress = PC_UNKNOWN;
+ int targetFrame= fTargetFrame;
+ resetViewer();
+ if (fScrollPos != null) {
+ fScrollPos.isDeleted = true;
+ }
+ gotoFrame(targetFrame);
+ } else {
+ refreshView((int)(refreshViewScheduled - now));
+ }
+ }};
+ if (delay > 0) {
+ invokeLater(delay, new Runnable() {
+ public void run() {
+ doScrollLocked(refresh);
+ }});
+ } else {
+ doScrollLocked(refresh);
+ }
+ }
+
+ private void resetViewer() {
+ // clear all state and cache
+ fPCAnnotationUpdatePending = false;
+ fGotoFramePending = false;
+ fPCAddress = fFrameAddress = PC_RUNNING;
+ fTargetFrame = -1;
+ fGotoAddressPending = fFocusAddress;
+ fFocusAddress = PC_UNKNOWN;
+ setFocusPosition(null);
+ fPCHistory.clear();
+ fPendingPCUpdates.clear();
+ fFile2Storage.clear();
+ DisassemblyDocument doc= fDocument;
+ fDocument = createDocument();
+ fViewer.setDocument(fDocument, new AnnotationModel());
+ doc.dispose();
+ if (fDebugSessionId != null) {
+ attachBreakpointsAnnotationModel();
+ fDocument.insertInvalidAddressRange(0, 0, fStartAddress, fEndAddress);
+ }
+ }
+
+ private AddressRangePosition getPCPosition(BigInteger address) {
+ if (address.compareTo(BigInteger.ZERO) < 0) {
+ // invalid address
+ return null;
+ }
+ AddressRangePosition pos = getPositionOfAddress(address);
+ if (pos == null || !pos.fValid) {
+ // invalid disassembly line
+ return null;
+ }
+ if (pos.length > 0) {
+ // valid disassembly line
+ return pos;
+ }
+ // hidden disassembly
+ if (!(pos instanceof DisassemblyPosition)) {
+ return pos;
+ }
+ String srcFile = ((DisassemblyPosition)pos).getFile();
+ if (srcFile == null) {
+ return pos;
+ }
+ SourceFileInfo fi = fDocument.getSourceInfo(srcFile);
+ if (fi == null) {
+ return pos;
+ }
+ if (fi.fSource == null) {
+ if (fi.fError != null) {
+ // could not read source
+ return pos;
+ }
+ return null;
+ }
+// if (!fi.fValid) {
+// // need line info first
+// return null;
+// }
+ // determine stmt line of source range
+ try {
+ int stmtLine = ((DisassemblyPosition)pos).getLine();
+ if (stmtLine < 0) {
+ return pos;
+ }
+ BigInteger stmtAddress = fi.fLine2Addr[stmtLine];
+ if (stmtAddress.compareTo(BigInteger.ZERO) < 0) {
+ return pos;
+ }
+ SourcePosition srcPos = fDocument.getSourcePosition(stmtAddress);
+ if (srcPos == null) {
+ return pos;
+ } else if (!srcPos.fValid) {
+ return null;
+ }
+ assert stmtLine >= srcPos.fLine;
+ int baseOffset = fi.fSource.getLineOffset(srcPos.fLine);
+ IRegion stmtLineRegion = fi.fSource.getLineInformation(stmtLine);
+ int lineOffset = stmtLineRegion.getOffset();
+ int offset = srcPos.offset + lineOffset - baseOffset;
+ int length = stmtLineRegion.getLength() + 1;
+ if (offset >= srcPos.offset && offset < srcPos.offset + srcPos.length) {
+ return new AddressRangePosition(offset, length, address, BigInteger.ZERO);
+ }
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ return pos;
+ }
+
+ /**
+ * Update the annotation indicating the given address.
+ * @return a position which denotes the documents position
+ */
+ private AddressRangePosition updateAddressAnnotation(Annotation annotation, BigInteger address) {
+ IAnnotationModel annotationModel = fViewer.getAnnotationModel();
+ annotationModel.removeAnnotation(annotation);
+ AddressRangePosition pos = getPCPosition(address);
+ if (pos != null) {
+ annotationModel.addAnnotation(annotation, new Position(pos.offset, Math.max(0, pos.length-1)));
+ }
+ return pos;
+ }
+
+ public IBreakpoint[] getBreakpointsAtLine(int line) {
+ BreakpointsAnnotationModel bpModel= null;
+ IAnnotationModel am= fViewer.getAnnotationModel();
+ if (am instanceof IAnnotationModelExtension) {
+ IAnnotationModelExtension ame= (IAnnotationModelExtension) am;
+ bpModel= (BreakpointsAnnotationModel) ame.getAnnotationModel(BREAKPOINT_ANNOTATIONS);
+ if (bpModel != null) {
+ IRegion lineRegion;
+ try {
+ lineRegion= fDocument.getLineInformation(line);
+ } catch (BadLocationException exc) {
+ return null;
+ }
+ int offset= lineRegion.getOffset();
+ int length= lineRegion.getLength();
+ @SuppressWarnings("unchecked")
+ Iterator<SimpleMarkerAnnotation> it= bpModel.getAnnotationIterator(offset, length, true, true);
+ List<IBreakpoint> bpList= new ArrayList<IBreakpoint>(5);
+ final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager();
+ while (it.hasNext()) {
+ final SimpleMarkerAnnotation annotation= it.next();
+ IBreakpoint bp= bpMgr.getBreakpoint(annotation.getMarker());
+ if (bp != null) {
+ bpList.add(bp);
+ }
+ }
+ if (bpList.size() > 0) {
+ return bpList.toArray(new IBreakpoint[bpList.size()]);
+ }
+ }
+ }
+ return null;
+ }
+
+ private void gotoFrame(int frame, BigInteger address) {
+ if (DEBUG) System.out.println("gotoFrame " + frame + " " + getAddressText(address)); //$NON-NLS-1$ //$NON-NLS-2$
+ fTargetFrame = frame;
+ fFrameAddress = address;
+ if (fTargetFrame == -1) {
+ fTargetFrame = getActiveStackFrame();
+ if (fTargetFrame < 0 && isSuspended(fTargetContext)) {
+ fTargetFrame= 0;
+ }
+ if (fTargetFrame == -1) {
+ fGotoFramePending = false;
+ return;
+ }
+ }
+ fGotoFramePending = true;
+ if (frame == 0) {
+ fPCAddress = fFrameAddress;
+ }
+ if (fFrameAddress.compareTo(PC_UNKNOWN) == 0) {
+ if (!fUpdatePending) {
+ fGotoFramePending = false;
+ retrieveFrameAddress(fTargetContext, fTargetFrame);
+ }
+ return;
+ }
+ AddressRangePosition pcPos = updatePCAnnotation();
+ if (pcPos == null && fFrameAddress.compareTo(BigInteger.ZERO) >= 0) {
+ pcPos = getPCPosition(fFrameAddress);
+ if (pcPos == null) {
+ gotoAddress(fFrameAddress);
+ return;
+ }
+ }
+ if (pcPos != null) {
+ if (frame == 0) {
+ addToPCHistory(pcPos);
+ }
+ fGotoFramePending = false;
+ if (fGotoAddressPending == fFrameAddress) {
+ fGotoAddressPending = PC_UNKNOWN;
+ }
+// if (DEBUG) System.out.println("pc updated "+getAddressText(address)); //$NON-NLS-1$
+ gotoPosition(pcPos, false);
+ updateVisibleArea();
+ } else {
+ // give up
+ fGotoFramePending = false;
+ fGotoAddressPending = PC_UNKNOWN;
+ }
+ doPendingPCUpdates();
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isActive()
+ */
+ public final boolean isActive() {
+ return fActive;
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isConnected()
+ */
+ public final boolean isConnected() {
+ return fDebugSessionId != null && fTargetContext != null;
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#isSuspended()
+ */
+ public final boolean isSuspended() {
+ return isConnected() && isSuspended(fTargetContext);
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#getTextViewer()
+ */
+ public final ISourceViewer getTextViewer() {
+ return fViewer;
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#addRulerContextMenuListener(org.eclipse.jface.action.IMenuListener)
+ */
+ public final void addRulerContextMenuListener(IMenuListener listener) {
+ fRulerContextMenuListeners.add(listener);
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart#removeRulerContextMenuListener(org.eclipse.jface.action.IMenuListener)
+ */
+ public final void removeRulerContextMenuListener(IMenuListener listener) {
+ fRulerContextMenuListeners.remove(listener);
+ }
+
+ private boolean isSuspended(IExecutionDMContext targetContext) {
+ return getRunControl().isSuspended(targetContext);
+ }
+
+ private IRunControl getRunControl() {
+ return getService(IRunControl.class);
+ }
+
+ /*default*/ DsfSession getSession() {
+ return DsfSession.getSession(fDebugSessionId);
+ }
+
+ /*default*/ <V> V getService(Class<V> serviceClass) {
+ if (fServicesTracker != null) {
+ return fServicesTracker.getService(serviceClass);
+ }
+ return null;
+ }
+
+ /*default*/ IFrameDMContext getTargetFrameContext() {
+ return fTargetFrameContext;
+ }
+
+ /**
+ * Schedule the retrieval of a module time stamp for the given address.
+ * Should return a <code>Long</code> object in case the value was computed,
+ * another object to be waited on if the retrieval is in progress, <code>null</code>
+ * if no time stamp could be retrieved.
+ *
+ * @param address
+ * @return Long, Object or <code>null</code>
+ */
+ synchronized Object retrieveModuleTimestamp(BigInteger address) {
+ // TLETODO [disassembly] retrieve and cache module time stamp
+ return null;
+ }
+
+ private void setFocusPosition(Position pcPos) {
+ if (fFocusPos != null) {
+ fDocument.removePosition(fFocusPos);
+ fFocusPos = null;
+ }
+ if (pcPos != null) {
+ fFocusPos = new Position(pcPos.offset, pcPos.length);
+ try {
+ fDocument.addPosition(fFocusPos);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ } else {
+ fFocusAddress = PC_UNKNOWN;
+ }
+ }
+
+ private void doPendingPCUpdates() {
+ if (fPendingPCUpdates.isEmpty()) {
+ return;
+ }
+ BigInteger pc;
+ do {
+ pc = fPendingPCUpdates.remove(0);
+ if (pc.compareTo(BigInteger.ZERO) >= 0) {
+ break;
+ }
+ } while (!fPendingPCUpdates.isEmpty());
+ gotoFrame(0, pc);
+ }
+
+ private void addToPCHistory(AddressRangePosition pcPos) {
+ if (DEBUG) System.out.println("addToPCHistory "+getAddressText(pcPos.fAddressOffset)); //$NON-NLS-1$
+ if (fPCHistorySizeMax <= 1) {
+ return;
+ }
+ AddressRangePosition first = null;
+ if (fPCHistory.size() > 0) {
+ first = fPCHistory.getFirst();
+ if (first.fAddressOffset == pcPos.fAddressOffset) {
+ if (first.offset != pcPos.offset || first.length != pcPos.length) {
+ fPCHistory.removeFirst();
+ fViewer.invalidateTextPresentation(first.offset, first.length);
+ } else {
+ return;
+ }
+ }
+ }
+ // clone and add
+ pcPos = new AddressRangePosition(pcPos.offset, pcPos.length, pcPos.fAddressOffset, BigInteger.ZERO);
+ fPCHistory.addFirst(pcPos);
+ try {
+ fDocument.addPosition(pcPos);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ // limit to max size
+ if (fPCHistory.size() > fPCHistorySizeMax) {
+ AddressRangePosition last = fPCHistory.removeLast();
+ fDocument.removePosition(last);
+ fViewer.invalidateTextPresentation(last.offset, last.length);
+ }
+ // redraw
+ for (Iterator<AddressRangePosition> it=fPCHistory.iterator(); it.hasNext();) {
+ AddressRangePosition pos = it.next();
+ fViewer.invalidateTextPresentation(pos.offset, pos.length);
+ }
+ }
+
+ /**
+ * Update current pc. If a pc update is currently under way, adds this
+ * address to a list of pending pc updates.
+ *
+ * @param pc Current pc address. -1 means retrieve pc from top frame, -2
+ * means target resumed
+ */
+ private void updatePC(BigInteger pc) {
+ if (!fPendingPCUpdates.isEmpty()) {
+ BigInteger last = fPendingPCUpdates.get(fPendingPCUpdates.size()-1);
+ if (last.compareTo(BigInteger.ZERO) < 0) {
+ fPendingPCUpdates.remove(fPendingPCUpdates.size()-1);
+ }
+ }
+ fPendingPCUpdates.add(pc);
+ if (fPendingPCUpdates.size() > fPCHistorySizeMax) {
+ if (!fActive) {
+ // if not active, we can savely remove
+ // the pc updates before the history range
+ fPendingPCUpdates.remove(0);
+ }
+ // we ignore the current goto frame request
+ // and continue with the pending updates
+ fGotoFramePending = false;
+ }
+ if (fActive) {
+ if (fGotoFramePending) {
+ if (!fUpdatePending) {
+ gotoFrame(0, fFrameAddress);
+ }
+ } else {
+ doPendingPCUpdates();
+ }
+ }
+ }
+
+ private AddressRangePosition updatePCAnnotation() {
+ if (fUpdatePending) {
+ fPCAnnotationUpdatePending = true;
+ return null;
+ }
+ AddressRangePosition pos;
+ if (fTargetFrame == 0) {
+ // clear secondary
+ updateAddressAnnotation(fSecondaryPCAnnotation, PC_UNKNOWN);
+ // set primary
+ pos = updateAddressAnnotation(fPCAnnotation, fPCAddress);
+ } else {
+ // clear primary
+ updateAddressAnnotation(fPCAnnotation, PC_UNKNOWN);
+ // set secondary
+ pos = updateAddressAnnotation(fSecondaryPCAnnotation, fFrameAddress);
+ }
+ fPCAnnotationUpdatePending = pos == null && fFrameAddress.compareTo(BigInteger.ZERO) >= 0;
+ return pos;
+ }
+
+ private void scheduleDoPending() {
+ if (!fUpdatePending && !fDoPendingPosted) {
+ fDoPendingPosted = true;
+ invokeLater(new Runnable() {
+ public void run() {
+ doPending();
+ fDoPendingPosted = false;
+ }
+ });
+ }
+ }
+
+ private void doPending() {
+ if (fViewer == null || fDocument == null) {
+ return;
+ }
+ if (fUpdateSourcePending) {
+ updateInvalidSource();
+ }
+ boolean sourceValid= fDocument.getInvalidSource().isEmpty();
+ if (sourceValid || fShowDisassembly) {
+ if (fGotoFramePending) {
+ gotoFrame(fTargetFrame, fFrameAddress);
+ }
+ }
+ if (sourceValid) {
+ if (fGotoAddressPending != PC_UNKNOWN) {
+ gotoAddress(fGotoAddressPending);
+ } else if (fGotoMarkerPending != null) {
+ gotoMarker(fGotoMarkerPending);
+ }
+ if (fPCAnnotationUpdatePending && !fGotoFramePending) {
+ updatePCAnnotation();
+ }
+ if (fUpdateTitlePending) {
+ updateTitle();
+ }
+ }
+ }
+
+ /**
+ * Safely run given runnable in a state when no update is pending.
+ * Delays execution by 10 ms if update is currently pending.
+ * @param doit
+ */
+ private void doScrollLocked(final Runnable doit) {
+ if (fViewer == null || fDebugSessionId == null) {
+ // disposed
+ return;
+ }
+ if (!fActive) {
+ // refresh all when becoming active again
+ fRefreshViewPending= false;
+ fRefreshAll = true;
+ return;
+ }
+ if (doit != null) {
+ fRunnableQueue.add(doit);
+ }
+ if (fUpdatePending) {
+ if (fRunnableQueue.size() == 1) {
+ Runnable doitlater = new Runnable() {
+ public void run() {
+ doScrollLocked(null);
+ }};
+ invokeLater(doitlater);
+ }
+ } else {
+ fUpdatePending = true;
+ lockScroller();
+ try {
+ ArrayList<Runnable> copy = new ArrayList<Runnable>(fRunnableQueue);
+ fRunnableQueue.clear();
+ for (Iterator<Runnable> iter = copy.iterator(); iter.hasNext();) {
+ Runnable doitnow = iter.next();
+ try {
+ doitnow.run();
+ } catch(Exception e) {
+ internalError(e);
+ }
+ }
+ } finally {
+ fUpdatePending = false;
+ unlockScroller();
+ doPending();
+ updateVisibleArea();
+ }
+ }
+ }
+
+ private void lockScroller() {
+ assert fScrollPos == null;
+ if (isOpcodeRulerVisible()) {
+ fRedrawControl = fViewer.getControl();
+ } else {
+ fRedrawControl = fViewer.getTextWidget();
+ }
+ fRedrawControl.setRedraw(false);
+ try {
+ int topOffset = fViewer.getTopIndexStartOffset();
+ int topIndex = fViewer.getTopIndex();
+ int bottomIndex = fViewer.getBottomIndex();
+ int bottomOffset = fViewer.getBottomIndexEndOffset();
+ int focusLine;
+ int focusOffset;
+ if (fFocusPos != null && fFocusPos.isDeleted) {
+ fFocusPos = null;
+ }
+ if (fFocusPos != null && fFocusPos.offset >= topOffset && fFocusPos.offset <= bottomOffset) {
+ focusOffset = fFocusPos.offset;
+ focusLine = fDocument.getLineOfOffset(focusOffset);
+ } else {
+ focusLine = Math.max(0, (topIndex + bottomIndex) / 2);
+ focusOffset = fDocument.getLineOffset(focusLine);
+ AddressRangePosition pos = fDocument.getDisassemblyPosition(focusOffset);
+ if (pos != null && !pos.fValid) {
+ // don't lock position of invalid range
+ focusOffset = pos.offset+pos.length;
+ focusLine = fDocument.getLineOfOffset(focusOffset);
+ }
+ }
+ fScrollPos = new Position(focusOffset);
+ fScrollLine = focusLine - topIndex;
+ fDocument.addPosition(fScrollPos);
+ } catch (BadLocationException e) {
+ // should not happen
+ internalError(e);
+ }
+ }
+
+ private void unlockScroller() {
+ try {
+ if (fScrollPos == null) {
+ return;
+ }
+ if (fScrollPos.isDeleted) {
+ fScrollPos.isDeleted = false;
+ if (fScrollPos.offset >= fDocument.getLength()) {
+ fScrollPos.offset = 0;
+ fScrollLine = 0;
+ }
+ }
+ if (fFocusPos != null && (fFocusPos.isDeleted || fFocusPos.length == 0)) {
+ if (fFocusAddress.compareTo(BigInteger.ZERO) >= 0) {
+ fGotoAddressPending = fFocusAddress;
+ setFocusPosition(getPositionOfAddress(fFocusAddress));
+ }
+ }
+ int topLine = fDocument.getLineOfOffset(fScrollPos.offset) - fScrollLine;
+ // limit text size
+ int lineCount = fDocument.getNumberOfLines();
+ if (lineCount > fgHighWaterMark*fBufferZone) {
+ int startLine = Math.max(0, topLine-fgLowWaterMark/2*fBufferZone);
+ int endLine = Math.min(lineCount-1, topLine+fgLowWaterMark/2*fBufferZone);
+ fDocument.deleteLineRange(endLine, lineCount-1);
+ fDocument.deleteLineRange(0, startLine);
+ }
+ int lineHeight = fViewer.getTextWidget().getLineHeight();
+ int topPixel = topLine * lineHeight;
+ if (Math.abs(fViewer.getTextWidget().getTopPixel() - topPixel) >= lineHeight) {
+ fViewer.setTopIndex(topLine);
+ }
+ } catch (BadLocationException e) {
+ // should not happen
+ internalError(e);
+ } finally {
+ if (fScrollPos != null && fDocument != null) {
+ fDocument.removePosition(fScrollPos);
+ fScrollPos = null;
+ }
+ if (fViewer != null) {
+ fRedrawControl.setRedraw(true);
+ getVerticalRuler().update();
+ getOverviewRuler().update();
+ }
+ }
+ }
+
+ private void insertSource(SourcePosition pos) {
+ if (!fShowSource) {
+ fDocument.insertSource(pos, "", pos.fLine, true); //$NON-NLS-1$
+ return;
+ }
+ SourceFileInfo fi = pos.fFileInfo;
+ BigInteger address = pos.fAddressOffset;
+ int lineNr = pos.fLine;
+ if (fi.fError != null) {
+ // handled below
+ } else if (fi.fValid) {
+// assert fi.fLinesNode.isValid();
+ Addr2Line a2l = fi.fAddr2Line[Addr2Line.hash(address, fi.fAddr2Line.length)];
+ while (a2l != null && !a2l.addr.equals(address))
+ a2l = a2l.next;
+ if (a2l != null) {
+ int first = a2l.first;
+ int line;
+ for (line = first; line <= a2l.last; ++line) {
+ if (!fi.fLine2Addr[line].equals(address)) {
+ if (line > first) {
+ String source = fi.getLines(first, line-1);
+ pos = fDocument.insertSource(pos, source, first, false);
+ }
+ first = line+1;
+ }
+ }
+ if (line > first) {
+ String source = fi.getLines(first, line-1);
+ fDocument.insertSource(pos, source, first, true);
+ if (source.length() == 0) {
+ fDocument.removeSourcePosition(pos);
+ }
+ } else if (first > a2l.first) {
+ fDocument.insertSource(pos, "", first, true); //$NON-NLS-1$
+ fDocument.removeSourcePosition(pos);
+ }
+ } else {
+ // no source at all
+ fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$
+ fDocument.removeSourcePosition(pos);
+ }
+ } else if (fi.fLinesNode == null) {
+ // TLETODO [disassembly] asynchronous line info
+ if (fi.fSource != null) {
+ fi.fError= new Error();
+ }
+ }
+ if (fi.fError != null && !pos.fValid) {
+ if (fi.fSource != null) {
+ if (fi.fSource != null && lineNr >= 0 && lineNr < fi.fSource.getNumberOfLines()) {
+ fi.fStartAddress = fi.fStartAddress.min(pos.fAddressOffset);
+ fi.fEndAddress = fi.fEndAddress.max(pos.fAddressOffset.add(pos.fAddressLength));
+ if (fi.fLine2Addr[lineNr] == null || fi.fLine2Addr[lineNr].compareTo(BigInteger.ZERO) < 0) {
+ fi.fLine2Addr[lineNr] = pos.fAddressOffset;
+ String sourceLine = fi.getLine(lineNr);
+ fDocument.insertSource(pos, sourceLine, lineNr, true);
+ } else if (fi.fLine2Addr[lineNr].compareTo(pos.fAddressOffset) > 0) {
+ SourcePosition oldPos = fDocument.getSourcePosition(fi.fLine2Addr[lineNr]);
+ if (oldPos != null) {
+ try {
+ fDocument.replace(oldPos, oldPos.length, null);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ fDocument.removeSourcePosition(oldPos);
+ }
+ fi.fLine2Addr[lineNr] = pos.fAddressOffset;
+ String sourceLine = fi.getLine(lineNr);
+ fDocument.insertSource(pos, sourceLine, lineNr, true);
+ } else if (fi.fLine2Addr[lineNr].equals(pos.fAddressOffset)) {
+ String sourceLine = fi.getLine(lineNr);
+ fDocument.insertSource(pos, sourceLine, lineNr, true);
+ } else {
+ fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$
+ fDocument.removeSourcePosition(pos);
+ }
+ }
+ } else {
+ // no source at all
+ fDocument.insertSource(pos, "", lineNr, true); //$NON-NLS-1$
+ fDocument.removeSourcePosition(pos);
+ }
+ }
+ }
+
+ private void updateTitle() {
+ if (fDebugSessionId == null) {
+ String descr = DisassemblyMessages.Disassembly_message_notConnected;
+ String title = getConfigurationElement().getAttribute("name"); //$NON-NLS-1$
+ setPartName(title);
+ setContentDescription(descr);
+ setTitleToolTip(title);
+ } else {
+ // TLETODO Proper content description
+ setContentDescription(""); //$NON-NLS-1$
+ }
+ }
+
+ private boolean isDissemblyMixedModeOn() {
+ // TLETODO [disassembly] mixed mode on/off
+ return true;
+ }
+
+ /**
+ * Close this part
+ */
+ protected abstract void closePart();
+
+ /*
+ * @see org.eclipse.jface.text.ITextPresentationListener#applyTextPresentation(org.eclipse.jface.text.TextPresentation)
+ */
+ @SuppressWarnings("unchecked")
+ public void applyTextPresentation(TextPresentation textPresentation) {
+ IRegion coverage = textPresentation.getExtent();
+ if (coverage == null) {
+ coverage= new Region(0, fDocument.getLength());
+ }
+ int startOffset = coverage.getOffset();
+ int length = coverage.getLength();
+ int endOffset = startOffset + length;
+ Iterator<Position> it;
+ try {
+ // make sure we start with first overlapping position
+ AddressRangePosition pos = fDocument.getModelPosition(startOffset);
+ assert pos != null;
+ if (pos == null) {
+ return;
+ }
+ it = fDocument.getPositionIterator(DisassemblyDocument.CATEGORY_MODEL, pos.offset);
+ } catch (BadPositionCategoryException e) {
+ return;
+ } catch (BadLocationException e) {
+ return;
+ }
+ ArrayList<StyleRange> styleRanges = new ArrayList<StyleRange>();
+ while(it.hasNext()) {
+ AddressRangePosition pos = (AddressRangePosition)it.next();
+ if (pos.offset >= endOffset) {
+ break;
+ }
+ if (pos.offset+pos.length <= startOffset) {
+ continue;
+ }
+ if (pos.fValid && pos.length > 0) {
+ if (pos instanceof DisassemblyPosition) {
+ DisassemblyPosition disPos = (DisassemblyPosition)pos;
+ styleRanges.add(new StyleRange(pos.offset, disPos.length, fInstructionColor, null, SWT.NULL));
+ } else if (pos instanceof ErrorPosition) {
+ styleRanges.add(new StyleRange(pos.offset, pos.length, fErrorColor, null, SWT.NULL));
+ } else if (pos instanceof LabelPosition) {
+ styleRanges.add(new StyleRange(pos.offset, pos.length, fLabelColor, null, SWT.BOLD));
+ } else if (pos instanceof SourcePosition) {
+ SourcePosition srcPos = (SourcePosition)pos;
+ TextPresentation presentation = null;
+ if (srcPos.fFileInfo.fSource != null) {
+ presentation = srcPos.fFileInfo.getPresentation(srcPos.fFileInfo.getRegion(srcPos.fLine, pos.length));
+ }
+ if (presentation != null) {
+ // clip result window to coverage
+ int start = Math.max(startOffset, srcPos.offset);
+ int end = Math.min(endOffset, srcPos.offset + srcPos.length);
+ int srcOffset = srcPos.fFileInfo.getLineOffset(srcPos.fLine);
+ int clipOffset = start - srcPos.offset;
+ presentation.setResultWindow(new Region(srcOffset + clipOffset, end-start));
+ for (Iterator<StyleRange> iter = presentation.getNonDefaultStyleRangeIterator(); iter.hasNext();) {
+ StyleRange styleRange = iter.next();
+ styleRange.start += srcPos.offset + clipOffset;
+ styleRanges.add(styleRange);
+ }
+ } else {
+ styleRanges.add(new StyleRange(pos.offset, pos.length, fSourceColor, null, SWT.NULL));
+ }
+ }
+ }
+ }
+ if (styleRanges.size() > 0) {
+ for (Iterator<StyleRange> iter = styleRanges.iterator(); iter.hasNext();) {
+ textPresentation.addStyleRange(iter.next());
+ }
+ }
+ // update pc history trail
+ if (fPCHistory.size() > 1) {
+ HSL hsv = new HSL(fPCAnnotationRGB);
+ double luminanceStep = (1-hsv.luminance)/(fPCHistorySizeMax+1);
+ hsv.luminance = 1 - luminanceStep * (fPCHistorySizeMax - fPCHistory.size());
+ for (ListIterator<AddressRangePosition> listIt = fPCHistory.listIterator(fPCHistory.size()); listIt.hasPrevious();) {
+ AddressRangePosition pcPos = listIt.previous();
+ hsv.luminance -= luminanceStep;
+ if (pcPos.isDeleted) {
+ listIt.remove();
+ continue;
+ }
+ if (!pcPos.fValid) {
+ continue;
+ }
+ if (pcPos.overlapsWith(startOffset, length)) {
+ RGB rgb = hsv.toRGB();
+ Color pcColor = getSharedColors().getColor(rgb);
+ Color textColor = null;
+ // experimental: if color is dark, use white (background) as text color
+// Color textColor = hsv.luminance < 0.7 ? fViewer.getTextWidget().getBackground() : null;
+ textPresentation.mergeStyleRange(new StyleRange(pcPos.offset, pcPos.length, textColor, pcColor));
+ }
+ }
+ }
+ }
+
+
+ private IBreakpoint insertBreakpoint(int line, boolean edit) throws CoreException {
+ SourcePosition srcPos = null;
+ try {
+ int lineOffset = fDocument.getLineOffset(line);
+ srcPos = fDocument.getSourcePosition(lineOffset);
+ } catch (BadLocationException e) {
+ // should not happen, but its safe to ignore anyway
+ }
+ boolean lineBreakpoint = srcPos != null && srcPos.length > 0;
+
+ IResource resource;
+ ICBreakpoint bp;
+
+ if (lineBreakpoint) {
+ SourceFileInfo srcInfo = srcPos.fFileInfo;
+ String filePath = null;
+ resource = (IResource)srcInfo.fFile.getAdapter(IResource.class);
+ if (resource != null) {
+ final IPath location= resource.getLocation();
+ if (location == null) {
+ return null;
+ }
+ filePath = location.toOSString();
+ } else {
+ resource = ResourcesPlugin.getWorkspace().getRoot();
+ filePath = srcInfo.fFile.getFullPath().toOSString();
+ }
+ BigInteger address = srcPos.fAddressOffset;
+ AddressRangePosition pos = fDocument.getDisassemblyPosition(address);
+ int srcLine = -1;
+ if (pos instanceof DisassemblyPosition) {
+ srcLine = ((DisassemblyPosition)pos).getLine();
+ }
+ bp= CDIDebugModel.createLineBreakpoint(filePath, resource, srcLine + 1, true, 0, "", true); //$NON-NLS-1$
+ } else {
+ resource = ResourcesPlugin.getWorkspace().getRoot();
+ BigInteger address = getAddressOfLine(line);
+ bp= CDIDebugModel.createAddressBreakpoint(null, null, resource, new Addr64(address), true, 0, "", true); //$NON-NLS-1$
+ }
+
+ return bp;
+ }
+
+ private AddressRangePosition insertSource(AddressRangePosition pos, BigInteger address, final String file, int lineNr) {
+ Object sourceElement = null;
+ if (fFile2Storage.containsKey(file)) {
+ sourceElement = fFile2Storage.get(file);
+ } else {
+ final ISourceLookup lookup= getService(ISourceLookup.class);
+ final ISourceLookupDMContext ctx= DMContexts.getAncestorOfType(fTargetContext, ISourceLookupDMContext.class);
+ final DsfExecutor executor= getSession().getExecutor();
+ Query<Object> query= new Query<Object>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ final DataRequestMonitor<Object> request= new DataRequestMonitor<Object>(executor, rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData());
+ rm.done();
+ }
+ };
+ lookup.getSource(ctx, file, request);
+ }
+ };
+ try {
+ getSession().getExecutor().execute(query);
+ sourceElement= query.get();
+ } catch (InterruptedException exc) {
+ internalError(exc);
+ } catch (ExecutionException exc) {
+ internalError(exc);
+ }
+ if (sourceElement instanceof File) {
+ sourceElement = new LocalFileStorage((File)sourceElement);
+ }
+ if (sourceElement instanceof IStorage) {
+ fFile2Storage.put(file, sourceElement);
+ } else {
+ fFile2Storage.put(file, null);
+ logWarning(DisassemblyMessages.Disassembly_log_error_locateFile+file, null);
+ }
+ }
+ if (sourceElement instanceof IStorage) {
+ SourceFileInfo fi = fDocument.getSourceInfo((IStorage)sourceElement);
+ if (fi == null) {
+ IStorage storage = (IStorage)sourceElement;
+ Display display = getSite().getShell().getDisplay();
+ Runnable done = new SourceColorerJob(display, storage, this);
+ fi = fDocument.createSourceInfo(file, storage, done);
+ EditionFinderJob editionJob = null;
+ if (storage instanceof IFile) {
+ editionJob = new EditionFinderJob(fi, address, this);
+ editionJob.schedule();
+ }
+ fi.fReadingJob.schedule();
+ }
+ pos = fDocument.insertInvalidSource(pos, address, fi, lineNr);
+ }
+ return pos;
+ }
+
+ private void disassemblyModeChanged(boolean isDisassemblyOn) {
+ if (fShowDisassembly == isDisassemblyOn) {
+ return;
+ }
+ if (fShowDisassembly && !fSourceOnlyMode) {
+ // if not in source-only mode, do not update if disassembly mode is disabled
+ return;
+ }
+ fShowDisassembly = isDisassemblyOn;
+ if (!fShowDisassembly) {
+ sourceModeChanged(true);
+ }
+ fActionToggleSource.update();
+ Runnable doit = new Runnable() {
+ public void run() {
+ fDocument.invalidateDisassemblyWithSource(!fShowDisassembly);
+ fGotoFramePending = true;
+ }};
+ doScrollLocked(doit);
+ }
+
+ /**
+ * Turn on/off source mode.
+ * @param isSourceModeOn
+ */
+ private void sourceModeChanged(boolean isSourceModeOn) {
+ if (fShowSource == isSourceModeOn) {
+ return;
+ }
+ fShowSource = isSourceModeOn;
+ fActionToggleSource.update();
+ fDocument.invalidateSource();
+ if (!fShowSource && !fShowDisassembly) {
+ disassemblyModeChanged(true);
+ } else {
+ fPCAnnotationUpdatePending = true;
+ updateInvalidSource();
+ }
+ }
+
+ public static BigInteger decodeAddress(String string) {
+ if (string.startsWith("0x")) { //$NON-NLS-1$
+ return new BigInteger(string.substring(2), 16);
+ }
+ return new BigInteger(string);
+ }
+
+ private static String getAddressText(BigInteger address) {
+ if (address == null) {
+ return "<null>"; //$NON-NLS-1$
+ }
+ if (address.compareTo(BigInteger.ZERO) < 0) {
+ return address.toString();
+ }
+ String hex = address.toString(16);
+ return "0x" + "0000000000000000".substring(hex.length() + (address.bitLength() <= 32 ? 8 : 0)) + hex; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ static void internalError(Throwable e) {
+ if (DEBUG) {
+ System.err.println("Disassembly: Internal error"); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java
new file mode 100644
index 00000000000..83015f86bef
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyRulerColumn.java
@@ -0,0 +1,985 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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
+ * Anton Leherbauer (Wind River Systems)
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextListener;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITextViewerExtension;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.IViewportListener;
+import org.eclipse.jface.text.TextEvent;
+import org.eclipse.jface.text.source.CompositeRuler;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IVerticalRulerColumn;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+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.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Vertical ruler column for use with disassembly parts.
+ * <p>
+ * Derived from {@link org.eclipse.jface.text.source.LineNumberRulerColumn}.
+ * </p>
+ */
+public class DisassemblyRulerColumn implements IVerticalRulerColumn {
+ protected final static String DOTS = "......................................................................"; //$NON-NLS-1$
+ protected final static String SPACES = " "; //$NON-NLS-1$
+
+ /**
+ * Internal listener class.
+ */
+ class InternalListener implements IViewportListener, ITextListener, ISelectionChangedListener {
+
+ /*
+ * @see IViewportListener#viewportChanged(int)
+ */
+ public void viewportChanged(int verticalPosition) {
+ if (verticalPosition != fScrollPos)
+ redraw();
+ }
+
+ /*
+ * @see ITextListener#textChanged(TextEvent)
+ */
+ public void textChanged(TextEvent event) {
+
+ if (updateNumberOfDigits()) {
+ computeIndentations();
+ layout(event.getViewerRedrawState());
+ return;
+ }
+
+ if (!event.getViewerRedrawState())
+ return;
+
+ if (fSensitiveToTextChanges || event.getDocumentEvent() == null)
+ postRedraw();
+
+ }
+
+ /*
+ * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
+ */
+ public void selectionChanged(SelectionChangedEvent event) {
+ postRedraw();
+ }
+ }
+
+ /**
+ * Handles all the mouse interaction in this line number ruler column.
+ */
+ class MouseHandler implements MouseListener, MouseMoveListener, MouseTrackListener {
+
+ /** The cached view port size */
+ private int fCachedViewportSize;
+ /** The area of the line at which line selection started */
+ private IRegion fStartLine;
+ /** The number of the line at which line selection started */
+ private int fStartLineNumber;
+ /** The auto scroll direction */
+ private int fAutoScrollDirection;
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseUp(MouseEvent event) {
+ // see bug 45700
+ if (event.button == 1) {
+ stopSelecting();
+ stopAutoScroll();
+ postRedraw();
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDown(MouseEvent event) {
+ fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
+ // see bug 45700
+ if (event.button == 1) {
+ startSelecting();
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent event) {
+ fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
+ stopSelecting();
+ stopAutoScroll();
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseMove(MouseEvent event) {
+ if (!autoScroll(event)) {
+ int newLine = fParentRuler.toDocumentLineNumber(event.y);
+ expandSelection(newLine);
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseEnter(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseEnter(MouseEvent event) {
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseExit(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseExit(MouseEvent event) {
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseTrackListener#mouseHover(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseHover(MouseEvent event) {
+ }
+
+ /**
+ * Called when line drag selection started. Adds mouse move and track
+ * listeners to this column's control.
+ */
+ private void startSelecting() {
+ try {
+
+ // select line
+ IDocument document = fCachedTextViewer.getDocument();
+ fStartLineNumber = fParentRuler.getLineOfLastMouseButtonActivity();
+ fStartLine = document.getLineInformation(fStartLineNumber);
+ fCachedTextViewer.setSelectedRange(fStartLine.getOffset(), fStartLine.getLength());
+ fCachedViewportSize = getVisibleLinesInViewport();
+
+ // prepare for drag selection
+ fCanvas.addMouseMoveListener(this);
+ fCanvas.addMouseTrackListener(this);
+
+ } catch (BadLocationException x) {
+ }
+ }
+
+ /**
+ * Called when line drag selection stopped. Removes all previously
+ * installed listeners from this column's control.
+ */
+ private void stopSelecting() {
+ // drag selection stopped
+ fCanvas.removeMouseMoveListener(this);
+ fCanvas.removeMouseTrackListener(this);
+ }
+
+ /**
+ * Expands the line selection from the remembered start line to the
+ * given line.
+ *
+ * @param lineNumber
+ * the line to which to expand the selection
+ */
+ private void expandSelection(int lineNumber) {
+ try {
+
+ IDocument document = fCachedTextViewer.getDocument();
+ IRegion lineInfo = document.getLineInformation(lineNumber);
+
+ int start = Math.min(fStartLine.getOffset(), lineInfo.getOffset());
+ int end = Math.max(fStartLine.getOffset() + fStartLine.getLength(), lineInfo.getOffset()
+ + lineInfo.getLength());
+
+ if (lineNumber < fStartLineNumber)
+ fCachedTextViewer.setSelectedRange(end, start - end);
+ else
+ fCachedTextViewer.setSelectedRange(start, end - start);
+
+ } catch (BadLocationException x) {
+ }
+ }
+
+ /**
+ * Called when auto scrolling stopped. Clears the auto scroll direction.
+ */
+ private void stopAutoScroll() {
+ fAutoScrollDirection = SWT.NULL;
+ }
+
+ /**
+ * Called on drag selection.
+ *
+ * @param event
+ * the mouse event caught by the mouse move listener
+ * @return <code>true</code> if scrolling happened, <code>false</code>
+ * otherwise
+ */
+ private boolean autoScroll(MouseEvent event) {
+ Rectangle area = fCanvas.getClientArea();
+
+ if (event.y > area.height) {
+ autoScroll(SWT.DOWN);
+ return true;
+ }
+
+ if (event.y < 0) {
+ autoScroll(SWT.UP);
+ return true;
+ }
+
+ stopAutoScroll();
+ return false;
+ }
+
+ /**
+ * Scrolls the viewer into the given direction.
+ *
+ * @param direction
+ * the scroll direction
+ */
+ private void autoScroll(int direction) {
+
+ if (fAutoScrollDirection == direction)
+ return;
+
+ final int TIMER_INTERVAL = 5;
+ final Display display = fCanvas.getDisplay();
+ Runnable timer = null;
+ switch (direction) {
+ case SWT.UP:
+ timer = new Runnable() {
+ public void run() {
+ if (fAutoScrollDirection == SWT.UP) {
+ int top = getInclusiveTopIndex();
+ if (top > 0) {
+ fCachedTextViewer.setTopIndex(top - 1);
+ expandSelection(top - 1);
+ display.timerExec(TIMER_INTERVAL, this);
+ }
+ }
+ }
+ };
+ break;
+ case SWT.DOWN:
+ timer = new Runnable() {
+ public void run() {
+ if (fAutoScrollDirection == SWT.DOWN) {
+ int top = getInclusiveTopIndex();
+ fCachedTextViewer.setTopIndex(top + 1);
+ expandSelection(top + 1 + fCachedViewportSize);
+ display.timerExec(TIMER_INTERVAL, this);
+ }
+ }
+ };
+ break;
+ }
+
+ if (timer != null) {
+ fAutoScrollDirection = direction;
+ display.timerExec(TIMER_INTERVAL, timer);
+ }
+ }
+
+ /**
+ * Returns the viewer's first visible line, even if only partially
+ * visible.
+ *
+ * @return the viewer's first visible line
+ */
+ private int getInclusiveTopIndex() {
+ if (fCachedTextWidget != null && !fCachedTextWidget.isDisposed()) {
+ int top = fCachedTextViewer.getTopIndex();
+ if ((fCachedTextWidget.getTopPixel() % fCachedTextWidget.getLineHeight()) != 0)
+ --top;
+ return top;
+ }
+ return -1;
+ }
+ }
+
+ /** This column's parent ruler */
+ private CompositeRuler fParentRuler;
+ /** Cached text viewer */
+ private ITextViewer fCachedTextViewer;
+ /** Cached text widget */
+ private StyledText fCachedTextWidget;
+ /** The columns canvas */
+ private Canvas fCanvas;
+ /** Cache for the actual scroll position in pixels */
+ private int fScrollPos;
+ /** The drawable for double buffering */
+ private Image fBuffer;
+ /** The internal listener */
+ private InternalListener fInternalListener = new InternalListener();
+ /** The font of this column */
+ private Font fFont;
+ /** The indentation cache */
+ private int[] fIndentation;
+ /** Indicates whether this column reacts on text change events */
+ private boolean fSensitiveToTextChanges = false;
+ /** The foreground color */
+ private Color fForeground;
+ /** The background color */
+ private Color fBackground;
+ /** Cached number of displayed digits */
+ private int fCachedNumberOfDigits = -1;
+ /** Flag indicating whether a relayout is required */
+ private boolean fRelayoutRequired = false;
+ /**
+ * Redraw runnable lock
+ */
+ private Object fRunnableLock = new Object();
+ /**
+ * Redraw runnable state
+ */
+ private boolean fIsRunnablePosted = false;
+ /**
+ * Redraw runnable
+ */
+ private Runnable fRunnable = new Runnable() {
+ public void run() {
+ synchronized (fRunnableLock) {
+ fIsRunnablePosted = false;
+ }
+ redraw();
+ }
+ };
+ private boolean fAlignRight;
+ private boolean fPaintStyleBackground;
+ private boolean fPaintSelectionBackground;
+
+ /**
+ * Constructs a new vertical ruler column.
+ *
+ */
+ public DisassemblyRulerColumn() {
+ this(SWT.LEFT);
+ // default constructor
+ }
+
+ public DisassemblyRulerColumn(int align) {
+ this(align, true, false);
+ }
+
+ public DisassemblyRulerColumn(int align, boolean paintSelection, boolean paintStyle) {
+ fAlignRight = (align & SWT.RIGHT) != 0;
+ fPaintSelectionBackground = paintSelection;
+ fPaintStyleBackground = paintStyle;
+ }
+
+ /**
+ * Sets the foreground color of this column.
+ *
+ * @param foreground
+ * the foreground color
+ */
+ public void setForeground(Color foreground) {
+ fForeground = foreground;
+ }
+
+ /**
+ * Returns the foreground color being used to print the line numbers.
+ *
+ * @return the configured foreground color
+ */
+ protected Color getForeground() {
+ return fForeground;
+ }
+
+ /**
+ * Sets the background color of this column.
+ *
+ * @param background
+ * the background color
+ */
+ public void setBackground(Color background) {
+ fBackground = background;
+ if (fCanvas != null && !fCanvas.isDisposed())
+ fCanvas.setBackground(getBackground(fCanvas.getDisplay()));
+ }
+
+ /**
+ * Returns the System background color for list widgets.
+ *
+ * @param display
+ * the display
+ * @return the System background color for list widgets
+ */
+ protected Color getBackground(Display display) {
+ if (fBackground == null)
+ return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+ return fBackground;
+ }
+
+ /*
+ * @see IVerticalRulerColumn#getControl()
+ */
+ public Control getControl() {
+ return fCanvas;
+ }
+
+ /*
+ * @see IVerticalRuleColumnr#getWidth
+ */
+ public int getWidth() {
+ return fIndentation[0];
+ }
+
+ /**
+ * Computes the number of digits to be displayed. Returns <code>true</code>
+ * if the number of digits changed compared to the previous call of this
+ * method. If the method is called for the first time, the return value is
+ * also <code>true</code>.
+ *
+ * @return whether the number of digits has been changed
+ */
+ protected boolean updateNumberOfDigits() {
+ if (fCachedTextViewer == null)
+ return false;
+
+ int digits = computeNumberOfCharacters();
+
+ if (fCachedNumberOfDigits != digits) {
+ fCachedNumberOfDigits = digits;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Does the real computation of the number of characters. The default
+ * implementation computes the number of digits for the line number.
+ * Subclasses may override this method if they need extra space on the ruler.
+ *
+ * @return the number of characters to be displayed on the ruler.
+ */
+ protected int computeNumberOfCharacters() {
+ IDocument document = fCachedTextViewer.getDocument();
+ int lines= document == null ? 0 : document.getNumberOfLines();
+
+ int digits= 2;
+ while (lines > Math.pow(10, digits) - 1) {
+ ++digits;
+ }
+ return digits;
+ }
+
+ /**
+ * Layouts the enclosing viewer to adapt the layout to changes of the size
+ * of the individual components.
+ *
+ * @param redraw
+ * <code>true</code> if this column can be redrawn
+ */
+ protected void layout(boolean redraw) {
+ if (!redraw) {
+ fRelayoutRequired= true;
+ return;
+ }
+
+ fRelayoutRequired= false;
+ if (fCachedTextViewer instanceof ITextViewerExtension) {
+ ITextViewerExtension extension= (ITextViewerExtension) fCachedTextViewer;
+ Control control= extension.getControl();
+ if (control instanceof Composite && !control.isDisposed()) {
+ Composite composite= (Composite) control;
+ composite.layout(true);
+ }
+ }
+ }
+
+ /**
+ * Computes the indentations for the given font and stores them in
+ * <code>fIndentation</code>.
+ */
+ protected void computeIndentations() {
+ if (fCanvas == null)
+ return;
+
+ GC gc= new GC(fCanvas);
+ try {
+
+ gc.setFont(fCanvas.getFont());
+
+ fIndentation= new int[fCachedNumberOfDigits + 1];
+ char[] digitStr= new char[fCachedNumberOfDigits + 1];
+ Arrays.fill(digitStr, '9');
+ Point p= gc.stringExtent(new String(digitStr, 0, fCachedNumberOfDigits + 1));
+ fIndentation[0]= p.x;
+
+ for (int i= 1; i <= fCachedNumberOfDigits; i++) {
+ p= gc.stringExtent(new String(digitStr, 0, i));
+ fIndentation[i]= fIndentation[0] - p.x;
+ }
+
+ } finally {
+ gc.dispose();
+ }
+ }
+
+ /*
+ * @see IVerticalRulerColumn#createControl(CompositeRuler, Composite)
+ */
+ public Control createControl(CompositeRuler parentRuler, Composite parentControl) {
+
+ fParentRuler= parentRuler;
+ fCachedTextViewer= parentRuler.getTextViewer();
+ fCachedTextWidget= fCachedTextViewer.getTextWidget();
+
+ fCanvas= new Canvas(parentControl, SWT.NONE);
+ fCanvas.setBackground(getBackground(fCanvas.getDisplay()));
+ fCanvas.setForeground(fForeground);
+
+ fCanvas.addPaintListener(new PaintListener() {
+ public void paintControl(PaintEvent event) {
+ if (fCachedTextViewer != null)
+ doubleBufferPaint(event.gc);
+ }
+ });
+
+ fCanvas.addDisposeListener(new DisposeListener() {
+ public void widgetDisposed(DisposeEvent e) {
+ handleDispose();
+ fCachedTextViewer= null;
+ fCachedTextWidget= null;
+ }
+ });
+
+ fCanvas.addMouseListener(new MouseHandler());
+
+ if (fCachedTextViewer != null) {
+
+ fCachedTextViewer.addViewportListener(fInternalListener);
+ fCachedTextViewer.addTextListener(fInternalListener);
+ fCachedTextViewer.getSelectionProvider().addSelectionChangedListener(fInternalListener);
+
+ if (fFont == null) {
+ if (fCachedTextWidget != null && !fCachedTextWidget.isDisposed())
+ fFont= fCachedTextWidget.getFont();
+ }
+ }
+
+ if (fFont != null)
+ fCanvas.setFont(fFont);
+
+ updateNumberOfDigits();
+ computeIndentations();
+ return fCanvas;
+ }
+
+ /**
+ * Disposes the column's resources.
+ */
+ protected void handleDispose() {
+
+ if (fCachedTextViewer != null) {
+ fCachedTextViewer.removeViewportListener(fInternalListener);
+ fCachedTextViewer.removeTextListener(fInternalListener);
+ fCachedTextViewer.getSelectionProvider().removeSelectionChangedListener(fInternalListener);
+ }
+
+ if (fBuffer != null) {
+ fBuffer.dispose();
+ fBuffer= null;
+ }
+ }
+
+ /**
+ * Double buffer drawing.
+ *
+ * @param dest
+ * the gc to draw into
+ */
+ private void doubleBufferPaint(GC dest) {
+
+ Point size= fCanvas.getSize();
+
+ if (size.x <= 0 || size.y <= 0)
+ return;
+
+ if (fBuffer != null) {
+ Rectangle r= fBuffer.getBounds();
+ if (r.width != size.x || r.height != size.y) {
+ fBuffer.dispose();
+ fBuffer= null;
+ }
+ }
+ if (fBuffer == null)
+ fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y);
+
+ GC gc= new GC(fBuffer);
+ gc.setFont(fCanvas.getFont());
+ if (fForeground != null)
+ gc.setForeground(fForeground);
+
+ try {
+ gc.setBackground(getBackground(fCanvas.getDisplay()));
+ gc.fillRectangle(0, 0, size.x, size.y);
+
+ if (fCachedTextViewer instanceof ITextViewerExtension5)
+ doPaint1(gc);
+ else
+ doPaint(gc);
+
+ } finally {
+ gc.dispose();
+ }
+
+ dest.drawImage(fBuffer, 0, 0);
+ }
+
+ /**
+ * Returns the viewport height in lines.
+ *
+ * @return the viewport height in lines
+ */
+ protected int getVisibleLinesInViewport() {
+ Rectangle clArea= fCachedTextWidget.getClientArea();
+ return clArea.height / fCachedTextWidget.getLineHeight();
+ }
+
+ /**
+ * Draws the ruler column.
+ *
+ * @param gc
+ * the gc to draw into
+ */
+ private void doPaint(GC gc) {
+
+ if (fCachedTextViewer == null)
+ return;
+
+ if (fCachedTextWidget == null)
+ return;
+
+ int firstLine= 0;
+
+ int topLine= fCachedTextWidget.getTopIndex();
+ fScrollPos= fCachedTextWidget.getTopPixel();
+ int lineheight= fCachedTextWidget.getLineHeight();
+ int partialLineHidden= fScrollPos % lineheight;
+
+ if (partialLineHidden > 0 && topLine > 0) // widgetTopLine shows the
+ // first fully visible line
+ --topLine;
+
+ int bottomLine;
+
+ try {
+
+ IRegion region= fCachedTextViewer.getVisibleRegion();
+ IDocument doc= fCachedTextViewer.getDocument();
+
+ if (doc == null)
+ return;
+
+ firstLine= doc.getLineOfOffset(region.getOffset());
+ if (firstLine > topLine)
+ topLine= firstLine;
+
+ bottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength());
+
+ } catch (BadLocationException x) {
+ return;
+ }
+
+ fSensitiveToTextChanges= bottomLine - topLine < getVisibleLinesInViewport();
+
+ int baselineBias= getBaselineBias(gc);
+
+ int topInset= fCachedTextViewer.getTopInset();
+ int y= topInset - partialLineHidden;
+ Point canvasSize= fCanvas.getSize();
+ Point selection= fCachedTextWidget.getSelection();
+ boolean selectedLine= false;
+ Color defaultForeground= gc.getForeground();
+ Color defaultBackground= gc.getBackground();
+
+ for (int line= topLine; y < canvasSize.y && line <= bottomLine; line++, y += lineheight) {
+ int widgetOffset= fCachedTextWidget.getOffsetAtLine(line);
+ if (fPaintSelectionBackground && widgetOffset >= selection.x && widgetOffset < selection.y) {
+ if (!selectedLine) {
+ selectedLine= true;
+ gc.setForeground(fCachedTextWidget.getSelectionForeground());
+ gc.setBackground(fCachedTextWidget.getSelectionBackground());
+ }
+ } else if (selectedLine) {
+ selectedLine= false;
+ gc.setForeground(defaultForeground);
+ gc.setBackground(defaultBackground);
+ }
+ if (selectedLine) {
+ gc.fillRectangle(0, y, canvasSize.x, lineheight);
+ } else if (fPaintStyleBackground && widgetOffset >= 0 && widgetOffset < fCachedTextWidget.getCharCount()) {
+ StyleRange style= fCachedTextWidget.getStyleRangeAtOffset(widgetOffset);
+ if (style != null && style.background != null) {
+ gc.setBackground(style.background);
+ gc.fillRectangle(0, y + baselineBias, canvasSize.x, lineheight - baselineBias);
+ gc.setBackground(defaultBackground);
+ }
+ }
+ paintLine(line, y, lineheight, gc, fCachedTextWidget.getDisplay());
+ String s= createDisplayString(line);
+ int indentation= fAlignRight ? fIndentation[s.length()] : 0;
+ gc.drawString(s, indentation, y + baselineBias, true);
+ }
+ }
+
+ /**
+ * Computes the string to be printed for <code>line</code>. The default
+ * implementation returns <code>Integer.toString(line + 1)</code>.
+ *
+ * @param line
+ * the line number for which the string is generated
+ * @return the string to be printed on the ruler column for <code>line</code>
+ */
+ String createDisplayString(int line) {
+ return Integer.toString(line + 1);
+ }
+
+ /**
+ * Draws the ruler column. Uses <code>ITextViewerExtension5</code> for the
+ * implementation. Will replace <code>doPinat(GC)</code>.
+ *
+ * @param gc
+ * the gc to draw into
+ */
+ private void doPaint1(GC gc) {
+
+ if (fCachedTextViewer == null)
+ return;
+
+ ITextViewerExtension5 extension= (ITextViewerExtension5) fCachedTextViewer;
+
+ int widgetTopLine= fCachedTextWidget.getTopIndex();
+ fScrollPos= fCachedTextWidget.getTopPixel();
+ int lineheight= fCachedTextWidget.getLineHeight();
+ int partialLineHidden= fScrollPos % lineheight;
+
+ if (partialLineHidden > 0 && widgetTopLine > 0) // widgetTopLine shows
+ // the first fully
+ // visible line
+ --widgetTopLine;
+
+ int modelTopLine= extension.widgetLine2ModelLine(widgetTopLine);
+ int modelBottomLine= fCachedTextViewer.getBottomIndex();
+ if (modelBottomLine >= 0)
+ ++modelBottomLine;
+
+ try {
+
+ IRegion region= extension.getModelCoverage();
+ IDocument doc= fCachedTextViewer.getDocument();
+
+ if (doc == null)
+ return;
+
+ int coverageTopLine= doc.getLineOfOffset(region.getOffset());
+ if (coverageTopLine > modelTopLine || modelTopLine == -1)
+ modelTopLine= coverageTopLine;
+
+ int coverageBottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength());
+ if (coverageBottomLine < modelBottomLine || modelBottomLine == -1)
+ modelBottomLine= coverageBottomLine;
+
+ } catch (BadLocationException x) {
+ return;
+ }
+
+ fSensitiveToTextChanges= modelBottomLine - modelTopLine < getVisibleLinesInViewport();
+
+ int baselineBias= getBaselineBias(gc);
+
+ int topInset= fCachedTextViewer.getTopInset();
+ int y= topInset - partialLineHidden;
+ Point canvasSize= fCanvas.getSize();
+ Point selection= fCachedTextWidget.getSelection();
+ boolean selectedLine= false;
+ Color defaultForeground= gc.getForeground();
+ Color defaultBackground= gc.getBackground();
+
+ for (int modelLine= modelTopLine; y < canvasSize.y && modelLine <= modelBottomLine; modelLine++) {
+
+ // don't draw hidden (e.g. folded) lines
+ int widgetLine= extension.modelLine2WidgetLine(modelLine);
+ if (widgetLine == -1)
+ continue;
+ int widgetOffset= fCachedTextWidget.getOffsetAtLine(widgetLine);
+ if (fPaintSelectionBackground && widgetOffset >= selection.x && widgetOffset < selection.y) {
+ if (!selectedLine) {
+ selectedLine= true;
+ gc.setForeground(fCachedTextWidget.getSelectionForeground());
+ gc.setBackground(fCachedTextWidget.getSelectionBackground());
+ }
+ } else if (selectedLine) {
+ selectedLine= false;
+ gc.setForeground(defaultForeground);
+ gc.setBackground(defaultBackground);
+ }
+ if (selectedLine) {
+ gc.fillRectangle(0, y, canvasSize.x, lineheight);
+ } else if (fPaintStyleBackground && widgetOffset >= 0 && widgetOffset < fCachedTextWidget.getCharCount()) {
+ StyleRange style= fCachedTextWidget.getStyleRangeAtOffset(widgetOffset);
+ if (style != null && style.background != null) {
+ gc.setBackground(style.background);
+ gc.fillRectangle(0, y + baselineBias, canvasSize.x, lineheight - baselineBias);
+ gc.setBackground(defaultBackground);
+ }
+ }
+
+ paintLine(modelLine, y, lineheight, gc, fCachedTextWidget.getDisplay());
+
+ String s= createDisplayString(modelLine);
+ int indentation= fAlignRight ? fIndentation[s.length()] : 0;
+ gc.drawString(s, indentation, y + baselineBias, true);
+ y += lineheight;
+ }
+ }
+
+ /**
+ * Returns the difference between the baseline of the widget and the
+ * baseline as specified by the font for <code>gc</code>. When drawing
+ * text, the returned bias should be added to obtain text line up on
+ * the correct base line of the text widget.
+ *
+ * @param gc
+ * the <code>GC</code> to get the font metrics from
+ * @return the baseline bias to use when drawing text that is line up with
+ * <code>fCachedTextWidget</code>
+ */
+ private int getBaselineBias(GC gc) {
+ /*
+ * https://bugs.eclipse.org/bugs/show_bug.cgi?id=62951 widget line
+ * height may be more than the font height used for the text,
+ * since font styles (bold, italics...) can have larger font metrics
+ * than the simple font used for the numbers.
+ */
+ int widgetBaseline= fCachedTextWidget.getBaseline();
+ FontMetrics fm= gc.getFontMetrics();
+ int fontBaseline= fm.getAscent() + fm.getLeading();
+ Assert.isTrue(widgetBaseline >= fontBaseline);
+ int baselineBias= widgetBaseline - fontBaseline;
+ return baselineBias;
+ }
+
+ /**
+ * Paints the line. After this method is called the text is painted
+ * on top of the result of this method.
+ * <p>
+ * This default implementation does nothing.
+ * </p>
+ *
+ * @param line
+ * the line of the document which the ruler is painted for
+ * @param y
+ * the y-coordinate of the box being painted for
+ * <code>line</code>, relative to <code>gc</code>
+ * @param lineheight
+ * the height of one line (and therefore of the box being
+ * painted)
+ * @param gc
+ * the drawing context the client may choose to draw on.
+ * @param display
+ * the display the drawing occurs on
+ */
+ protected void paintLine(int line, int y, int lineheight, GC gc, Display display) {
+ }
+
+ /**
+ * Triggers a redraw in the display thread.
+ */
+ protected final void postRedraw() {
+ if (fCanvas != null && !fCanvas.isDisposed()) {
+ Display d= fCanvas.getDisplay();
+ if (d != null) {
+ synchronized (fRunnableLock) {
+ if (fIsRunnablePosted)
+ return;
+ fIsRunnablePosted= true;
+ }
+ d.asyncExec(fRunnable);
+ }
+ }
+ }
+
+ /*
+ * @see IVerticalRulerColumn#redraw()
+ */
+ public void redraw() {
+
+ if (fRelayoutRequired) {
+ layout(true);
+ return;
+ }
+
+ if (fCanvas != null && !fCanvas.isDisposed()) {
+ GC gc= new GC(fCanvas);
+ doubleBufferPaint(gc);
+ gc.dispose();
+ }
+ }
+
+ /*
+ * @see IVerticalRulerColumn#setModel(IAnnotationModel)
+ */
+ public void setModel(IAnnotationModel model) {
+ }
+
+ /*
+ * @see IVerticalRulerColumn#setFont(Font)
+ */
+ public void setFont(Font font) {
+ fFont= font;
+ if (fCanvas != null && !fCanvas.isDisposed()) {
+ fCanvas.setFont(fFont);
+ updateNumberOfDigits();
+ computeIndentations();
+ }
+ }
+
+ /**
+ * Returns the parent (composite) ruler of this ruler column.
+ *
+ * @return the parent ruler
+ */
+ protected CompositeRuler getParentRuler() {
+ return fParentRuler;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java
new file mode 100644
index 00000000000..4d6fc9eac78
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyTextHover.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.AddressRangePosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.LabelPosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourcePosition;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.internal.ui.text.CWordFinder;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+
+/**
+ * A text hover to evaluate registers and variables under the cursor.
+ */
+@SuppressWarnings("restriction")
+public class DisassemblyTextHover implements ITextHover {
+
+ private final DisassemblyPart fDisassemblyPart;
+
+ /**
+ * Create a new disassembly text hover.
+ */
+ public DisassemblyTextHover(DisassemblyPart part) {
+ fDisassemblyPart= part;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int)
+ */
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ IDocument doc = textViewer.getDocument();
+ return CWordFinder.findWord(doc, offset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
+ */
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ DisassemblyDocument doc = (DisassemblyDocument)textViewer.getDocument();
+ int offset = hoverRegion.getOffset();
+ AddressRangePosition pos;
+ try {
+ String ident = doc.get(offset, hoverRegion.getLength());
+ String value = null;
+ pos = doc.getModelPosition(offset);
+ if (pos instanceof SourcePosition) {
+ value = evaluateExpression(ident);
+ } else if (pos instanceof LabelPosition) {
+ value = evaluateExpression(ident);
+ } else if (pos instanceof DisassemblyPosition) {
+ // first, try to evaluate as register
+ value = evaluateRegister(ident);
+ if (value == null) {
+ // if this fails, try expression
+ value = evaluateExpression(ident);
+ }
+ }
+ if (value != null) {
+ return ident + " = " + value; //$NON-NLS-1$
+ }
+ } catch (BadLocationException e) {
+ if (DsfUIPlugin.getDefault().isDebugging()) {
+ DsfUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, "Internal Error", e)); //$NON-NLS-1$
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Evaluate the given register.
+ * @param register
+ * @return register value or <code>null</code>
+ */
+ private String evaluateRegister(String register) {
+ // TLETODO [disassembly] evaluate register
+ return null;
+ }
+
+ /**
+ * Evaluate the given expression.
+ * @param expr
+ * @return expression value or <code>null</code>
+ */
+ private String evaluateExpression(String expr) {
+ final IExpressions expressions= fDisassemblyPart.getService(IExpressions.class);
+ if (expressions == null) {
+ return null;
+ }
+ final IFrameDMContext frameDmc= fDisassemblyPart.getTargetFrameContext();
+ if (frameDmc == null || !fDisassemblyPart.isSuspended()) {
+ return null;
+ }
+ IExpressionDMContext exprDmc= expressions.createExpression(frameDmc, expr);
+ final FormattedValueDMContext valueDmc= expressions.getFormattedValueContext(exprDmc, IFormattedValues.NATURAL_FORMAT);
+ final DsfExecutor executor= fDisassemblyPart.getSession().getExecutor();
+ Query<FormattedValueDMData> query= new Query<FormattedValueDMData>() {
+ @Override
+ protected void execute(final DataRequestMonitor<FormattedValueDMData> rm) {
+ expressions.getFormattedExpressionValue(valueDmc, new DataRequestMonitor<FormattedValueDMData>(executor, rm) {
+ @Override
+ protected void handleSuccess() {
+ FormattedValueDMData data= getData();
+ rm.setData(data);
+ rm.done();
+ }
+ });
+ }};
+
+ executor.execute(query);
+ FormattedValueDMData data= null;
+ try {
+ data= query.get();
+ } catch (InterruptedException exc) {
+ } catch (ExecutionException exc) {
+ }
+ if (data != null) {
+ return data.getFormattedValue();
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyView.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyView.java
new file mode 100644
index 00000000000..5ab83c6c1d3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyView.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PartInitException;
+
+/**
+ * DisassemblyView
+ */
+public class DisassemblyView extends DisassemblyPart implements IViewPart {
+
+ private ISelectionListener fDebugViewListener;
+
+ /**
+ *
+ */
+ public DisassemblyView() {
+ super();
+ }
+
+ @Override
+ protected IActionBars getActionBars() {
+ return getViewSite().getActionBars();
+ }
+
+ /*
+ * @see org.eclipse.ui.IViewPart#getViewSite()
+ */
+ public IViewSite getViewSite() {
+ return (IViewSite)getSite();
+ }
+
+ /*
+ * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite)
+ */
+ public void init(IViewSite site) throws PartInitException {
+ setSite(site);
+ }
+
+ /*
+ * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
+ */
+ public void init(IViewSite site, IMemento memento) throws PartInitException {
+ setSite(site);
+ site.getPage().addSelectionListener(IDebugUIConstants.ID_DEBUG_VIEW, fDebugViewListener= new ISelectionListener() {
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ updateDebugContext();
+ }});
+ }
+
+ /*
+ * @see org.eclipse.ui.IViewPart#saveState(org.eclipse.ui.IMemento)
+ */
+ public void saveState(IMemento memento) {
+ }
+
+ @Override
+ protected void contributeToActionBars(IActionBars bars) {
+ super.contributeToActionBars(bars);
+ fillLocalPullDown(bars.getMenuManager());
+ }
+
+ protected void fillLocalPullDown(IMenuManager manager) {
+ manager.add(fActionGotoPC);
+ manager.add(fActionGotoAddress);
+ manager.add(fActionToggleSource);
+ manager.add(new Separator());
+ }
+
+ @Override
+ protected void closePart() {
+ getViewSite().getPage().hideView(this);
+ }
+
+ @Override
+ public void dispose() {
+ getSite().getPage().removeSelectionListener(fDebugViewListener);
+ super.dispose();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java
new file mode 100644
index 00000000000..b57cd30f185
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewer.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.source.CompositeRuler;
+import org.eclipse.jface.text.source.IOverviewRuler;
+import org.eclipse.jface.text.source.IVerticalRuler;
+import org.eclipse.jface.text.source.IVerticalRulerColumn;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.dnd.TextTransfer;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * DisassemblyViewer
+ */
+public class DisassemblyViewer extends SourceViewer {
+
+ class ResizeListener implements ControlListener {
+ /*
+ * @see ControlListener#controlResized(ControlEvent)
+ */
+ public void controlResized(ControlEvent e) {
+ updateViewportListeners(RESIZE);
+ }
+ /*
+ * @see ControlListener#controlMoved(ControlEvent)
+ */
+ public void controlMoved(ControlEvent e) {
+ }
+ }
+
+ private boolean fUserTriggeredScrolling;
+ private int fCachedLastTopPixel;
+
+ // extra resize listener to workaround bug 171018
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=171018
+ private ResizeListener fResizeListener;
+
+ /**
+ * Create a new DisassemblyViewer.
+ * @param parent
+ * @param ruler
+ * @param overviewRuler
+ * @param showsAnnotationOverview
+ * @param styles
+ */
+ public DisassemblyViewer(Composite parent, IVerticalRuler ruler, IOverviewRuler overviewRuler, boolean showsAnnotationOverview, int styles) {
+ super(parent, ruler, overviewRuler, showsAnnotationOverview, styles);
+ // always readonly
+ setEditable(false);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewer#createControl(org.eclipse.swt.widgets.Composite, int)
+ */
+ @Override
+ protected void createControl(Composite parent, int styles) {
+ super.createControl(parent, styles);
+ // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=171018
+ getTextWidget().addControlListener(fResizeListener= new ResizeListener());
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewer#handleDispose()
+ */
+ @Override
+ protected void handleDispose() {
+ if (fResizeListener != null) {
+ getTextWidget().removeControlListener(fResizeListener);
+ }
+ super.handleDispose();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewer#doOperation(int)
+ */
+ @Override
+ public void doOperation(int operation) {
+ switch (operation) {
+ case COPY:
+ StyledText textWidget = getTextWidget();
+ if (textWidget == null || !redraws()) {
+ return;
+ }
+ if (textWidget.getSelectionCount() == 0) {
+ return;
+ }
+ String selectedText;
+ try {
+ selectedText = getSelectedText();
+ } catch (BadLocationException e) {
+ // should not happend
+ DsfUIPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, e.getLocalizedMessage(), e));
+ return;
+ }
+ Clipboard clipboard = new Clipboard(textWidget.getDisplay());
+ clipboard.setContents(new Object[] { selectedText }, new Transfer[] { TextTransfer.getInstance() });
+ clipboard.dispose();
+ break;
+ default:
+ super.doOperation(operation);
+ }
+ }
+
+ /**
+ * Get the selected text together with text displayed in visible
+ * ruler columns.
+ * @return the selected text
+ * @throws BadLocationException
+ */
+ public String getSelectedText() throws BadLocationException {
+ StringBuffer text = new StringBuffer(200);
+ String lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$
+ DisassemblyDocument doc = (DisassemblyDocument)getDocument();
+ Point selection = getSelectedRange();
+ int startOffset = selection.x;
+ int length = selection.y;
+ int endOffset = startOffset + length;
+ int startLine = doc.getLineOfOffset(startOffset);
+ int endLine = doc.getLineOfOffset(endOffset);
+ int firstLineOffset = startOffset - doc.getLineOffset(startLine);
+ if (firstLineOffset > 0) {
+ // partial first line
+ int lineLength = doc.getLineInformation(startLine).getLength();
+ text.append(doc.get(startOffset, Math.min(lineLength - firstLineOffset, length)));
+ ++startLine;
+ if (startLine <= endLine) {
+ text.append(lineSeparator);
+ }
+ }
+ for (int line = startLine; line < endLine; ++line) {
+ String lineText = getLineText(line);
+ text.append(lineText);
+ text.append(lineSeparator);
+ }
+ if (doc.getLineOffset(endLine) < endOffset) {
+ // partial last line
+ if (startLine <= endLine) {
+ int lineStart = doc.getLineOffset(endLine);
+ text.append(getLinePrefix(endLine));
+ text.append(doc.get(lineStart, endOffset - lineStart));
+ }
+ }
+ return text.toString();
+ }
+
+ /**
+ * Return the content of the given line, excluding line separator.
+ * @param line the line number
+ * @return the line content
+ * @throws BadLocationException
+ */
+ public String getLineText(int line) throws BadLocationException {
+ IDocument doc = getDocument();
+ IRegion lineRegion = doc.getLineInformation(line);
+ return getLinePrefix(line) + doc.get(lineRegion.getOffset(), lineRegion.getLength());
+ }
+
+ /**
+ * Get the line prefix by concatenating the text displayed by
+ * the visible ruler columns.
+ * @param line the line number
+ * @return the prefix string with trailing blank or the empty string
+ */
+ public String getLinePrefix(int line) {
+ StringBuffer prefix = new StringBuffer(10);
+ IVerticalRuler ruler = getVerticalRuler();
+ if (ruler instanceof CompositeRuler) {
+ for (Iterator<?> iter = ((CompositeRuler)ruler).getDecoratorIterator(); iter.hasNext();) {
+ IVerticalRulerColumn column = (IVerticalRulerColumn) iter.next();
+ if (column instanceof DisassemblyRulerColumn) {
+ DisassemblyRulerColumn disassColumn = (DisassemblyRulerColumn)column;
+ String columnText = disassColumn.createDisplayString(line);
+ prefix.append(columnText);
+ int columnWidth = disassColumn.computeNumberOfCharacters();
+ columnWidth -= columnText.length();
+ while(columnWidth-- > 0)
+ prefix.append(' ');
+ prefix.append(' ');
+ }
+ }
+ }
+ return prefix.toString();
+ }
+
+ /**
+ * Scroll the given position into the visible area if it is not yet visible.
+ * @param offset
+ * @see org.eclipse.jface.text.TextViewer#revealRange(int, int)
+ */
+ public void revealOffset(int offset, boolean onTop) {
+ try {
+ IDocument doc = getVisibleDocument();
+
+ int focusLine = doc.getLineOfOffset(offset);
+
+ StyledText textWidget = getTextWidget();
+ int top = textWidget.getTopIndex();
+ if (top > -1) {
+
+ // scroll vertically
+ int lines = getEstimatedVisibleLinesInViewport();
+ int bottom = top + lines;
+
+ int bottomBuffer = Math.max(1, lines / 3);
+
+ if (!onTop && focusLine >= top && focusLine <= bottom - bottomBuffer) {
+ // do not scroll at all as it is already visible
+ } else {
+ if (focusLine > bottom - bottomBuffer && focusLine <= bottom) {
+ // focusLine is already in bottom bufferZone
+ // scroll to top of bottom bufferzone - for smooth down-scrolling
+ int scrollDelta = focusLine - (bottom - bottomBuffer);
+ textWidget.setTopIndex(top + scrollDelta);
+ } else {
+ // scroll to top of visible area minus buffer zone
+ int topBuffer = onTop ? 0 : lines / 3;
+ textWidget.setTopIndex(Math.max(0, focusLine - topBuffer));
+ }
+ updateViewportListeners(INTERNAL);
+ }
+ }
+ } catch (BadLocationException ble) {
+ throw new IllegalArgumentException(ble.getLocalizedMessage());
+ }
+ }
+
+ /**
+ * @return the number of visible lines in the viewport assuming a constant
+ * line height.
+ */
+ private int getEstimatedVisibleLinesInViewport() {
+ StyledText textWidget = getTextWidget();
+ if (textWidget != null) {
+ Rectangle clArea= textWidget.getClientArea();
+ if (!clArea.isEmpty())
+ return clArea.height / textWidget.getLineHeight();
+ }
+ return -1;
+ }
+
+ int getLastTopPixel() {
+ return fCachedLastTopPixel;
+ }
+ boolean isUserTriggeredScrolling() {
+ return fUserTriggeredScrolling;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.TextViewer#updateViewportListeners(int)
+ */
+ @Override
+ protected void updateViewportListeners(int origin) {
+ fCachedLastTopPixel = fLastTopPixel;
+ fUserTriggeredScrolling = origin != INTERNAL && origin != RESIZE;
+ super.updateViewportListeners(origin);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java
new file mode 100644
index 00000000000..c11fbe38d03
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/DisassemblyViewerConfiguration.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.IUndoManager;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.presentation.IPresentationDamager;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.IPresentationRepairer;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.reconciler.IReconciler;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+
+/**
+ * DisassemblyViewerConfiguration
+ */
+public class DisassemblyViewerConfiguration extends TextSourceViewerConfiguration {
+
+ private DisassemblyPart fPart;
+
+ /**
+ * SimpleDamagerRepairer
+ */
+ public class SimpleDamagerRepairer implements IPresentationDamager, IPresentationRepairer {
+
+ /*
+ * @see org.eclipse.jface.text.presentation.IPresentationDamager#setDocument(org.eclipse.jface.text.IDocument)
+ */
+ public void setDocument(IDocument document) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.presentation.IPresentationDamager#getDamageRegion(org.eclipse.jface.text.ITypedRegion, org.eclipse.jface.text.DocumentEvent, boolean)
+ */
+ public IRegion getDamageRegion(ITypedRegion partition, DocumentEvent e, boolean documentPartitioningChanged) {
+ int start= e.fOffset;
+ int end= e.getOffset() + (e.getText() == null ? 0 : e.getText().length());
+ return new Region(start, end - start);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.presentation.IPresentationRepairer#createPresentation(org.eclipse.jface.text.TextPresentation, org.eclipse.jface.text.ITypedRegion)
+ */
+ public void createPresentation(TextPresentation presentation, ITypedRegion damage) {
+ // do nothing
+ }
+
+ }
+
+ /**
+ *
+ */
+ public DisassemblyViewerConfiguration(DisassemblyPart part) {
+ super(EditorsUI.getPreferenceStore());
+ fPart = part;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getPresentationReconciler(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ @Override
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+ PresentationReconciler reconciler = new PresentationReconciler();
+ SimpleDamagerRepairer dr = new SimpleDamagerRepairer();
+ reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ return reconciler;
+ }
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getUndoManager(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ @Override
+ public IUndoManager getUndoManager(ISourceViewer sourceViewer) {
+ // no undo/redo
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getTextHover(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
+ */
+ @Override
+ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
+ return new DisassemblyTextHover(fPart);
+ }
+
+ /*
+ * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getHyperlinkDetectors(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ @Override
+ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
+ IHyperlinkDetector[] inheritedDetectors= super.getHyperlinkDetectors(sourceViewer);
+
+ if (fPart == null)
+ return inheritedDetectors;
+
+ int inheritedDetectorsLength= inheritedDetectors != null ? inheritedDetectors.length : 0;
+ IHyperlinkDetector[] detectors= new IHyperlinkDetector[inheritedDetectorsLength + 1];
+ detectors[0]= new DisassemblyHyperlinkDetector(fPart);
+ for (int i= 0; i < inheritedDetectorsLength; i++) {
+ detectors[i+1]= inheritedDetectors[i];
+ }
+
+ return detectors;
+ }
+
+ /*
+ * @see org.eclipse.ui.editors.text.TextSourceViewerConfiguration#getReconciler(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ @Override
+ public IReconciler getReconciler(ISourceViewer sourceViewer) {
+ // disable spell checking
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/EditionFinderJob.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/EditionFinderJob.java
new file mode 100644
index 00000000000..40b32498824
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/EditionFinderJob.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourceFileInfo;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFileState;
+import org.eclipse.core.runtime.Assert;
+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.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.Job;
+
+/**
+ * A job to find a suitable edition from the local history
+ * based on a file and the timestamp of the code module.
+ */
+class EditionFinderJob extends Job {
+
+ private final IFile fFile;
+ private final BigInteger fAddress;
+ private final DisassemblyPart fDisassemblyPart;
+ private final SourceFileInfo fSourceInfo;
+
+ /**
+ * Create a new edition finder for a file resource and address.
+ *
+ * @param sourceInfo the file info containing the file resource for which to find an edition
+ * @param address address inside the module
+ * @param disassemblyPart the disassembly part where this job originated from
+ */
+ public EditionFinderJob(SourceFileInfo sourceInfo, BigInteger address, DisassemblyPart disassemblyPart) {
+ super(DisassemblyMessages.EditionFinderJob_name);
+ Assert.isNotNull(sourceInfo);
+ Assert.isLegal(sourceInfo.fFile instanceof IFile);
+ fSourceInfo= sourceInfo;
+ fFile = (IFile)sourceInfo.fFile;
+ fAddress = address;
+ fDisassemblyPart= disassemblyPart;
+ setRule(fFile);
+ setSystem(true);
+ sourceInfo.fEditionJob= this;
+ }
+
+ /*
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ monitor.beginTask(DisassemblyMessages.EditionFinderJob_name, 2);
+ monitor.subTask(DisassemblyMessages.EditionFinderJob_task_get_timestamp);
+ long moduleTime;
+ Object token = fDisassemblyPart.retrieveModuleTimestamp(fAddress);
+ if (token != null && !(token instanceof Long) && !monitor.isCanceled()) {
+ try {
+ synchronized (token) {
+ token.wait(1000);
+ }
+ } catch (InterruptedException e) {
+ DisassemblyPart.internalError(e);
+ }
+ token = fDisassemblyPart.retrieveModuleTimestamp(fAddress);
+ }
+ monitor.worked(1);
+ if (token instanceof Long && !monitor.isCanceled()) {
+ moduleTime = ((Long)token).longValue();
+ long buildTime = moduleTime * 1000;
+ if (fFile.getLocalTimeStamp() > buildTime) {
+ monitor.subTask(DisassemblyMessages.EditionFinderJob_task_search_history);
+ // get history - recent states first
+ IFileState[] states;
+ try {
+ states = fFile.getHistory(new SubProgressMonitor(monitor, 1));
+ } catch (CoreException e) {
+ states = new IFileState[0];
+ }
+ for (int i = 0; i < states.length; i++) {
+ IFileState state = states[i];
+ long saveTime = state.getModificationTime();
+ if (saveTime <= buildTime) {
+ fSourceInfo.fEdition = state;
+ break;
+ }
+ }
+ }
+ }
+ fSourceInfo.fEditionJob = null;
+ monitor.worked(1);
+ monitor.done();
+ return Status.OK_STATUS;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java
new file mode 100644
index 00000000000..3c8809d3e10
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/FunctionOffsetRulerColumn.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.AddressRangePosition;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyPosition;
+import org.eclipse.jface.text.BadLocationException;
+
+/**
+ * A vertical ruler column to display the function + offset of instructions.
+ */
+public class FunctionOffsetRulerColumn extends DisassemblyRulerColumn {
+
+ /** Maximum width of column (in characters) */
+ private static final int MAXWIDTH= 40;
+
+ /**
+ * Default constructor.
+ */
+ public FunctionOffsetRulerColumn() {
+ super();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.LineNumberRulerColumn#createDisplayString(int)
+ */
+ @Override
+ protected String createDisplayString(int line) {
+ DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument();
+ int offset;
+ try {
+ offset = doc.getLineOffset(line);
+ AddressRangePosition pos = doc.getDisassemblyPosition(offset);
+ if (pos instanceof DisassemblyPosition && pos.length > 0 && pos.offset == offset && pos.fValid) {
+ DisassemblyPosition disassPos = (DisassemblyPosition)pos;
+ int length = disassPos.fFunction.length;
+ if (length > MAXWIDTH) {
+ return "..." + new String(disassPos.fFunction, length - MAXWIDTH + 3, MAXWIDTH - 3); //$NON-NLS-1$
+ }
+ return new String(disassPos.fFunction);
+ } else if (pos != null && !pos.fValid) {
+ return DOTS.substring(0, Math.min(MAXWIDTH, doc.getMaxFunctionLength()));
+ }
+ } catch (BadLocationException e) {
+ // silently ignored
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ protected int computeNumberOfCharacters() {
+ DisassemblyDocument doc = (DisassemblyDocument)getParentRuler().getTextViewer().getDocument();
+ return Math.min(MAXWIDTH, doc.getMaxFunctionLength());
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java
new file mode 100644
index 00000000000..4e4eb8838aa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyHelpContextIds.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+
+/**
+ * IDisassemblyHelpContextIds
+ */
+public interface IDisassemblyHelpContextIds {
+
+ public final static String PREFIX = DsfUIPlugin.PLUGIN_ID + '.';
+ public final static String DISASSEMBLY_PREFERENCE_PAGE = PREFIX + "disassembly_preference_page"; //$NON-NLS-1$
+ public final static String DISASSEMBLY_VIEW = PREFIX + "disassembly_view"; //$NON-NLS-1$
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java
new file mode 100644
index 00000000000..5b6b2ebe380
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/IDisassemblyPart.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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:
+ * Anton Leherbauer (Wind River Systems) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.disassembly;
+
+import java.math.BigInteger;
+
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Interface which the disassembly view and editor implement.
+ */
+public interface IDisassemblyPart extends IWorkbenchPart {
+
+ /**
+ * Property id for the active state of the part.
+ */
+ public final int PROP_ACTIVE= 0x505;
+
+ /**
+ * Property id for the connected state of the part.
+ */
+ public final int PROP_CONNECTED= 0x506;
+
+ /**
+ * Property id for the suspended state of the underlying execution context.
+ */
+ public final int PROP_SUSPENDED= 0x507;
+
+ /**
+ * Test whether this part is connected to a debug session and execution context.
+ *
+ * @return <code>true</code> if the part is connected to a debug session and execution context
+ */
+ boolean isConnected();
+
+ /**
+ * Test whether this part is active. A part is active if it is visible and connected.
+ *
+ * @return <code>true</code> if the part is active
+ */
+ boolean isActive();
+
+ /**
+ * Test whether the underlying execution context is currently suspended.
+ * Implies connected state.
+ *
+ * @return <code>true</code> if the execution context is currently suspended
+ */
+ boolean isSuspended();
+
+ /**
+ * Get access to the text viewer.
+ *
+ * @return the text viewer
+ */
+ ISourceViewer getTextViewer();
+
+ /**
+ * Navigate to the given address.
+ *
+ * @param address
+ */
+ void gotoAddress(BigInteger address);
+
+ /**
+ * Navigate to current program counter.
+ */
+ void gotoProgramCounter();
+
+ /**
+ * Navigate to the address the given expression evaluates to.
+ *
+ * @param expression a symbolic address expression
+ */
+ void gotoSymbol(String expression);
+
+ /**
+ * Adds a ruler context menu listener to the disassembly part.
+ *
+ * @param listener the listener
+ */
+ void addRulerContextMenuListener(IMenuListener listener);
+
+ /**
+ * Removes a ruler context menu listener from the disassembly part.
+ *
+ * @param listener the listener
+ */
+ void removeRulerContextMenuListener(IMenuListener listener);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/SourceColorerJob.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/SourceColorerJob.java
new file mode 100644
index 00000000000..508aed24244
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/SourceColorerJob.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.DisassemblyDocument;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourceFileInfo;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
+import org.eclipse.ui.progress.UIJob;
+
+/**
+ * UI job to color source code.
+ */
+class SourceColorerJob extends UIJob implements Runnable {
+
+ private final DisassemblyPart fDisassemblyPart;
+ private final ISourceViewer fViewer;
+ private final DisassemblyDocument fDocument;
+ private final IStorage fStorage;
+
+ public SourceColorerJob(Display jobDisplay, IStorage storage, DisassemblyPart disassemblyPart) {
+ super(DisassemblyMessages.SourceColorerJob_name);
+ fDisassemblyPart= disassemblyPart;
+ fViewer= disassemblyPart.getTextViewer();
+ fDocument= (DisassemblyDocument) fViewer.getDocument();
+ fStorage = storage;
+ setDisplay(fDisassemblyPart.getSite().getShell().getDisplay());
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ /*
+ * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (fViewer != null && !monitor.isCanceled()) {
+ monitor.beginTask(DisassemblyMessages.SourceColorerJob_name, IProgressMonitor.UNKNOWN);
+ SourceFileInfo fi = fDocument.getSourceInfo(fStorage);
+ if (fi != null) {
+ fi.initPresentationCreator(fViewer);
+ if (fi.fError != null) {
+ String message= DisassemblyMessages.Disassembly_log_error_readFile + fi.fFileKey;
+ fDisassemblyPart.logWarning(message, fi.fError);
+ }
+ }
+ fDisassemblyPart.updateInvalidSource();
+ monitor.done();
+ }
+ return Status.OK_STATUS;
+ }
+
+ /*
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ IWorkbenchSiteProgressService progressService = (IWorkbenchSiteProgressService)fDisassemblyPart.getSite().getAdapter(IWorkbenchSiteProgressService.class);
+ if(progressService != null) {
+ progressService.schedule(this, 0, true);
+ } else {
+ schedule();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java
new file mode 100644
index 00000000000..81b935133c0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyAction.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.action.Action;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.texteditor.IUpdate;
+
+public abstract class AbstractDisassemblyAction extends Action implements IUpdate, IPropertyListener {
+
+ protected IDisassemblyPart fDisassemblyPart;
+
+ AbstractDisassemblyAction() {
+ }
+
+ /**
+ * Create a disassembly action.
+ *
+ * @param disassemblyPart
+ */
+ public AbstractDisassemblyAction(IDisassemblyPart disassemblyPart) {
+ Assert.isLegal(disassemblyPart != null);
+ fDisassemblyPart= disassemblyPart;
+ fDisassemblyPart.addPropertyListener(this);
+ }
+
+ /**
+ * @return the disassembly part
+ */
+ public final IDisassemblyPart getDisassemblyPart() {
+ return fDisassemblyPart;
+ }
+
+ /*
+ * @see org.eclipse.jface.action.Action#run()
+ */
+ @Override
+ public abstract void run();
+
+ public void update() {
+ boolean enabled= fDisassemblyPart == null || fDisassemblyPart.isConnected();
+ setEnabled(enabled);
+ }
+
+ /*
+ * @see org.eclipse.ui.IPropertyListener#propertyChanged(java.lang.Object, int)
+ */
+ public void propertyChanged(Object source, int propId) {
+ if (source == fDisassemblyPart && (propId & 0x500) != 0) {
+ update();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java
new file mode 100644
index 00000000000..1a3ad778b39
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyBreakpointRulerAction.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
+
+/**
+ * Abstract implementation of a breakpoint ruler action.
+ */
+public abstract class AbstractDisassemblyBreakpointRulerAction extends AbstractDisassemblyRulerAction {
+
+ /**
+ * Create breakpoint ruler action.
+ *
+ * @param disassemblyPart
+ * @param rulerInfo
+ */
+ protected AbstractDisassemblyBreakpointRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) {
+ super(disassemblyPart, rulerInfo);
+ }
+
+ /**
+ * Returns the breakpoint at the last line of mouse activity in the ruler
+ * or <code>null</code> if none.
+ *
+ * @return breakpoint associated with activity in the ruler or <code>null</code>
+ */
+ protected IBreakpoint getBreakpoint() {
+ IAnnotationModel annotationModel = getAnnotationModel();
+ IDocument document = getDocument();
+ if (annotationModel != null) {
+ Iterator<?> iterator = annotationModel.getAnnotationIterator();
+ while (iterator.hasNext()) {
+ Object object = iterator.next();
+ if (object instanceof SimpleMarkerAnnotation) {
+ SimpleMarkerAnnotation markerAnnotation = (SimpleMarkerAnnotation) object;
+ IMarker marker = markerAnnotation.getMarker();
+ try {
+ if (marker.isSubtypeOf(IBreakpoint.BREAKPOINT_MARKER)) {
+ Position position = annotationModel.getPosition(markerAnnotation);
+ int line = document.getLineOfOffset(position.getOffset());
+ if (line == getRulerInfo().getLineOfLastMouseButtonActivity()) {
+ IBreakpoint breakpoint = DebugPlugin.getDefault().getBreakpointManager().getBreakpoint(marker);
+ if (breakpoint != null) {
+ return breakpoint;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ } catch (BadLocationException e) {
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java
new file mode 100644
index 00000000000..d5af5e28b04
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerAction.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+
+/**
+ * Abstract implementation for disassembly vertical ruler actions.
+ */
+public abstract class AbstractDisassemblyRulerAction extends AbstractDisassemblyAction {
+
+ private final IVerticalRulerInfo fRulerInfo;
+
+ protected AbstractDisassemblyRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) {
+ fDisassemblyPart= disassemblyPart;
+ fRulerInfo= rulerInfo;
+ }
+
+ public final IVerticalRulerInfo getRulerInfo() {
+ return fRulerInfo;
+ }
+
+ public final IDocument getDocument() {
+ return getDisassemblyPart().getTextViewer().getDocument();
+ }
+
+ public final IAnnotationModel getAnnotationModel() {
+ return getDisassemblyPart().getTextViewer().getAnnotationModel();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java
new file mode 100644
index 00000000000..91aafa31b32
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/AbstractDisassemblyRulerActionDelegate.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.actions.ActionDelegate;
+import org.eclipse.ui.texteditor.IUpdate;
+
+/**
+ * This class serves as an adapter for actions contributed to the vertical ruler's
+ * context menu. This adapter provides the contributed actions access to their disassembly part
+ * and the disassembly part's vertical ruler. These actions gain only limited access to the vertical
+ * ruler as defined by <code>IVerticalRulerInfo</code>. The adapter updates the
+ * adapter (inner) action on menu and mouse action on the vertical ruler.<p>
+ * Extending classes must implement the factory method
+ * <code>createAction(IDisassemblyPart, IVerticalRulerInfo)</code>.
+ *
+ * @see org.eclipse.ui.texteditor.AbstractRulerActionDelegate
+ */
+public abstract class AbstractDisassemblyRulerActionDelegate extends ActionDelegate implements IEditorActionDelegate, IViewActionDelegate, MouseListener, IMenuListener {
+
+ /** The disassembly part. */
+ private IDisassemblyPart fDisassemblyPart;
+ /** The action calling the action delegate. */
+ private IAction fCallerAction;
+ /** The underlying action. */
+ private IAction fAction;
+
+ /**
+ * The factory method creating the underlying action.
+ *
+ * @param disassemblyPart the disassembly part the action to be created will work on
+ * @param rulerInfo the vertical ruler the action to be created will work on
+ * @return the created action
+ */
+ protected abstract IAction createAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo);
+
+ /*
+ * @see IEditorActionDelegate#setActiveEditor(org.eclipse.jface.action.IAction, org.eclipse.ui.IEditorPart)
+ */
+ public void setActiveEditor(IAction callerAction, IEditorPart targetEditor) {
+ setTargetPart(callerAction, targetEditor);
+ }
+
+ /*
+ * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
+ */
+ public void init(IViewPart view) {
+ setTargetPart(fCallerAction, view);
+ }
+
+ @Override
+ public void init(IAction action) {
+ fCallerAction= action;
+ }
+
+ private void setTargetPart(IAction callerAction, IWorkbenchPart targetPart) {
+ if (fDisassemblyPart != null) {
+ IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fDisassemblyPart.getAdapter(IVerticalRulerInfo.class);
+ if (rulerInfo != null) {
+ Control control= rulerInfo.getControl();
+ if (control != null && !control.isDisposed())
+ control.removeMouseListener(this);
+ }
+
+ fDisassemblyPart.removeRulerContextMenuListener(this);
+ }
+
+ fDisassemblyPart= (IDisassemblyPart)(targetPart == null ? null : targetPart.getAdapter(IDisassemblyPart.class));
+ fCallerAction= callerAction;
+ fAction= null;
+
+ if (fDisassemblyPart != null) {
+ fDisassemblyPart.addRulerContextMenuListener(this);
+
+ IVerticalRulerInfo rulerInfo= (IVerticalRulerInfo) fDisassemblyPart.getAdapter(IVerticalRulerInfo.class);
+ if (rulerInfo != null) {
+ fAction= createAction(fDisassemblyPart, rulerInfo);
+ update();
+
+ Control control= rulerInfo.getControl();
+ if (control != null && !control.isDisposed())
+ control.addMouseListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void run(IAction callerAction) {
+ if (fAction != null)
+ fAction.run();
+ }
+
+ @Override
+ public void runWithEvent(IAction action, Event event) {
+ if (fAction != null)
+ fAction.runWithEvent(event);
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ /*
+ * This is a ruler action - don't update on selection.
+ */
+ }
+
+ /**
+ * Updates to the current state.
+ */
+ private void update() {
+ if (fAction instanceof IUpdate) {
+ ((IUpdate) fAction).update();
+ if (fCallerAction != null) {
+ fCallerAction.setText(fAction.getText());
+ fCallerAction.setEnabled(fAction.isEnabled());
+ }
+ }
+ }
+
+ /*
+ * @see IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
+ */
+ public void menuAboutToShow(IMenuManager manager) {
+ update();
+ }
+
+ /*
+ * @see MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ /*
+ * @see MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDown(MouseEvent e) {
+ update();
+ }
+
+ /*
+ * @see MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseUp(MouseEvent e) {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java
new file mode 100644
index 00000000000..2b9a597ef15
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoAddress.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyPart;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.swt.widgets.Shell;
+
+public final class ActionGotoAddress extends AbstractDisassemblyAction {
+ public ActionGotoAddress(IDisassemblyPart disassemblyPart) {
+ super(disassemblyPart);
+ setText(DisassemblyMessages.Disassembly_action_GotoAddress_label);
+ }
+ @Override
+ public void run() {
+ IInputValidator validator = new IInputValidator() {
+ public String isValid(String input) {
+ if (input == null || input.length() == 0)
+ return " "; //$NON-NLS-1$
+ try {
+ BigInteger address= DisassemblyPart.decodeAddress(input);
+ if (address.compareTo(BigInteger.ZERO) < 0) {
+ return DisassemblyMessages.Disassembly_GotoAddressDialog_error_invalid_address;
+ }
+ } catch (NumberFormatException x) {
+ return DisassemblyMessages.Disassembly_GotoAddressDialog_error_not_a_number; //;
+ }
+ return null;
+ }
+ };
+ String defaultValue = ((ITextSelection)getDisassemblyPart().getSite().getSelectionProvider().getSelection()).getText();
+ if (validator.isValid(defaultValue) != null) {
+ defaultValue = DsfUIPlugin.getDefault().getDialogSettings().get("gotoAddress"); //$NON-NLS-1$
+ if (validator.isValid(defaultValue) != null) {
+ defaultValue = ""; //$NON-NLS-1$
+ }
+ }
+ String dlgTitle = DisassemblyMessages.Disassembly_GotoAddressDialog_title;
+ String dlgLabel = DisassemblyMessages.Disassembly_GotoAddressDialog_label;
+ final Shell shell= getDisassemblyPart().getSite().getShell();
+ InputDialog dlg = new InputDialog(shell, dlgTitle, dlgLabel, defaultValue, validator);
+ if (dlg.open() == IDialogConstants.OK_ID) {
+ String value = dlg.getValue();
+ BigInteger address= DisassemblyPart.decodeAddress(value);
+ DsfUIPlugin.getDefault().getDialogSettings().put("gotoAddress", value); //$NON-NLS-1$
+ getDisassemblyPart().gotoAddress(address);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java
new file mode 100644
index 00000000000..5dfddfb633e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoProgramCounter.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+
+public final class ActionGotoProgramCounter extends AbstractDisassemblyAction {
+ public ActionGotoProgramCounter(IDisassemblyPart disassemblyPart) {
+ super(disassemblyPart);
+ setText(DisassemblyMessages.Disassembly_action_GotoPC_label);
+ setToolTipText(DisassemblyMessages.Disassembly_action_GotoPC_tooltip);
+ }
+ @Override
+ public void run() {
+ getDisassemblyPart().gotoProgramCounter();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java
new file mode 100644
index 00000000000..893970968b7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionGotoSymbol.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.internal.ui.text.CWordFinder;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.swt.widgets.Shell;
+
+@SuppressWarnings("restriction")
+public final class ActionGotoSymbol extends AbstractDisassemblyAction {
+ public ActionGotoSymbol(IDisassemblyPart disassemblyPart) {
+ super(disassemblyPart);
+ setText(DisassemblyMessages.Disassembly_action_GotoSymbol_label);
+ }
+ @Override
+ public void run() {
+ ITextViewer viewer = getDisassemblyPart().getTextViewer();
+ IDocument document= viewer.getDocument();
+ IRegion wordRegion = CWordFinder.findWord(document, viewer.getSelectedRange().x);
+ String defaultValue = null;
+ if (wordRegion != null) {
+ try {
+ defaultValue = document.get(wordRegion.getOffset(), wordRegion.getLength());
+ } catch (BadLocationException e) {
+ // safely ignored
+ }
+ }
+ if (defaultValue == null) {
+ defaultValue = DsfUIPlugin.getDefault().getDialogSettings().get("gotoSymbol"); //$NON-NLS-1$
+ if (defaultValue == null) {
+ defaultValue = ""; //$NON-NLS-1$
+ }
+ }
+ String dlgTitle = DisassemblyMessages.Disassembly_GotoSymbolDialog_title;
+ String dlgLabel = DisassemblyMessages.Disassembly_GotoSymbolDialog_label;
+ final Shell shell= getDisassemblyPart().getSite().getShell();
+ InputDialog dlg = new InputDialog(shell, dlgTitle, dlgLabel, defaultValue, null);
+ if (dlg.open() == IDialogConstants.OK_ID) {
+ String value = dlg.getValue();
+ DsfUIPlugin.getDefault().getDialogSettings().put("gotoSymbol", value); //$NON-NLS-1$
+ getDisassemblyPart().gotoSymbol(value);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java
new file mode 100644
index 00000000000..dd5186fa8d9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/ActionOpenPreferences.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+
+public final class ActionOpenPreferences extends Action {
+ private final static String PREF_PAGE_ID = "org.eclipse.cdt.dsf.debug.ui.disassembly.preferencePage"; //$NON-NLS-1$
+ private final Shell fShell;
+ public ActionOpenPreferences(Shell shell) {
+ fShell= shell;
+ setText(DisassemblyMessages.Disassembly_action_OpenPreferences_label);
+ }
+ @Override
+ public void run() {
+ PreferencesUtil.createPreferenceDialogOn(fShell, PREF_PAGE_ID, new String[] { PREF_PAGE_ID }, null).open();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java
new file mode 100644
index 00000000000..4aab7e44ea2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerAction.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.debug.core.model.ICBreakpoint;
+import org.eclipse.cdt.debug.internal.ui.CBreakpointContext;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.ui.dialogs.PropertyDialogAction;
+
+/**
+ * Ruler action to display breakpoint properties.
+ */
+public class BreakpointPropertiesRulerAction extends AbstractDisassemblyBreakpointRulerAction {
+
+ private Object fContext;
+
+ protected BreakpointPropertiesRulerAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) {
+ super(disassemblyPart, rulerInfo);
+ setText(DisassemblyMessages.Disassembly_action_BreakpointProperties_label);
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyAction#run()
+ */
+ @Override
+ public void run() {
+ if ( fContext != null ) {
+ PropertyDialogAction action = new PropertyDialogAction( getDisassemblyPart().getSite(), new ISelectionProvider() {
+
+ public void addSelectionChangedListener( ISelectionChangedListener listener ) {
+ }
+
+ public ISelection getSelection() {
+ return new StructuredSelection( fContext );
+ }
+
+ public void removeSelectionChangedListener( ISelectionChangedListener listener ) {
+ }
+
+ public void setSelection( ISelection selection ) {
+ }
+ } );
+ action.run();
+ action.dispose();
+ }
+ }
+
+ /*
+ * @see IUpdate#update()
+ */
+ @Override
+ public void update() {
+ IBreakpoint breakpoint= getBreakpoint();
+ if (breakpoint instanceof ICBreakpoint) {
+ fContext = new CBreakpointContext((ICBreakpoint)breakpoint, getDebugContext());
+ } else {
+ fContext = breakpoint;
+ }
+ setEnabled( fContext != null );
+ }
+
+ private ISelection getDebugContext() {
+ return DebugUITools.getDebugContextManager().getContextService(getDisassemblyPart().getSite().getWorkbenchWindow()).getActiveContext();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java
new file mode 100644
index 00000000000..b5589d0d4f3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/BreakpointPropertiesRulerActionDelegate.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.source.IVerticalRulerInfo;
+
+/**
+ * Ruler action delegate for the breakpoint properties action.
+ */
+public class BreakpointPropertiesRulerActionDelegate extends AbstractDisassemblyRulerActionDelegate {
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.actions.AbstractDisassemblyRulerActionDelegate#createAction(org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyPart, org.eclipse.jface.text.source.IVerticalRulerInfo)
+ */
+ @Override
+ protected IAction createAction(IDisassemblyPart disassemblyPart, IVerticalRulerInfo rulerInfo) {
+ return new BreakpointPropertiesRulerAction(disassemblyPart, rulerInfo);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java
new file mode 100644
index 00000000000..87ac2124c45
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/actions/TextOperationAction.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.actions;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.ui.texteditor.IUpdate;
+
+/**
+ * TextOperationAction
+ */
+public class TextOperationAction extends Action implements IUpdate {
+
+ private int fOperationCode= -1;
+ private ITextOperationTarget fOperationTarget;
+
+ public TextOperationAction(ITextViewer viewer, int operationCode) {
+ fOperationCode= operationCode;
+ fOperationTarget= viewer.getTextOperationTarget();
+ update();
+ }
+
+ /**
+ * Updates the enabled state of the action.
+ * Fires a property change if the enabled state changes.
+ *
+ * @see Action#firePropertyChange(String, Object, Object)
+ */
+ public void update() {
+
+ boolean wasEnabled= isEnabled();
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ setEnabled(isEnabled);
+
+ if (wasEnabled != isEnabled) {
+ firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE);
+ }
+ }
+
+ /**
+ * @see Action#run()
+ */
+ @Override
+ public void run() {
+ if (fOperationCode != -1 && fOperationTarget != null) {
+ fOperationTarget.doOperation(fOperationCode);
+ }
+ }
+ }
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/Addr2Line.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/Addr2Line.java
new file mode 100644
index 00000000000..7f72b603188
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/Addr2Line.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+
+public class Addr2Line {
+ public BigInteger addr;
+ public Addr2Line next;
+ public int first;
+ public int last;
+
+ public static int hash(BigInteger addr, int size) {
+ return (int)((addr.shiftRight(2).longValue()) % size);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java
new file mode 100644
index 00000000000..7f4b865fdf0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/AddressRangePosition.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+import org.eclipse.jface.text.Position;
+
+/**
+ * AddressRangePosition
+ */
+public class AddressRangePosition extends Position {
+
+ public BigInteger fAddressOffset;
+ public BigInteger fAddressLength;
+ public boolean fValid;
+
+ /**
+ * @param offset
+ * @param length
+ */
+ public AddressRangePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength) {
+ super(offset, length);
+ fAddressOffset = addressOffset;
+ fAddressLength = addressLength;
+ fValid = true;
+ }
+
+ /**
+ * @param offset
+ * @param length
+ * @param valid
+ */
+ public AddressRangePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, boolean valid) {
+ super(offset, length);
+ fAddressOffset = addressOffset;
+ fAddressLength = addressLength;
+ fValid = valid;
+ }
+
+ /**
+ * @param address
+ * @return
+ */
+ public boolean containsAddress(BigInteger address) {
+ return address.compareTo(fAddressOffset) >= 0
+ && address.compareTo(fAddressOffset.add(fAddressLength)) < 0;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object other) {
+ // identity comparison
+ return this == other;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java
new file mode 100644
index 00000000000..c95b04a817a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/BreakpointsAnnotationModel.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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:
+ * Anton Leherbauer (Wind River Systems) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+import java.util.Iterator;
+
+import org.eclipse.cdt.debug.core.model.ICAddressBreakpoint;
+import org.eclipse.cdt.debug.core.model.ICLineBreakpoint;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointListener;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ILineBreakpoint;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.AnnotationModel;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
+import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
+
+/**
+ * Annotation model for breakpoints in the disassembly.
+ * Works only with {@link DisassemblyDocument}.
+ */
+public class BreakpointsAnnotationModel extends AnnotationModel implements IBreakpointListener, IDocumentListener {
+
+ private Runnable fCatchup;
+
+ @Override
+ public void connect(IDocument document) {
+ super.connect(document);
+ if (document instanceof DisassemblyDocument) {
+ final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager();
+ addBreakpoints(bpMgr.getBreakpoints());
+ bpMgr.addBreakpointListener(this);
+ document.addDocumentListener(this);
+ }
+ }
+
+ @Override
+ public void disconnect(IDocument document) {
+ if (document instanceof DisassemblyDocument) {
+ final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager();
+ bpMgr.removeBreakpointListener(this);
+ document.removeDocumentListener(this);
+ fCatchup= null;
+ }
+ super.disconnect(document);
+ }
+
+ private void catchupWithBreakpoints() {
+ removeAllAnnotations(false);
+ final IBreakpointManager bpMgr= DebugPlugin.getDefault().getBreakpointManager();
+ addBreakpoints(bpMgr.getBreakpoints());
+ }
+
+ private void addBreakpoints(IBreakpoint[] breakpoints) {
+ for (IBreakpoint breakpoint : breakpoints) {
+ addBreakpointAnnotation(breakpoint, false);
+ }
+ fireModelChanged();
+ }
+
+ /*
+ * @see org.eclipse.debug.core.IBreakpointListener#breakpointAdded(org.eclipse.debug.core.model.IBreakpoint)
+ */
+ public void breakpointAdded(IBreakpoint breakpoint) {
+ addBreakpointAnnotation(breakpoint, true);
+ }
+
+ /*
+ * @see org.eclipse.debug.core.IBreakpointListener#breakpointChanged(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
+ */
+ public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
+ Annotation a= findAnnotation(breakpoint.getMarker());
+ if (a != null) {
+ if (a instanceof SimpleMarkerAnnotation) {
+ ((SimpleMarkerAnnotation)a).update();
+ }
+ synchronized (getLockObject()) {
+ getAnnotationModelEvent().annotationChanged(a);
+ }
+ fireModelChanged();
+ }
+ }
+
+ /*
+ * @see org.eclipse.debug.core.IBreakpointListener#breakpointRemoved(org.eclipse.debug.core.model.IBreakpoint, org.eclipse.core.resources.IMarkerDelta)
+ */
+ public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
+ Annotation a= findAnnotation(breakpoint.getMarker());
+ if (a != null) {
+ removeAnnotation(a, true);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Annotation findAnnotation(IMarker marker) {
+ for (Iterator<SimpleMarkerAnnotation> it= getAnnotationIterator(false); it.hasNext();) {
+ SimpleMarkerAnnotation a= it.next();
+ if (a.getMarker().equals(marker)) {
+ return a;
+ }
+ }
+ return null;
+ }
+
+ private void addBreakpointAnnotation(IBreakpoint breakpoint, boolean fireEvent) {
+ final IMarker marker= breakpoint.getMarker();
+ if (marker == null) {
+ return;
+ }
+ try {
+ Position position= createPositionFromBreakpoint(breakpoint);
+ if (position != null) {
+ addAnnotation(new MarkerAnnotation(marker), position, fireEvent);
+ }
+ } catch (CoreException exc) {
+ // ignore problems accessing attributes
+ } catch (BadLocationException exc) {
+ // ignore wrong positions
+ }
+ }
+
+ private Position createPositionFromBreakpoint(IBreakpoint breakpoint) throws CoreException {
+ if (breakpoint instanceof ICAddressBreakpoint) {
+ ICAddressBreakpoint addressBreakpoint= (ICAddressBreakpoint) breakpoint;
+ return createPositionFromAddress(decodeAddress(addressBreakpoint.getAddress()));
+ } else if (breakpoint instanceof ILineBreakpoint) {
+ ILineBreakpoint lineBreakpoint= (ILineBreakpoint) breakpoint;
+ Position position= null;
+ final int lineNumber= lineBreakpoint.getLineNumber() - 1;
+ final IMarker marker= breakpoint.getMarker();
+ if (marker.getResource().getType() == IResource.FILE) {
+ position= createPositionFromSourceLine((IFile) marker.getResource(), lineNumber);
+ } else if (breakpoint instanceof ICLineBreakpoint) {
+ ICLineBreakpoint cBreakpoint= (ICLineBreakpoint) breakpoint;
+ position= createPositionFromSourceLine(cBreakpoint.getFileName(), lineNumber);
+ if (position == null) {
+ position= createPositionFromAddress(decodeAddress(cBreakpoint.getAddress()));
+ }
+ } else {
+ String fileName= marker.getAttribute(ICLineBreakpoint.SOURCE_HANDLE, null);
+ if (fileName != null) {
+ position= createPositionFromSourceLine(fileName, lineNumber);
+ }
+ }
+ return position;
+ }
+ return null;
+ }
+
+ private Position createPositionFromSourceLine(String fileName, int lineNumber) {
+ return getDisassemblyDocument().getSourcePosition(fileName, lineNumber);
+ }
+
+ private Position createPositionFromSourceLine(IFile file, int lineNumber) {
+ return getDisassemblyDocument().getSourcePosition(file, lineNumber);
+ }
+
+ private Position createPositionFromAddress(BigInteger address) {
+ AddressRangePosition p= getDisassemblyDocument().getDisassemblyPosition(address);
+ if (p != null && p.fValid) {
+ return new Position(p.offset, p.length);
+ }
+ return null;
+ }
+
+ private DisassemblyDocument getDisassemblyDocument() {
+ return (DisassemblyDocument) fDocument;
+ }
+
+ /**
+ * Decode given string representation of a non-negative integer. A
+ * hexadecimal encoded integer is expected to start with <code>0x</code>.
+ *
+ * @param string
+ * decimal or hexadecimal representation of an non-negative integer
+ * @return address value as <code>BigInteger</code>
+ */
+ private static BigInteger decodeAddress(String string) {
+ if (string.startsWith("0x")) { //$NON-NLS-1$
+ return new BigInteger(string.substring(2), 16);
+ }
+ return new BigInteger(string);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent)
+ */
+ public void documentAboutToBeChanged(DocumentEvent event) {
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent)
+ */
+ public void documentChanged(DocumentEvent event) {
+ if (fCatchup == null && event.fText != null && event.fText.length() > 0) {
+ fCatchup= new Runnable() {
+ public void run() {
+ if (fCatchup == this) {
+ catchupWithBreakpoints();
+ fCatchup= null;
+ }
+ }};
+ Display.getCurrent().timerExec(50, fCatchup);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java
new file mode 100644
index 00000000000..84666b0351c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyDocument.java
@@ -0,0 +1,1423 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.io.File;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text.REDDocument;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.BadPositionCategoryException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Position;
+
+/**
+ * DisassemblyDocument
+ */
+public class DisassemblyDocument extends REDDocument {
+
+ public final static String CATEGORY_MODEL = "category_model"; //$NON-NLS-1$
+ public final static String CATEGORY_DISASSEMBLY = "category_disassembly"; //$NON-NLS-1$
+ public final static String CATEGORY_SOURCE = "category_source"; //$NON-NLS-1$
+ public final static String CATEGORY_LABELS = "category_labels"; //$NON-NLS-1$
+
+ private final static boolean DEBUG = false;
+
+ public ArrayList<AddressRangePosition> fInvalidAddressRanges = new ArrayList<AddressRangePosition>();
+ public ArrayList<SourcePosition> fInvalidSource = new ArrayList<SourcePosition>();
+ private Map<IStorage, SourceFileInfo> fFileInfoMap = new HashMap<IStorage, SourceFileInfo>();
+
+ private int fMaxFunctionLength = 0;
+
+ private boolean fShowAddresses = false;
+ private int fRadix = 16;
+ private boolean fShowRadixPrefix = false;
+ private String fRadixPrefix;
+ private int fNumberOfDigits;
+ private boolean fShowCodeBytes = false;
+
+ private int fNumberOfInstructions;
+ private double fMeanSizeOfInstructions = 4;
+
+ public DisassemblyDocument() {
+ super();
+ }
+
+ /*
+ * @see org.eclipse.jface.text.AbstractDocument#completeInitialization()
+ */
+ @Override
+ protected void completeInitialization() {
+ super.completeInitialization();
+ addPositionCategory(CATEGORY_MODEL);
+ addPositionCategory(CATEGORY_DISASSEMBLY);
+ addPositionCategory(CATEGORY_SOURCE);
+ addPositionCategory(CATEGORY_LABELS);
+ setRadix(16);
+ setShowRadixPrefix(false);
+ }
+
+ /**
+ * Cleanup.
+ */
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (fFileInfoMap != null) {
+ // cleanup source info
+ for (Iterator<SourceFileInfo> iter = fFileInfoMap.values().iterator(); iter.hasNext();) {
+ SourceFileInfo fi = iter.next();
+ fi.dispose();
+ }
+ fFileInfoMap = null;
+ }
+ }
+
+ public List<AddressRangePosition> getInvalidAddressRanges() {
+ return fInvalidAddressRanges;
+ }
+
+ public List<SourcePosition> getInvalidSource() {
+ return fInvalidSource;
+ }
+
+ public void setMaxOpcodeLength(int opcodeLength) {
+ fMaxFunctionLength = opcodeLength;
+ }
+
+ public int getMaxFunctionLength() {
+ return fMaxFunctionLength;
+ }
+
+ public int getAddressLength() {
+ return fNumberOfDigits+2;
+ }
+
+ public int getMeanSizeOfInstructions() {
+ return (int)(fMeanSizeOfInstructions+.9);
+ }
+
+ public Iterator<AddressRangePosition> getModelPositionIterator(BigInteger address) {
+ try {
+ return getPositionIterator(CATEGORY_MODEL, address);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ return null;
+ }
+
+ public Iterator<Position> getPositionIterator(String category, int offset) throws BadPositionCategoryException {
+ @SuppressWarnings("unchecked")
+ List<Position> positions = (List<Position>) getDocumentManagedPositions().get(category);
+ if (positions == null) {
+ throw new BadPositionCategoryException();
+ }
+ int idx = computeIndexInPositionList(positions, offset, true);
+ return positions.listIterator(idx);
+ }
+
+ public Iterator<AddressRangePosition> getPositionIterator(String category, BigInteger address) throws BadPositionCategoryException {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> positions = (List<AddressRangePosition>) getDocumentManagedPositions().get(category);
+ if (positions == null) {
+ throw new BadPositionCategoryException();
+ }
+ int idx = computeIndexInPositionListFirst(positions, address);
+ return positions.listIterator(idx);
+ }
+
+ public int computeIndexInCategory(String category, BigInteger address) throws BadPositionCategoryException {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> c = (List<AddressRangePosition>) getDocumentManagedPositions().get(category);
+ if (c == null) {
+ throw new BadPositionCategoryException();
+ }
+ return computeIndexInPositionListFirst(c, address);
+ }
+
+ /**
+ * Computes the index in the list of positions at which a position with the
+ * given address would be inserted. The position is supposed to become the
+ * first in this list of all positions with the same offset.
+ *
+ * @param positions
+ * the list in which the index is computed
+ * @param address
+ * the address for which the index is computed
+ * @return the computed index
+ *
+ */
+ protected int computeIndexInPositionListFirst(List<AddressRangePosition> positions, BigInteger address) {
+ int size = positions.size();
+ if (size == 0) {
+ return 0;
+ }
+ int left = 0;
+ int right = size - 1;
+ int mid = 0;
+ while (left <= right) {
+ mid = (left + right) / 2;
+ AddressRangePosition range = positions.get(mid);
+ if (address.compareTo(range.fAddressOffset) < 0) {
+ right = mid - 1;
+ } else if (address.compareTo(range.fAddressOffset) == 0) {
+ break;
+ } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) {
+ left = mid + 1;
+ } else {
+ break;
+ }
+ }
+ int idx = mid;
+ AddressRangePosition p = positions.get(idx);
+ if (address.compareTo(p.fAddressOffset.add(p.fAddressLength)) > 0) {
+ ++idx;
+ } else if (address.compareTo(p.fAddressOffset) == 0) {
+ do {
+ --idx;
+ if (idx < 0) {
+ break;
+ }
+ p = positions.get(idx);
+ } while (address.compareTo(p.fAddressOffset) == 0);
+ ++idx;
+ }
+ return idx;
+ }
+
+ /**
+ * Computes the index in the list of positions at which a position with the
+ * given address would be inserted. The position is supposed to become the
+ * last but one in this list of all positions with the same address.
+ *
+ * @param positions
+ * the list in which the index is computed
+ * @param address
+ * the address for which the index is computed
+ * @return the computed index
+ *
+ */
+ protected int computeIndexInPositionListLast(List<AddressRangePosition> positions, BigInteger address) {
+ int size = positions.size();
+ if (size == 0) {
+ return 0;
+ }
+ int left = 0;
+ int right = size - 1;
+ int mid = 0;
+ while (left <= right) {
+ mid = (left + right) / 2;
+ AddressRangePosition range = positions.get(mid);
+ if (address.compareTo(range.fAddressOffset) < 0) {
+ right = mid - 1;
+ } else if (address.compareTo(range.fAddressOffset) == 0) {
+ break;
+ } else if (address.compareTo(range.fAddressOffset.add(range.fAddressLength)) >= 0) {
+ left = mid + 1;
+ } else {
+ break;
+ }
+ }
+ int idx = mid;
+ AddressRangePosition p = positions.get(idx);
+ if (address.compareTo(p.fAddressOffset) > 0) {
+ ++idx;
+ } else if (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0) {
+ do {
+ ++idx;
+ if (idx == size) {
+ break;
+ }
+ p = positions.get(idx);
+ } while (address.compareTo(p.fAddressOffset) == 0 && p.fAddressLength.compareTo(BigInteger.ZERO) == 0);
+ // --idx;
+ }
+ return idx;
+ }
+
+ /**
+ * Computes the index in the list of positions at which a position with the
+ * given offset would be inserted. The position is supposed to become the
+ * last in this list of all positions with the same offset.
+ *
+ * @param positions
+ * the list in which the index is computed
+ * @param offset
+ * the offset for which the index is computed
+ * @return the computed index
+ *
+ * @see IDocument#computeIndexInCategory(String, int)
+ */
+ protected int computeIndexInPositionListLast(List<Position> positions, int offset) {
+
+ if (positions.size() == 0)
+ return 0;
+
+ int left = 0;
+ int right = positions.size() - 1;
+ int mid = 0;
+ Position p = null;
+
+ while (left < right) {
+
+ mid = (left + right) / 2;
+
+ p = positions.get(mid);
+ if (offset < p.getOffset()) {
+ if (left == mid)
+ right = left;
+ else
+ right = mid - 1;
+ } else if (offset > p.getOffset()) {
+ if (right == mid)
+ left = right;
+ else
+ left = mid + 1;
+ } else if (offset == p.getOffset()) {
+ left = right = mid;
+ }
+
+ }
+
+ int pos = left;
+ p = positions.get(pos);
+ while (offset >= p.getOffset()) {
+ // entry will become the last of all entries with the same offset
+ ++pos;
+ if (pos == positions.size()) {
+ break;
+ }
+ p = positions.get(pos);
+ }
+
+ assert 0 <= pos && pos <= positions.size();
+
+ return pos;
+ }
+
+ /**
+ * Get the position for the supplied category and index.
+ *
+ * @param category
+ * @param index
+ * @return a Position matching the category and index, or <code>null</code>.
+ */
+ public Position getPositionOfIndex(String category, int index) throws BadPositionCategoryException {
+ if (index >= 0) {
+ @SuppressWarnings("unchecked")
+ List<Position> positions = (List<Position>) getDocumentManagedPositions().get(category);
+ if (positions == null) {
+ throw new BadPositionCategoryException();
+ }
+ if (index < positions.size()) {
+ return positions.get(index);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param address
+ * @return
+ */
+ public AddressRangePosition getPositionOfAddress(BigInteger address) {
+ AddressRangePosition pos = getPositionOfAddress(CATEGORY_DISASSEMBLY, address);
+ return pos;
+ }
+
+ /**
+ * @param category
+ * @param address
+ * @return
+ */
+ public AddressRangePosition getPositionOfAddress(String category, BigInteger address) {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> positions = (List<AddressRangePosition>) getDocumentManagedPositions().get(category);
+ if (positions == null) {
+ return null;
+ }
+ int index = computeIndexInPositionListFirst(positions, address);
+ if (index < positions.size()) {
+ AddressRangePosition p = positions.get(index);
+ if (address.compareTo(p.fAddressOffset) == 0 || p.containsAddress(address)) {
+ return p;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param category
+ * @param range
+ * @return
+ */
+ public AddressRangePosition getPositionInAddressRange(String category, AddressRangePosition range) {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> positions = (List<AddressRangePosition>) getDocumentManagedPositions().get(category);
+ if (positions == null) {
+ return null;
+ }
+ BigInteger endAddress = range.fAddressOffset.add(range.fAddressLength);
+ int index = computeIndexInPositionListFirst(positions, range.fAddressOffset);
+ if (index < positions.size()) {
+ do {
+ AddressRangePosition p = positions.get(index);
+ if (p.fAddressOffset.compareTo(endAddress) >= 0) {
+ --index;
+ } else {
+ return p;
+ }
+ } while (index >= 0);
+ }
+ return null;
+ }
+
+ /**
+ * Compute the address of the given document line number.
+ *
+ * @param line
+ * @return the address of the given document line number, -1 if no valid
+ * address can be computed
+ */
+ public BigInteger getAddressOfLine(int line) {
+ try {
+ int offset = getLineOffset(line);
+ return getAddressOfOffset(offset);
+ } catch (BadLocationException e) {
+ // intentionally ignored
+ }
+ return BigInteger.valueOf(-1);
+ }
+
+ /**
+ * Compute the address off the given document offset.
+ *
+ * @param offset
+ * @return the address of the given document offset, -1 if no valid address
+ * can be computed
+ */
+ public BigInteger getAddressOfOffset(int offset) {
+ AddressRangePosition pos;
+ try {
+ pos = getModelPosition(offset);
+ } catch (BadLocationException e) {
+ internalError(e);
+ return BigInteger.valueOf(-1);
+ }
+ if (pos == null) {
+ return BigInteger.valueOf(-1);
+ }
+ return pos.fAddressOffset;
+ }
+
+ /**
+ * @param offset
+ * @return
+ */
+ public AddressRangePosition getDisassemblyPosition(int offset) throws BadLocationException {
+ Position p = null;
+ try {
+ p = getPosition(CATEGORY_DISASSEMBLY, offset, false);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ return (AddressRangePosition) p;
+ }
+
+ /**
+ * @param address
+ * @return
+ */
+ public AddressRangePosition getDisassemblyPosition(BigInteger address) {
+ return getPositionOfAddress(CATEGORY_DISASSEMBLY, address);
+ }
+
+
+ /**
+ * @param offset
+ * @return
+ * @throws BadLocationException
+ */
+ public AddressRangePosition getModelPosition(int offset) throws BadLocationException {
+ Position p = null;
+ try {
+ p = getPosition(CATEGORY_MODEL, offset, false);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ return (AddressRangePosition) p;
+ }
+
+ /**
+ * @param offset
+ * @return
+ * @throws BadLocationException
+ */
+ public SourcePosition getSourcePosition(int offset) throws BadLocationException {
+ Position p = null;
+ try {
+ p = getPosition(CATEGORY_SOURCE, offset, true);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ return (SourcePosition) p;
+ }
+
+ /**
+ * @param address
+ * @return
+ */
+ public SourcePosition getSourcePosition(BigInteger address) {
+ return (SourcePosition) getPositionOfAddress(CATEGORY_SOURCE, address);
+ }
+
+ /**
+ * @param address
+ * @return
+ */
+ public LabelPosition getLabelPosition(BigInteger address) {
+ return (LabelPosition) getPositionOfAddress(CATEGORY_LABELS, address);
+ }
+
+ /**
+ * @param range
+ * @return
+ */
+ public SourcePosition getSourcePositionInAddressRange(AddressRangePosition range) {
+ return (SourcePosition) getPositionInAddressRange(CATEGORY_SOURCE, range);
+ }
+
+ /**
+ * Compute document position of the given source line.
+ *
+ * @param file the file as an <code>IStorage</code>
+ * @param lineNumber the 0-based line number
+ * @return the document position or <code>null</code>
+ */
+ public Position getSourcePosition(IStorage file, int lineNumber) {
+ SourceFileInfo info= getSourceInfo(file);
+ return getSourcePosition(info, lineNumber);
+ }
+
+ /**
+ * Compute document position of the given source line.
+ *
+ * @param fileName the file name, may be a raw debugger path or the path to an external file
+ * @param lineNumber the 0-based line number
+ * @return the document position or <code>null</code>
+ */
+ public Position getSourcePosition(String fileName, int lineNumber) {
+ SourceFileInfo info= getSourceInfo(fileName);
+ if (info == null) {
+ info= getSourceInfo(new LocalFileStorage(new File(fileName)));
+ }
+ return getSourcePosition(info, lineNumber);
+ }
+
+ /**
+ * Compute document position of the given source line.
+ *
+ * @param info
+ * @param lineNumber the 0-based line number
+ * @return the document position or <code>null</code>
+ */
+ protected Position getSourcePosition(SourceFileInfo info, int lineNumber) {
+ if (info == null || info.fSource == null) {
+ return null;
+ }
+ try {
+ SourcePosition srcPos= null;
+ IRegion stmtLineRegion= info.fSource.getLineInformation(lineNumber);
+ final int lineOffset = stmtLineRegion.getOffset();
+ final int lineLength = stmtLineRegion.getLength() + 1;
+ BigInteger stmtAddress = info.fLine2Addr[lineNumber];
+ if (stmtAddress != null && stmtAddress.compareTo(BigInteger.ZERO) > 0) {
+ srcPos = getSourcePosition(stmtAddress);
+ }
+ if (srcPos == null) {
+ for (Iterator<Position> iterator = getPositionIterator(CATEGORY_SOURCE, 0); iterator.hasNext(); ) {
+ SourcePosition pos= (SourcePosition) iterator.next();
+ if (pos.fFileInfo == info && pos.fValid && lineNumber >= pos.fLine) {
+ int baseOffset= info.fSource.getLineOffset(pos.fLine);
+ if (lineOffset + lineLength - baseOffset <= pos.length) {
+ srcPos= pos;
+ break;
+ }
+ }
+ }
+ if (srcPos == null) {
+ return null;
+ }
+ } else if (!srcPos.fValid) {
+ return null;
+ }
+ assert lineNumber >= srcPos.fLine;
+ int baseOffset = info.fSource.getLineOffset(srcPos.fLine);
+ int offset = srcPos.offset + lineOffset - baseOffset;
+ if (offset >= srcPos.offset && offset < srcPos.offset + srcPos.length) {
+ return new Position(offset, lineLength);
+ }
+ } catch (BadLocationException exc) {
+ // TLETODO Auto-generated catch block
+ exc.printStackTrace();
+ } catch (BadPositionCategoryException exc) {
+ // TLETODO Auto-generated catch block
+ exc.printStackTrace();
+ }
+ return null;
+ }
+
+
+ /**
+ * @param category
+ * @param offset
+ * @return
+ * @throws BadPositionCategoryException
+ * @throws BadLocationException
+ */
+ public Position getPosition(String category, int offset, boolean allowZeroLength) throws BadLocationException, BadPositionCategoryException {
+ @SuppressWarnings("unchecked")
+ List<Position> list = (List<Position>) getDocumentManagedPositions().get(category);
+ int idx;
+ idx = computeIndexInPositionList(list, offset, true);
+ if (idx > 0) {
+ --idx;
+ }
+ while (idx < list.size()) {
+ Position pos = list.get(idx);
+ if (pos.offset > offset) {
+ break;
+ }
+ if (pos.includes(offset)) {
+ return pos;
+ }
+ if (allowZeroLength && pos.offset == offset) {
+ return pos;
+ }
+ ++idx;
+ }
+ return null;
+ }
+
+ /**
+ * @param pos
+ */
+ public void addModelPosition(AddressRangePosition pos) {
+ try {
+ addPositionLast(CATEGORY_MODEL, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ */
+ public void addModelPositionFirst(AddressRangePosition pos) {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> list = (List<AddressRangePosition>) getDocumentManagedPositions().get(CATEGORY_MODEL);
+ int idx;
+ idx = computeIndexInPositionListFirst(list, pos.fAddressOffset.add(pos.fAddressLength));
+ if (idx < list.size()) {
+ AddressRangePosition nextPos = list.get(idx);
+ assert nextPos.fAddressOffset.compareTo(pos.fAddressOffset.add(pos.fAddressLength)) == 0;
+ }
+ list.add(idx, pos);
+ }
+
+ /**
+ * @param pos
+ * @throws BadLocationException
+ */
+ public void addDisassemblyPosition(AddressRangePosition pos) throws BadLocationException {
+ try {
+ addPositionLast(CATEGORY_DISASSEMBLY, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ if (pos instanceof DisassemblyPosition) {
+ int functionLength = ((DisassemblyPosition)pos).fFunction.length;
+ if (functionLength > fMaxFunctionLength) {
+ fMaxFunctionLength = functionLength;
+ }
+ if (fNumberOfInstructions < 100) {
+ fMeanSizeOfInstructions = (fMeanSizeOfInstructions * fNumberOfInstructions + pos.fAddressLength.floatValue()) / (++fNumberOfInstructions);
+ }
+ }
+ }
+
+ /**
+ * @param pos
+ * @throws BadPositionCategoryException
+ */
+ public void addPositionLast(String category, AddressRangePosition pos) throws BadPositionCategoryException {
+ @SuppressWarnings("unchecked")
+ List<AddressRangePosition> list = (List<AddressRangePosition>) getDocumentManagedPositions().get(category);
+ if (list == null) {
+ throw new BadPositionCategoryException();
+ }
+ int idx;
+ idx = computeIndexInPositionListLast(list, pos.fAddressOffset);
+ list.add(idx, pos);
+ }
+
+ /**
+ * @param pos
+ * @throws BadLocationException
+ */
+ public void addLabelPosition(AddressRangePosition pos) throws BadLocationException {
+ try {
+ addPositionLast(CATEGORY_LABELS, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ */
+ public void addSourcePosition(AddressRangePosition pos) throws BadLocationException {
+ try {
+ addPositionLast(CATEGORY_SOURCE, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ */
+ public void removeDisassemblyPosition(AddressRangePosition pos) {
+ try {
+ removePosition(CATEGORY_DISASSEMBLY, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ */
+ public void removeSourcePosition(AddressRangePosition pos) {
+ try {
+ removePosition(CATEGORY_SOURCE, pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ */
+ public void removeModelPosition(AddressRangePosition pos) {
+ try {
+ removePosition(getCategory(pos), pos);
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ }
+
+ /**
+ * @param pos
+ * @return
+ */
+ private static String getCategory(AddressRangePosition pos) {
+ if (pos instanceof LabelPosition) {
+ return CATEGORY_LABELS;
+ } else if (pos instanceof SourcePosition) {
+ return CATEGORY_SOURCE;
+ }
+ return CATEGORY_DISASSEMBLY;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.IDocument#removePosition(java.lang.String,
+ * org.eclipse.jface.text.Position)
+ */
+ @Override
+ public void removePosition(String category, Position position) throws BadPositionCategoryException {
+ super.removePosition(category, position);
+ if (category != CATEGORY_MODEL && position instanceof AddressRangePosition) {
+ super.removePosition(CATEGORY_MODEL, position);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void removePositions(String category, List<AddressRangePosition> toRemove) {
+ if (toRemove.isEmpty()) {
+ return;
+ }
+ List<Position> positions = (List<Position>) getDocumentManagedPositions().get(category);
+ if (positions != null) {
+ positions.removeAll(toRemove);
+ }
+ if (category != CATEGORY_MODEL) {
+ positions = (List<Position>) getDocumentManagedPositions().get(CATEGORY_MODEL);
+ if (positions != null) {
+ positions.removeAll(toRemove);
+ }
+ }
+ }
+
+ public void addPositionLast(String category, Position position) throws BadLocationException,
+ BadPositionCategoryException {
+
+ if ((0 > position.offset) || (0 > position.length) || (position.offset + position.length > getLength()))
+ throw new BadLocationException();
+
+ if (category == null)
+ throw new BadPositionCategoryException();
+
+ @SuppressWarnings("unchecked")
+ List<Position> list = (List<Position>) getDocumentManagedPositions().get(category);
+ if (list == null)
+ throw new BadPositionCategoryException();
+
+ list.add(computeIndexInPositionListLast(list, position.offset), position);
+ }
+
+ public void checkConsistency() {
+ AddressRangePosition last = null;
+ try {
+ for (Iterator<Position> it = getPositionIterator(CATEGORY_MODEL, 0); it.hasNext();) {
+ AddressRangePosition pos = (AddressRangePosition) it.next();
+ if (last != null) {
+ assert last.fAddressOffset.compareTo(pos.fAddressOffset) <= 0;
+ assert last.fAddressOffset.add(last.fAddressLength).compareTo(pos.fAddressOffset) == 0;
+ assert last.offset <= pos.offset;
+ assert last.offset + last.length == pos.offset;
+ }
+ last = pos;
+ }
+ } catch (BadPositionCategoryException e) {
+ assert false;
+ }
+ }
+
+ /**
+ * @param insertPos
+ * @param replaceLength
+ * @param text
+ * @throws BadLocationException
+ */
+ public void replace(AddressRangePosition insertPos, int replaceLength, String text) throws BadLocationException {
+ int delta = (text != null ? text.length() : 0) - replaceLength;
+ if (delta != 0) {
+ BigInteger address = insertPos.fAddressOffset;
+ Iterator<AddressRangePosition> it = getModelPositionIterator(address);
+ while (it.hasNext()) {
+ AddressRangePosition pos = it.next();
+ assert pos.fAddressOffset.compareTo(address) >= 0;
+ if (pos.fAddressOffset.compareTo(address) > 0) {
+ break;
+ }
+ if (pos.offset > insertPos.offset) {
+ break;
+ }
+ if (pos == insertPos) {
+ break;
+ }
+ }
+ while (it.hasNext()) {
+ AddressRangePosition pos = it.next();
+ pos.offset += delta;
+ }
+ }
+ super.replace(insertPos.offset, replaceLength, text);
+ }
+
+ /**
+ * @param pos
+ * @param insertPos
+ * @param line
+ * @throws BadPositionCategoryException
+ * @throws BadLocationException
+ */
+ public AddressRangePosition insertAddressRange(AddressRangePosition pos, AddressRangePosition insertPos, String line, boolean addToModel)
+ throws BadLocationException {
+ final BigInteger address = insertPos.fAddressOffset;
+ BigInteger length = insertPos.fAddressLength;
+ if (pos == null) {
+ pos = getPositionOfAddress(address);
+ }
+ assert !pos.isDeleted && !pos.fValid && (length.compareTo(BigInteger.ZERO) == 0 || pos.containsAddress(address));
+ int insertOffset;
+ int replaceLength = 0;
+ if (length.compareTo(BigInteger.ONE) > 0 && !pos.containsAddress(address.add(length.subtract(BigInteger.ONE)))) {
+ // merge with successor positions
+ Iterator<AddressRangePosition> it = getModelPositionIterator(pos.fAddressOffset.add(pos.fAddressLength));
+ assert it.hasNext();
+ do {
+ AddressRangePosition overlap = it.next();
+ BigInteger posEndAddress= pos.fAddressOffset.add(pos.fAddressLength);
+ assert pos.offset <= overlap.offset && overlap.fAddressOffset.compareTo(posEndAddress) == 0;
+ if (overlap instanceof LabelPosition || overlap instanceof SourcePosition) {
+ // don't override label or source positions, instead fix
+ // length of disassembly line to insert
+ length = insertPos.fAddressLength = posEndAddress.subtract(address.max(pos.fAddressOffset));
+ break;
+ }
+ pos.fAddressLength = pos.fAddressLength.add(overlap.fAddressLength);
+ replaceLength = overlap.offset + overlap.length - pos.offset - pos.length;
+ it.remove();
+ removeModelPosition(overlap);
+ if (!overlap.fValid) {
+ fInvalidAddressRanges.remove(overlap);
+ }
+ } while(!pos.containsAddress(address.add(length.subtract(BigInteger.ONE))));
+ }
+ BigInteger newEndAddress = pos.fAddressOffset.add(pos.fAddressLength);
+ BigInteger newStartAddress = address.add(length);
+ assert newEndAddress.compareTo(newStartAddress) >= 0;
+ if (address.compareTo(pos.fAddressOffset) == 0) {
+ // insert at start of range
+ insertOffset = pos.offset;
+ if (replaceLength == 0 && newEndAddress.compareTo(newStartAddress) > 0) {
+ // optimization: shrink position in place
+ pos.fAddressOffset = newStartAddress;
+ pos.fAddressLength = pos.fAddressLength.subtract(length);
+ // don't insert new pos
+ newEndAddress = newStartAddress;
+ } else {
+ replaceLength += pos.length;
+ fInvalidAddressRanges.remove(pos);
+ removeDisassemblyPosition(pos);
+ pos = null;
+ }
+ } else {
+ // insert in mid/end of range
+ insertOffset = pos.offset + pos.length;
+ pos.fAddressLength = address.subtract(pos.fAddressOffset);
+ assert pos.fAddressLength.compareTo(BigInteger.ZERO) > 0;
+ pos = null;
+ }
+ if (newEndAddress.compareTo(newStartAddress) > 0) {
+ pos = insertInvalidAddressRange(insertOffset+replaceLength, 0, newStartAddress, newEndAddress);
+ }
+ assert pos == null || pos.fAddressLength.compareTo(BigInteger.ZERO) > 0 && pos.containsAddress(address.add(length));
+ assert insertOffset + replaceLength <= getLength();
+
+ insertPos.offset = insertOffset;
+ if (addToModel) {
+ addModelPosition(insertPos);
+ }
+ replace(insertPos, replaceLength, line);
+ if (DEBUG) checkConsistency();
+ return pos;
+ }
+
+ /**
+ * @param pos
+ * @param address
+ * @param length
+ * @param instruction
+ * @throws BadPositionCategoryException
+ * @throws BadLocationException
+ */
+ public AddressRangePosition insertDisassemblyLine(AddressRangePosition pos, BigInteger address, int length, String opcode, String instruction, String file, int lineNr)
+ throws BadLocationException {
+ String disassLine = null;
+ if (instruction == null || instruction.length() == 0) {
+ disassLine = ""; //$NON-NLS-1$
+ } else {
+ disassLine = buildDisassemblyLine(address, opcode, instruction);
+ }
+ AddressRangePosition disassPos;
+ if (lineNr < 0) {
+ disassPos = new DisassemblyPosition(0, disassLine.length(), address, BigInteger.valueOf(length), opcode);
+ } else {
+ disassPos = new DisassemblyWithSourcePosition(0, disassLine.length(), address, BigInteger.valueOf(length),
+ opcode, file, lineNr);
+ }
+ pos = insertAddressRange(pos, disassPos, disassLine, true);
+ addDisassemblyPosition(disassPos);
+ return pos;
+ }
+ /**
+ * @param address
+ * @param opcode
+ * @param instruction
+ */
+ private String buildDisassemblyLine(BigInteger address, String opcode, String instruction) {
+ StringBuffer buf = new StringBuffer(40);
+ if (fShowAddresses) {
+ if (fRadixPrefix != null) {
+ buf.append(fRadixPrefix);
+ }
+ String str = address.toString(fRadix);
+ for (int i=str.length(); i<fNumberOfDigits; ++i)
+ buf.append('0');
+ buf.append(str);
+ buf.append(':');
+ buf.append(' ');
+ }
+ if (fShowCodeBytes && opcode != null && opcode.length() > 0) {
+ buf.append(opcode);
+ int tab = 16;
+ if (opcode.length() >= 16) {
+ tab = (opcode.length() + 8) & ~7;
+ }
+ int diff = tab - opcode.length();
+ while (diff-- > 0) {
+ buf.append(' ');
+ }
+ } else if (!fShowAddresses) {
+ buf.append(' ');
+ buf.append(' ');
+ }
+ int n = instruction.length();
+ int prefixLen = buf.length();
+ for (int j = 0; j < n; j++) {
+ char ch = instruction.charAt(j);
+ if (ch == '\t') {
+ int tab = (buf.length()-prefixLen + 8) & ~0x7;
+ do
+ buf.append(' ');
+ while (buf.length()-prefixLen < tab);
+ } else {
+ buf.append(ch);
+ }
+ }
+ buf.append('\n');
+ return buf.toString();
+ }
+
+ public void setRadix(int radix) {
+ fRadix = radix;
+ fNumberOfDigits = (int)(Math.log(1L<<32)/Math.log(radix)+0.9);
+ setShowRadixPrefix(fShowRadixPrefix);
+ }
+
+ public void setShowRadixPrefix(boolean showRadixPrefix) {
+ fShowRadixPrefix = showRadixPrefix;
+ if (!fShowRadixPrefix) {
+ fRadixPrefix = null;
+ } else if (fRadix == 16) {
+ fRadixPrefix = "0x"; //$NON-NLS-1$
+ } else if (fRadix == 8) {
+ fRadixPrefix = "0"; //$NON-NLS-1$
+ } else {
+ fRadixPrefix = null;
+ }
+ }
+
+ public AddressRangePosition insertErrorLine(AddressRangePosition pos, BigInteger address, BigInteger length, String line)
+ throws BadLocationException {
+ int hashCode = line.hashCode();
+ final long alignment = 0x1L;
+ if (alignment > 1 && !(pos instanceof ErrorPosition)) {
+ AddressRangePosition before = getPositionOfAddress(address.subtract(BigInteger.ONE));
+ if (before instanceof ErrorPosition && before.hashCode() == hashCode && before.offset + before.length == pos.offset) {
+ assert before.fAddressOffset.add(before.fAddressLength).compareTo(address) == 0;
+ assert pos.fAddressOffset.compareTo(address) == 0;
+ // merge with previous error position
+ BigInteger pageOffset = before.fAddressOffset.and(BigInteger.valueOf(~(alignment-1)));
+ BigInteger mergeLen = pageOffset.add(BigInteger.valueOf(alignment))
+ .subtract((before.fAddressOffset.add(before.fAddressLength))).min(length);
+ if (mergeLen.compareTo(BigInteger.ZERO) > 0) {
+ pos.fAddressLength = pos.fAddressLength.subtract(mergeLen);
+ if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) {
+ replace(pos, pos.length, null);
+ removeModelPosition(pos);
+ fInvalidAddressRanges.remove(pos);
+ pos = null;
+ } else {
+ pos.fAddressOffset = pos.fAddressOffset.add(mergeLen);
+ }
+ before.fAddressLength = before.fAddressLength.add(mergeLen);
+ address = address.add(mergeLen);
+ length = length.subtract(mergeLen);
+ if (DEBUG) checkConsistency();
+ if (length.compareTo(BigInteger.ZERO) == 0) {
+ return pos;
+ }
+ }
+ }
+ AddressRangePosition after = getPositionOfAddress(address.add(length));
+ if (after instanceof ErrorPosition && after.hashCode() == hashCode && pos.offset + pos.length == after.offset) {
+ assert after.fAddressOffset == address.add(length);
+ assert pos.fAddressOffset.add(pos.fAddressLength).compareTo(after.fAddressOffset) == 0;
+ // merge with next error position
+ BigInteger pageOffset = after.fAddressOffset.add(BigInteger.valueOf(~(alignment-1)));
+ BigInteger mergeLen = after.fAddressOffset.subtract(pageOffset).min(length);
+ if (mergeLen.compareTo(BigInteger.ZERO) > 0) {
+ after.fAddressOffset = after.fAddressOffset.subtract(mergeLen);
+ after.fAddressLength = after.fAddressLength.add(mergeLen);
+ pos.fAddressLength = pos.fAddressLength.subtract(mergeLen);
+ if (pos.fAddressLength.compareTo(BigInteger.ZERO) == 0) {
+ replace(pos, pos.length, null);
+ removeModelPosition(pos);
+ fInvalidAddressRanges.remove(pos);
+ pos = null;
+ }
+ if (DEBUG) checkConsistency();
+ length = length.subtract(mergeLen);
+ if (length.compareTo(BigInteger.ZERO) == 0) {
+ return pos;
+ }
+ }
+ }
+ }
+ BigInteger pageOffset = address.and(BigInteger.valueOf(~(alignment-1)));
+ BigInteger posLen = pageOffset.add(BigInteger.valueOf(alignment)).subtract(address).min(length);
+ while (length.compareTo(BigInteger.ZERO) > 0) {
+ AddressRangePosition errorPos = new ErrorPosition(0, 0, address, posLen, hashCode);
+ String errorLine = buildDisassemblyLine(address, null, line);
+ // TLEHACK: check for error messages, which occur only temporarily:
+ // "Target is busy. Try again later"
+ // "Cannot Perform requested Operation"
+ if (line.startsWith("Target is busy") || line.startsWith("Cannot perform")) { //$NON-NLS-1$ //$NON-NLS-2$
+ // try again only once...
+ if (!(pos instanceof ErrorPosition)) {
+ errorLine = "...\n"; //$NON-NLS-1$
+ errorPos.fValid = false;
+ }
+ }
+ errorPos.length = errorLine.length();
+ pos = insertAddressRange(pos, errorPos, errorLine, true);
+ addDisassemblyPosition(errorPos);
+ if (!errorPos.fValid) {
+ fInvalidAddressRanges.add(errorPos);
+ }
+ length = length.subtract(posLen);
+ address = address.add(posLen);
+ posLen = BigInteger.valueOf(alignment).min(length);
+ }
+ return pos;
+ }
+
+ /**
+ * @param pos
+ * @param address
+ * @param label
+ * @throws BadLocationException
+ * @throws BadPositionCategoryException
+ */
+ public AddressRangePosition insertLabel(AddressRangePosition pos, BigInteger address, String label, boolean showLabels)
+ throws BadLocationException {
+ String labelLine = showLabels ? label + ":\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$
+ LabelPosition labelPos = getLabelPosition(address);
+ if (labelPos != null) {
+ assert labelPos.fAddressOffset.compareTo(address) == 0;
+ if (labelPos.length != labelLine.length()) {
+ int oldLength = labelPos.length;
+ labelPos.length = labelLine.length();
+ replace(labelPos, oldLength, labelLine);
+ }
+ return pos;
+ }
+ labelPos = new LabelPosition(0, labelLine.length(), address, null);
+ pos = insertAddressRange(pos, labelPos, labelLine, true);
+ addLabelPosition(labelPos);
+ return pos;
+ }
+
+ /**
+ * @param pos
+ * @param address
+ * @param source
+ * @param line
+ * @param endOfSource
+ * @throws BadLocationException
+ * @throws BadPositionCategoryException
+ */
+ public SourcePosition insertSource(SourcePosition pos, String source, int line, boolean endOfSource) {
+// System.out.println("insertSource at "+getAddressText(pos.fAddressOffset));
+// System.out.println(source);
+ String sourceLines = source;
+ if (source.length() > 0 && sourceLines.charAt(source.length() - 1) != '\n') {
+ sourceLines += "\n"; //$NON-NLS-1$
+ }
+ try {
+ assert !pos.fValid;
+ int oldLength = pos.length;
+ pos.length = sourceLines.length();
+ pos.fLine = line;
+ pos.fValid = true;
+ fInvalidSource.remove(pos);
+ replace(pos, oldLength, sourceLines);
+ if (!endOfSource) {
+ if (pos.length > 0) {
+ SourcePosition oldPos = getSourcePosition(pos.offset+pos.length);
+ if (oldPos == null || oldPos.fAddressOffset.compareTo(pos.fAddressOffset) != 0) {
+ pos = new SourcePosition(pos.offset+pos.length, 0, pos.fAddressOffset, pos.fFileInfo, line, false);
+ addSourcePosition(pos);
+ addModelPosition(pos);
+ fInvalidSource.add(pos);
+ } else {
+ //TLETODO need more checks for correct source pos
+ pos = oldPos;
+ }
+ }
+ }
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ return pos;
+ }
+
+ /**
+ * @param pos
+ * @param address
+ * @param fi
+ * @param lineNr
+ * @return
+ */
+ public AddressRangePosition insertInvalidSource(AddressRangePosition pos, BigInteger address, SourceFileInfo fi, int lineNr) {
+ SourcePosition sourcePos = getSourcePosition(address);
+ if (sourcePos != null) {
+ return pos;
+ }
+ String sourceLine = ""; //$NON-NLS-1$
+ sourcePos = new SourcePosition(0, sourceLine.length(), address, fi, lineNr, false);
+ try {
+ pos = insertAddressRange(pos, sourcePos, sourceLine, true);
+ addSourcePosition(sourcePos);
+ assert !fInvalidSource.contains(sourcePos);
+ fInvalidSource.add(sourcePos);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ return pos;
+ }
+
+ /**
+ * @param offset
+ * @param replaceLength
+ * @param startAddress
+ * @param endAddress
+ * @return
+ */
+ public AddressRangePosition insertInvalidAddressRange(int offset, int replaceLength, BigInteger startAddress, BigInteger endAddress) {
+ String periods = "...\n"; //$NON-NLS-1$
+ AddressRangePosition newPos = new AddressRangePosition(offset, periods.length(), startAddress, endAddress
+ .subtract(startAddress), false);
+ try {
+ addModelPositionFirst(newPos);
+ replace(newPos, replaceLength, periods);
+ addDisassemblyPosition(newPos);
+ fInvalidAddressRanges.add(newPos);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ return newPos;
+ }
+
+ public void invalidateAddressRange(BigInteger startAddress, BigInteger endAddress, boolean collapse) {
+ deleteDisassemblyRange(startAddress, endAddress, true, collapse);
+ }
+
+ public void deleteDisassemblyRange(BigInteger startAddress, BigInteger endAddress, boolean invalidate, boolean collapse) {
+ String replacement = invalidate ? "...\n" : null; //$NON-NLS-1$
+ int replaceLen = replacement != null ? replacement.length() : 0;
+ AddressRangePosition lastPos = null;
+ ArrayList<AddressRangePosition> toRemove = new ArrayList<AddressRangePosition>();
+ Iterator<AddressRangePosition> it = getModelPositionIterator(startAddress);
+ while (it.hasNext()) {
+ AddressRangePosition pos = it.next();
+ BigInteger posEndAddress = pos.fAddressOffset.add(pos.fAddressLength);
+ if (pos instanceof LabelPosition) {
+ if (!invalidate && pos.length > 0 && posEndAddress.compareTo(endAddress) > 0) {
+ try {
+ int oldLength = pos.length;
+ pos.length = 0;
+ replace(pos, oldLength, null);
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ }
+ pos = null;
+ } else if (pos instanceof SourcePosition) {
+ pos = null;
+ } else if (pos instanceof ErrorPosition) {
+ pos = null;
+ } else if (pos instanceof DisassemblyPosition) {
+ // optimization: join adjacent positions
+ if (collapse && lastPos != null
+ && (invalidate || lastPos.fValid == pos.fValid)
+ && lastPos.offset+lastPos.length == pos.offset) {
+ assert lastPos.fAddressOffset.add(lastPos.fAddressLength).compareTo(pos.fAddressOffset) == 0;
+ lastPos.length += pos.length;
+ lastPos.fAddressLength = lastPos.fAddressLength.add(pos.fAddressLength);
+ toRemove.add(pos);
+ if (!pos.fValid) {
+ fInvalidAddressRanges.remove(pos);
+ }
+ pos = null;
+ if (posEndAddress.compareTo(endAddress) < 0) {
+ continue;
+ }
+ }
+ }
+ if (lastPos != null) {
+ try {
+ if (lastPos.length > 0 || replaceLen > 0) {
+ int oldLength = lastPos.length;
+ lastPos.length = replaceLen;
+ replace(lastPos, oldLength, replacement);
+ }
+ } catch (BadLocationException e) {
+ internalError(e);
+ }
+ }
+ if (pos == null && posEndAddress.compareTo(endAddress) >= 0) {
+ break;
+ }
+ lastPos = null;
+ if (pos != null) {
+ if (pos.fValid && invalidate) {
+ pos.fValid = false;
+ fInvalidAddressRanges.add(pos);
+ }
+ lastPos = pos;
+ }
+ }
+ removePositions(CATEGORY_DISASSEMBLY, toRemove);
+ if (DEBUG) checkConsistency();
+ }
+
+ public void invalidateSource() {
+ Iterator<Position> it;
+ try {
+ it = getPositionIterator(CATEGORY_SOURCE, 0);
+ } catch (BadPositionCategoryException e) {
+ internalError(e);
+ return;
+ }
+ while (it.hasNext()) {
+ SourcePosition srcPos = (SourcePosition)it.next();
+ if (srcPos != null && srcPos.fValid) {
+ srcPos.fValid = false;
+ assert !getInvalidSource().contains(srcPos);
+ getInvalidSource().add(srcPos);
+ }
+ }
+ }
+
+ public void invalidateDisassemblyWithSource(boolean removeDisassembly) {
+ for (Iterator<SourceFileInfo> it = fFileInfoMap.values().iterator(); it.hasNext();) {
+ SourceFileInfo info = it.next();
+ if (info.fLine2Addr != null) {
+ deleteDisassemblyRange(info.fStartAddress, info.fEndAddress.add(BigInteger.ONE), !removeDisassembly, !removeDisassembly);
+ }
+ }
+ }
+
+ /**
+ * @param start
+ * @param end
+ * @throws BadLocationException
+ */
+ public void deleteLineRange(int start, int end) throws BadLocationException {
+ if (start >= end) {
+ return;
+ }
+ int startOffset = getLineOffset(start);
+ int endOffset = getLineOffset(end);
+ int replaceLength = 0;
+ AddressRangePosition startPos = getDisassemblyPosition(startOffset);
+ if (startPos == null) {
+ return;
+ }
+ startOffset = startPos.offset;
+ AddressRangePosition endPos = getDisassemblyPosition(endOffset);
+ if (endPos == null) {
+ return;
+ }
+ BigInteger startAddress = BigInteger.ZERO;
+ BigInteger addressLength = BigInteger.ZERO;
+ ArrayList<AddressRangePosition> toRemove = new ArrayList<AddressRangePosition>();
+ try {
+ Iterator<AddressRangePosition> it = getPositionIterator(DisassemblyDocument.CATEGORY_MODEL, startAddress);
+ while (it.hasNext()) {
+ AddressRangePosition p = it.next();
+ addressLength = addressLength.add(p.fAddressLength);
+ replaceLength += p.length;
+ toRemove.add(p);
+ if (!p.fValid) {
+ if (p instanceof SourcePosition) {
+ getInvalidSource().remove(p);
+ } else {
+ getInvalidAddressRanges().remove(p);
+ }
+ }
+ if (addressLength.compareTo(BigInteger.ZERO) > 0 && p.fAddressOffset.compareTo(endPos.fAddressOffset) >= 0) {
+ break;
+ }
+ }
+ } catch (BadPositionCategoryException e) {
+ // cannot happen
+ }
+ for (Iterator<AddressRangePosition> iter = toRemove.iterator(); iter.hasNext();) {
+ AddressRangePosition pos = iter.next();
+ removeModelPosition(pos);
+ }
+ if (addressLength.compareTo(BigInteger.ZERO) > 0) {
+ insertInvalidAddressRange(startOffset, replaceLength, startAddress, startAddress.add(addressLength));
+ }
+ }
+
+ public SourceFileInfo getSourceInfo(BigInteger address) {
+ AddressRangePosition pos = getDisassemblyPosition(address);
+ if (pos instanceof DisassemblyPosition) {
+ DisassemblyPosition disassPos = (DisassemblyPosition)pos;
+ return getSourceInfo(disassPos.getFile());
+ }
+ return null;
+ }
+
+ public SourceFileInfo getSourceInfo(String file) {
+ if (fFileInfoMap == null || file == null) {
+ return null;
+ }
+ for (Iterator<SourceFileInfo> iter = fFileInfoMap.values().iterator(); iter.hasNext();) {
+ SourceFileInfo info = iter.next();
+ if (file.equals(info.fFileKey)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ public SourceFileInfo getSourceInfo(IStorage sourceElement) {
+ if (fFileInfoMap == null) {
+ return null;
+ }
+ SourceFileInfo fi = fFileInfoMap.get(sourceElement);
+ return fi;
+ }
+
+ public SourceFileInfo createSourceInfo(String fileKey, IStorage sourceElement, Runnable done) {
+ SourceFileInfo fi = new SourceFileInfo(fileKey, sourceElement);
+ assert fFileInfoMap != null;
+ if (fFileInfoMap != null) {
+ fFileInfoMap.put(sourceElement, fi);
+ new SourceReadingJob(fi, done);
+ }
+ return fi;
+ }
+
+ private void internalError(Throwable e) {
+ if (DEBUG) {
+ System.err.println("Disassembly: Internal error"); //$NON-NLS-1$
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java
new file mode 100644
index 00000000000..d07f699353a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyPosition.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+/**
+ * DisassemblyPosition
+ */
+public class DisassemblyPosition extends AddressRangePosition {
+
+ public char[] fFunction;
+
+ /**
+ *
+ * @param offset
+ * @param length
+ * @param addressOffset
+ * @param addressLength
+ * @param opcodes
+ */
+ public DisassemblyPosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, String opcodes) {
+ super(offset, length, addressOffset, addressLength);
+ fFunction = opcodes.toCharArray();
+ }
+
+ /**
+ * @return source file
+ */
+ public String getFile() {
+ return null;
+ }
+
+ /**
+ * @return source line number
+ */
+ public int getLine() {
+ return -1;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java
new file mode 100644
index 00000000000..3b466857f28
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/DisassemblyWithSourcePosition.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+/**
+ * DisassemblyWithSourcePosition
+ */
+public class DisassemblyWithSourcePosition extends DisassemblyPosition {
+
+ private String fFile;
+ private int fLine;
+
+ /**
+ * @param offset
+ * @param length
+ * @param addressOffset
+ * @param addressLength
+ * @param opcodes
+ */
+ public DisassemblyWithSourcePosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, String opcodes, String file, int lineNr) {
+ super(offset, length, addressOffset, addressLength, opcodes);
+ fFile = file;
+ fLine = lineNr;
+ }
+
+ @Override
+ public String getFile() {
+ return fFile;
+ }
+
+ @Override
+ public int getLine() {
+ return fLine;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java
new file mode 100644
index 00000000000..3e47f0783c9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/ErrorPosition.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+/**
+ * ErrorPosition
+ */
+public class ErrorPosition extends AddressRangePosition {
+
+ public int fHashCode;
+
+ /**
+ * @param offset
+ * @param length
+ * @param addressOffset
+ * @param addressLength
+ */
+ public ErrorPosition(int offset, int length, BigInteger addressOffset, BigInteger addressLength, int hashCode) {
+ super(offset, length, addressOffset, addressLength);
+ fHashCode = hashCode;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return fHashCode;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/LabelPosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/LabelPosition.java
new file mode 100644
index 00000000000..5dbaea989c0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/LabelPosition.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+/**
+ * LabelPosition
+ */
+public class LabelPosition extends AddressRangePosition {
+
+ public String fLabel;
+
+ /**
+ * @param offset
+ * @param length
+ * @param addressOffset
+ */
+ public LabelPosition(int offset, int length, BigInteger addressOffset, String label) {
+ super(offset, length, addressOffset, BigInteger.ZERO);
+ fLabel = label;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java
new file mode 100644
index 00000000000..152566bed25
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceDocumentProvider.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.util.Iterator;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text.REDDocument;
+import org.eclipse.cdt.internal.ui.editor.CDocumentSetupParticipant;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFileState;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.ui.IStorageEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.editors.text.StorageDocumentProvider;
+
+/**
+ * SourceDocumentProvider
+ */
+@SuppressWarnings("restriction")
+public class SourceDocumentProvider extends StorageDocumentProvider {
+
+ public SourceDocumentProvider() {
+ super();
+ }
+
+ /**
+ * Dispose all connected documents.
+ */
+ public void dispose() {
+ Iterator<?> it = getConnectedElements();
+ while(it.hasNext()) {
+ Object element = it.next();
+ ElementInfo info = getElementInfo(element);
+ // force refcount to 1
+ info.fCount = 1;
+ disconnect(element);
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#createDocument(java.lang.Object)
+ */
+ @Override
+ protected IDocument createEmptyDocument() {
+ IDocument doc = new REDDocument();
+ return doc;
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#createAnnotationModel(java.lang.Object)
+ */
+ @Override
+ protected IAnnotationModel createAnnotationModel(Object element) throws CoreException {
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.ui.editors.text.StorageDocumentProvider#setupDocument(java.lang.Object, org.eclipse.jface.text.IDocument)
+ */
+ @Override
+ protected void setupDocument(Object element, IDocument document) {
+ super.setupDocument(element, document);
+ if (element instanceof IStorageEditorInput) {
+ new CDocumentSetupParticipant().setup(document);
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#disposeElementInfo(java.lang.Object, org.eclipse.ui.texteditor.AbstractDocumentProvider.ElementInfo)
+ */
+ @Override
+ protected void disposeElementInfo(Object element, ElementInfo info) {
+ super.disposeElementInfo(element, info);
+ IDocument doc = info.fDocument;
+ if (doc instanceof REDDocument) {
+ ((REDDocument)doc).dispose();
+ }
+ }
+
+ /*
+ * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#getModificationStamp(java.lang.Object)
+ */
+ @Override
+ public long getModificationStamp(Object element) {
+ try {
+ if (element instanceof IStorageEditorInput) {
+ IStorage file= ((IStorageEditorInput)element).getStorage();
+ if (file instanceof IFile) {
+ return ((IFile)file).getLocalTimeStamp();
+ } else if (file instanceof IFileState) {
+ return ((IFileState)file).getModificationTime();
+ } else if (file instanceof LocalFileStorage) {
+ return ((LocalFileStorage)file).getFile().lastModified();
+ }
+ } else if (element instanceof IURIEditorInput) {
+ return EFS.getStore(((IURIEditorInput)element).getURI()).fetchInfo().getLastModified();
+ }
+ } catch (CoreException e) {
+ // ignore
+ }
+ return 0;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java
new file mode 100644
index 00000000000..8980e78c637
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceEditorInput.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.util.StorageEditorInput;
+import org.eclipse.core.resources.IStorage;
+
+/**
+ * SourceEditorInput
+ */
+public class SourceEditorInput extends StorageEditorInput {
+
+ /**
+ * @param storage
+ */
+ public SourceEditorInput(IStorage storage) {
+ super(storage);
+ }
+
+ /*
+ * @see org.eclipse.ui.IEditorInput#exists()
+ */
+ public boolean exists() {
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java
new file mode 100644
index 00000000000..f433228e9c4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceFileInfo.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.LanguageManager;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.ISourcePresentationCreator;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.SourcePresentationCreatorFactory;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.content.IContentType;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.ui.IEditorInput;
+
+/**
+ * Holds information about a source file.
+ */
+public class SourceFileInfo {
+ public final String fFileKey;
+ public final IStorage fFile;
+ public IStorage fEdition;
+ public BigInteger[] fLine2Addr;
+ public Addr2Line[] fAddr2Line;
+ public volatile IDocument fSource;
+ public volatile boolean fValid;
+ public Object fLinesNode;
+ public Throwable fError;
+ public volatile SourceReadingJob fReadingJob;
+ public volatile Job fEditionJob;
+ public ISourcePresentationCreator fPresentationCreator;
+ public BigInteger fStartAddress = BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE);
+ public BigInteger fEndAddress= BigInteger.ZERO;
+
+ public SourceFileInfo(String fileKey, IStorage file) {
+ fFileKey = fileKey;
+ fFile = fEdition = file;
+ }
+
+ /**
+ * Initialize source document.
+ * @throws CoreException
+ */
+ public void initSource() throws CoreException {
+ SourceDocumentProvider provider = DsfUIPlugin.getSourceDocumentProvider();
+ IEditorInput input = new SourceEditorInput(fEdition);
+ synchronized (provider) {
+ provider.connect(input);
+ }
+ IStatus status = provider.getStatus(input);
+ if (status != null && !status.isOK()) {
+ throw new CoreException(status);
+ }
+ }
+
+ /**
+ * Initialize presentation creator.
+ * @param viewer
+ */
+ public void initPresentationCreator(ITextViewer viewer) {
+ SourceDocumentProvider provider = DsfUIPlugin.getSourceDocumentProvider();
+ IEditorInput input = new SourceEditorInput(fEdition);
+ IDocument doc = provider.getDocument(input);
+ if (doc != null) {
+ IContentType contentType= null;
+ if (fEdition instanceof IFile) {
+ IFile file= (IFile)fEdition;
+ contentType= CCorePlugin.getContentType(file.getProject(), file.getName());
+ } else {
+ contentType= CCorePlugin.getContentType(fEdition.getName());
+ }
+ ILanguage language= null;
+ if (contentType != null) {
+ language= LanguageManager.getInstance().getLanguage(contentType);
+ }
+ if (language != null) {
+ fPresentationCreator= SourcePresentationCreatorFactory.create(language, fEdition, viewer);
+ }
+ int lines = doc.getNumberOfLines();
+ fLine2Addr = new BigInteger[lines];
+ fAddr2Line = new Addr2Line[lines / 10 + 1];
+ // assign fSource last, triggering source update
+ fSource = doc;
+ }
+ }
+
+ /**
+ * Dispose this object.
+ */
+ public void dispose() {
+ if (fReadingJob != null) {
+ if (!fReadingJob.cancel()) {
+ fReadingJob.dispose();
+ }
+ fReadingJob = null;
+ }
+ if (fPresentationCreator != null) {
+ fPresentationCreator.dispose();
+ fPresentationCreator = null;
+ }
+ SourceDocumentProvider provider = DsfUIPlugin.getSourceDocumentProvider();
+ synchronized (provider) {
+ provider.disconnect(new SourceEditorInput(fEdition));
+ }
+ fSource = null;
+ fValid = false;
+// fLinesNode = null;
+ }
+
+ public String getLine(int lineNr) {
+ return getLines(lineNr, lineNr);
+ }
+
+ public String getLines(int first, int last) {
+ try {
+ int startOffset = fSource.getLineOffset(first);
+ int endOffset;
+ if (last < fSource.getNumberOfLines()-1) {
+ IRegion lastRegion = fSource.getLineInformation(last+1);
+ endOffset = lastRegion.getOffset();
+ } else {
+ // last line
+ IRegion lastRegion = fSource.getLineInformation(last);
+ endOffset = lastRegion.getOffset() + lastRegion.getLength();
+ }
+ return fSource.get(startOffset, endOffset - startOffset);
+ } catch (BadLocationException e) {
+ return null;
+ }
+ }
+
+ public IRegion getRegion(int line, int length) {
+ try {
+ IRegion lineRegion = fSource.getLineInformation(line);
+ return new Region(lineRegion.getOffset(), length);
+ } catch (BadLocationException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get or create text presentation for the given region.
+ * Must be called in display thread.
+ * @param region
+ * @return text presentation
+ */
+ public TextPresentation getPresentation(IRegion region) {
+ if (fSource != null && fPresentationCreator != null) {
+ return fPresentationCreator.getPresentation(region, fSource);
+ }
+ return null;
+ }
+
+ /**
+ * @return offset of given line
+ */
+ public int getLineOffset(int line) {
+ if (fSource != null) {
+ try {
+ return fSource.getLineOffset(line);
+ } catch (BadLocationException e) {
+ // ignored
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourcePosition.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourcePosition.java
new file mode 100644
index 00000000000..f5138df554b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourcePosition.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import java.math.BigInteger;
+
+/**
+ * SourcePosition
+ */
+public class SourcePosition extends AddressRangePosition {
+
+ public SourceFileInfo fFileInfo;
+ public int fLine;
+
+ /**
+ *
+ * @param offset
+ * @param length
+ * @param addressOffset
+ * @param fileInfo
+ * @param line
+ */
+ public SourcePosition(int offset, int length, BigInteger addressOffset, SourceFileInfo fileInfo, int line) {
+ this(offset, length, addressOffset, fileInfo, line, true);
+ }
+
+ /**
+ *
+ * @param offset
+ * @param length
+ * @param addressOffset
+ * @param fileInfo
+ * @param line
+ * @param valid
+ */
+ public SourcePosition(int offset, int length, BigInteger addressOffset, SourceFileInfo fileInfo, int line, boolean valid) {
+ super(offset, length, addressOffset, BigInteger.ZERO, valid);
+ fFileInfo = fileInfo;
+ fLine = line;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java
new file mode 100644
index 00000000000..2fb06aa1d53
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/model/SourceReadingJob.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.model;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+
+
+/**
+ * Low-level job to read source files in the background.
+ */
+public class SourceReadingJob extends Job {
+
+ private final static String NAME = DisassemblyMessages.SourceReadingJob_name;
+
+ private SourceFileInfo fFileInfo;
+ private Runnable fDone;
+
+ public SourceReadingJob(SourceFileInfo fi, Runnable done) {
+ super(NAME);
+ fFileInfo = fi;
+ fFileInfo.fReadingJob = this;
+ fDone = done;
+ if (fi.fFile instanceof ISchedulingRule) {
+ setRule((ISchedulingRule)fi.fFile);
+ }
+ setSystem(true);
+ // usually short lived job
+ setPriority(SHORT);
+ if (fi.fFile.getFullPath() != null) {
+ String fileName = fi.fFile.getFullPath().lastSegment();
+ setName(NAME + " (" + fileName + ')'); //$NON-NLS-1$
+ }
+ }
+
+ public synchronized void dispose() {
+ fDone = null;
+ Thread thread = getThread();
+ if (thread != null && thread.isAlive()) {
+ thread.interrupt();
+ }
+ }
+
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ if (fFileInfo.fEditionJob != null) {
+ try {
+ fFileInfo.fEditionJob.join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ try {
+ fFileInfo.initSource();
+ } catch (Throwable e) {
+ fFileInfo.fError = e;
+ } finally {
+ fFileInfo.fReadingJob = null;
+ synchronized (this) {
+ if (fDone != null && !getThread().isInterrupted()) {
+ fDone.run();
+ }
+ }
+ }
+ // errors are handled elsewhere
+ return Status.OK_STATUS;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java
new file mode 100644
index 00000000000..e06a20dd61b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferenceConstants.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.preferences;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.editors.text.TextEditorPreferenceConstants;
+
+/**
+ * DisassemblyPreferenceConstants
+ */
+public class DisassemblyPreferenceConstants {
+
+ public static final String START_ADDRESS = "disassembly.startAddress"; //$NON-NLS-1$
+ public static final String END_ADDRESS = "disassembly.endAddress"; //$NON-NLS-1$
+ public static final String PC_HISTORY_SIZE = "disassembly.pcHistorySize"; //$NON-NLS-1$
+ public static final String SHOW_SOURCE = "disassembly.showSource"; //$NON-NLS-1$
+ public static final String SHOW_LABELS = "disassembly.showLabels"; //$NON-NLS-1$
+ public static final String SHOW_SYMBOLS = "disassembly.showSymbols"; //$NON-NLS-1$
+ public static final String SIMPLIFIED = "disassembly.simplified"; //$NON-NLS-1$
+ public static final String INSTRUCTION_RADIX = "disassembly.instructionRadix"; //$NON-NLS-1$
+ public static final String ADDRESS_RADIX = "disassembly.addressRadix"; //$NON-NLS-1$
+ public static final String SHOW_ADDRESS_RADIX = "disassembly.showAddressRadix"; //$NON-NLS-1$
+ public static final String SHOW_ADDRESS_RULER = "disassembly.showAddressRuler"; //$NON-NLS-1$
+ public static final String ADDRESS_COLOR = "disassembly.addressColor"; //$NON-NLS-1$
+ public static final String SHOW_FUNCTION_OFFSETS = "disassembly.showFunctionOffsetRuler"; //$NON-NLS-1$
+ public static final String OPCODE_COLOR = "disassembly.opcodeColor"; //$NON-NLS-1$
+ public static final String USE_SOURCE_ONLY_MODE = "disassembly.useSourceOnlyMode"; //$NON-NLS-1$
+ public static final String AVOID_READ_BEFORE_PC = "disassembly.avoidReadBeforePC"; //$NON-NLS-1$
+
+ /**
+ *
+ */
+ private DisassemblyPreferenceConstants() {
+ // not intended to be subclassed or instatiated
+ }
+
+ /**
+ * Initialize preference default values.
+ * @param store
+ */
+ public static void initializeDefaults(IPreferenceStore store) {
+ TextEditorPreferenceConstants.initializeDefaultValues(store);
+ store.setDefault(START_ADDRESS, 0x0L);
+ store.setDefault(END_ADDRESS, "0x" + BigInteger.ONE.shiftLeft(64).toString(16)); //$NON-NLS-1$
+ store.setDefault(PC_HISTORY_SIZE, 4);
+ store.setDefault(SHOW_SOURCE, true);
+ store.setDefault(SHOW_FUNCTION_OFFSETS, false);
+ store.setDefault(SHOW_LABELS, true);
+ store.setDefault(SHOW_SYMBOLS, true);
+ store.setDefault(SIMPLIFIED, true);
+ store.setDefault(INSTRUCTION_RADIX, 16);
+ store.setDefault(ADDRESS_RADIX, 16);
+ store.setDefault(SHOW_ADDRESS_RADIX, false);
+ store.setDefault(SHOW_ADDRESS_RULER, true);
+ store.setDefault(AVOID_READ_BEFORE_PC, false);
+ store.setDefault(USE_SOURCE_ONLY_MODE, false);
+ PreferenceConverter.setDefault(store, ADDRESS_COLOR, new RGB(0, 96, 0));
+ PreferenceConverter.setDefault(store, OPCODE_COLOR, new RGB(96, 0, 0));
+ }
+
+ public static class Initializer extends AbstractPreferenceInitializer {
+ @Override
+ public void initializeDefaultPreferences() {
+ IPreferenceStore store = DsfUIPlugin.getDefault().getPreferenceStore();
+ initializeDefaults(store);
+ EditorsUI.useAnnotationsPreferencePage(store);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java
new file mode 100644
index 00000000000..b41dcd46e39
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/preferences/DisassemblyPreferencePage.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.preferences;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.IDisassemblyHelpContextIds;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * DisassemblyPreferencePage
+ */
+public class DisassemblyPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+ private List<Button> fCheckBoxes = new ArrayList<Button>();
+ private List<Combo> fComboBoxes = new ArrayList<Combo>();
+ private ArrayList<Text> fNumberFields = new ArrayList<Text>();
+ private ModifyListener fNumberFieldListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ numberFieldChanged((Text)e.widget);
+ }
+ };
+ private final static String[] fcRadixItems = {
+ DisassemblyMessages.DisassemblyPreferencePage_radix_octal,
+ DisassemblyMessages.DisassemblyPreferencePage_radix_decimal,
+ DisassemblyMessages.DisassemblyPreferencePage_radix_hexadecimal,
+ };
+ private final static int[] fcRadixValues = {
+ 8, 10, 16
+ };
+
+ /**
+ * Create the Disassembly preference page.
+ */
+ public DisassemblyPreferencePage() {
+ super();
+ setPreferenceStore(DsfUIPlugin.getDefault().getPreferenceStore());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent) {
+ super.createControl(parent);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IDisassemblyHelpContextIds.DISASSEMBLY_PREFERENCE_PAGE);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createContents(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NULL);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.numColumns = 2;
+ composite.setLayout(layout);
+ composite.setFont(parent.getFont());
+
+ String label;
+
+// label = DisassemblyMessages.DisassemblyPreferencePage_startAddress; //$NON-NLS-1$
+// addTextField(composite, label, DisassemblyPreferenceConstants.START_ADDRESS, 20, 0, true);
+// label = DisassemblyMessages.DisassemblyPreferencePage_endAddress; //$NON-NLS-1$
+// addTextField(composite, label, DisassemblyPreferenceConstants.END_ADDRESS, 20, 0, true);
+
+ label = DisassemblyMessages.DisassemblyPreferencePage_addressRadix;
+ addComboBox(composite, label, DisassemblyPreferenceConstants.ADDRESS_RADIX, fcRadixItems);
+// label = DisassemblyMessages.DisassemblyPreferencePage_instructionRadix;
+// addComboBox(composite, label, DisassemblyPreferenceConstants.INSTRUCTION_RADIX, fcRadixItems);
+
+ label = DisassemblyMessages.DisassemblyPreferencePage_showSource;
+ addCheckBox(composite, label, DisassemblyPreferenceConstants.SHOW_SOURCE, 0);
+ label = DisassemblyMessages.DisassemblyPreferencePage_showSymbols;
+ addCheckBox(composite, label, DisassemblyPreferenceConstants.SHOW_SYMBOLS, 0);
+// label = DisassemblyMessages.DisassemblyPreferencePage_simplifiedMnemonics;
+// addCheckBox(composite, label, DisassemblyPreferenceConstants.SIMPLIFIED, 0);
+ label = DisassemblyMessages.DisassemblyPreferencePage_showAddressRadix;
+ addCheckBox(composite, label, DisassemblyPreferenceConstants.SHOW_ADDRESS_RADIX, 0);
+ label = DisassemblyMessages.DisassemblyPreferencePage_showFunctionOffsets;
+ addCheckBox(composite, label, DisassemblyPreferenceConstants.SHOW_FUNCTION_OFFSETS, 0);
+ label = DisassemblyMessages.DisassemblyPreferencePage_showAddress;
+ addCheckBox(composite, label, DisassemblyPreferenceConstants.SHOW_ADDRESS_RULER, 0);
+// label = DisassemblyMessages.DisassemblyPreferencePage_avoidReadBeforePC;
+// addCheckBox(composite, label, DisassemblyPreferenceConstants.AVOID_READ_BEFORE_PC, 0);
+
+ // horizontal line
+// Label separator = new Label(composite, SWT.SEPARATOR|SWT.HORIZONTAL);
+// GridData data;
+// data = new GridData(GridData.FILL_HORIZONTAL);
+// data.horizontalSpan = layout.numColumns;
+// separator.setLayoutData(data);
+//
+// label = DisassemblyMessages.DisassemblyPreferencePage_useSourceOnlyMode;
+// addCheckBox(composite, label, DisassemblyPreferenceConstants.USE_SOURCE_ONLY_MODE, 0);
+//
+// // note
+// String noteTitle = DisassemblyMessages.DisassemblyPreferencePage_useSourceOnlyMode_noteTtitle;
+// String noteMessage = DisassemblyMessages.DisassemblyPreferencePage_useSourceOnlyMode_noteMessage;
+// Composite note = createNoteComposite(composite.getFont(), composite, noteTitle, noteMessage);
+// data = (GridData)note.getLayoutData();
+// if (data == null) {
+// data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+// note.setLayoutData(data);
+// }
+// data.horizontalSpan = layout.numColumns;
+// Control msgControl = note.getChildren()[1];
+// data = new GridData(GridData.FILL_HORIZONTAL);
+// data.widthHint = convertWidthInCharsToPixels(65);
+// data.heightHint = convertHeightInCharsToPixels(3);
+// msgControl.setLayoutData(data);
+
+ Dialog.applyDialogFont(parent);
+
+ initialize();
+
+ return composite;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ public void init(IWorkbench workbench) {
+ }
+
+ private Button addCheckBox(Composite parent, String label, String key, int indentation) {
+ Button checkBox = new Button(parent, SWT.CHECK);
+ checkBox.setText(label);
+
+ GridData gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalIndent = indentation;
+ gd.horizontalSpan = 2;
+ checkBox.setLayoutData(gd);
+ checkBox.setData(key);
+ fCheckBoxes.add(checkBox);
+
+ return checkBox;
+ }
+
+ private Combo addComboBox(Composite parent, String label, String key, String[] items) {
+ Label labelControl= new Label(parent, SWT.NONE);
+ labelControl.setText(label);
+ GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ labelControl.setLayoutData(gd);
+
+ Combo combo = new Combo(parent, SWT.READ_ONLY);
+ gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ combo.setLayoutData(gd);
+ combo.setItems(items);
+ combo.setData(key);
+ fComboBoxes.add(combo);
+
+ return combo;
+ }
+
+ protected Text addTextField(Composite composite, String label, String key, int textLimit, int indentation, boolean isNumber) {
+ return getTextControl(addLabelledTextField(composite, label, key, textLimit, indentation, isNumber));
+ }
+
+// private static Label getLabelControl(Control[] labelledTextField){
+// return (Label)labelledTextField[0];
+// }
+
+ private static Text getTextControl(Control[] labelledTextField){
+ return (Text)labelledTextField[1];
+ }
+
+ /**
+ * Returns an array of size 2:
+ * - first element is of type <code>Label</code>
+ * - second element is of type <code>Text</code>
+ * Use <code>getLabelControl</code> and <code>getTextControl</code> to get the 2 controls.
+ */
+ private Control[] addLabelledTextField(Composite composite, String label, String key, int textLimit, int indentation, boolean isNumber) {
+ Label labelControl= new Label(composite, SWT.NONE);
+ labelControl.setText(label);
+ GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ gd.horizontalIndent= indentation;
+ labelControl.setLayoutData(gd);
+
+ Text textControl= new Text(composite, SWT.BORDER | SWT.SINGLE);
+ gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
+ gd.widthHint= convertWidthInCharsToPixels(textLimit + 1);
+ textControl.setLayoutData(gd);
+ textControl.setTextLimit(textLimit);
+ textControl.setData(key);
+ if (isNumber) {
+ fNumberFields.add(textControl);
+ textControl.addModifyListener(fNumberFieldListener);
+ }
+
+ return new Control[]{labelControl, textControl};
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.IPreferencePage#performOk()
+ */
+ @Override
+ public boolean performOk() {
+ IPreferenceStore store = getPreferenceStore();
+ for (Iterator<Button> iter = fCheckBoxes.iterator(); iter.hasNext();) {
+ Button btn = iter.next();
+ store.setValue((String)btn.getData(), btn.getSelection());
+ }
+ for (Iterator<Text> iter = fNumberFields.iterator(); iter.hasNext();) {
+ Text field = iter.next();
+ store.setValue((String)field.getData(), Long.decode(field.getText()).longValue());
+ }
+ for (Iterator<Combo> iter = fComboBoxes.iterator(); iter.hasNext();) {
+ Combo combo = iter.next();
+ store.setValue((String)combo.getData(), fcRadixValues[combo.getSelectionIndex()]);
+ }
+ return super.performOk();
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.PreferencePage#performDefaults()
+ */
+ @Override
+ protected void performDefaults() {
+ IPreferenceStore store = getPreferenceStore();
+ for (Iterator<Button> iter = fCheckBoxes.iterator(); iter.hasNext();) {
+ Button btn = iter.next();
+ btn.setSelection(store.getDefaultBoolean((String)btn.getData()));
+ }
+ for (Iterator<Text> iter = fNumberFields.iterator(); iter.hasNext();) {
+ Text field = iter.next();
+ long value = store.getDefaultLong((String)field.getData());
+ field.setText("0x"+Long.toHexString(value)); //$NON-NLS-1$
+ }
+ for (Iterator<Combo> iter = fComboBoxes.iterator(); iter.hasNext();) {
+ Combo combo = iter.next();
+ int value = store.getDefaultInt((String)combo.getData());
+ for (int i = 0; i < fcRadixValues.length; i++) {
+ if (fcRadixValues[i] == value) {
+ combo.select(i);
+ }
+ }
+ }
+ super.performDefaults();
+ }
+ /**
+ * Initialize widget values from preference store.
+ */
+ private void initialize() {
+ IPreferenceStore store = getPreferenceStore();
+ for (Iterator<Button> iter = fCheckBoxes.iterator(); iter.hasNext();) {
+ Button btn = iter.next();
+ btn.setSelection(store.getBoolean((String)btn.getData()));
+ }
+ for (Iterator<Text> iter = fNumberFields.iterator(); iter.hasNext();) {
+ Text field = iter.next();
+ long value = store.getLong((String)field.getData());
+ field.setText("0x"+Long.toHexString(value)); //$NON-NLS-1$
+ }
+ for (Iterator<Combo> iter = fComboBoxes.iterator(); iter.hasNext();) {
+ Combo combo = iter.next();
+ int value = store.getInt((String)combo.getData());
+ for (int i = 0; i < fcRadixValues.length; i++) {
+ if (fcRadixValues[i] == value) {
+ combo.select(i);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param text
+ */
+ protected void numberFieldChanged(Text text) {
+ try {
+ long value = Long.decode(text.getText()).longValue();
+ if (value < 0) {
+ setErrorMessage(DisassemblyMessages.DisassemblyPreferencePage_error_negative_number);
+ } else {
+ setErrorMessage(null);
+ }
+ } catch(NumberFormatException nfe) {
+ setErrorMessage(DisassemblyMessages.DisassemblyPreferencePage_error_not_a_number);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourcePresentationCreator.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourcePresentationCreator.java
new file mode 100644
index 00000000000..8fb4f3620f3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourcePresentationCreator.java
@@ -0,0 +1,350 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.CoreModel;
+import org.eclipse.cdt.core.model.IAsmLanguage;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ICModel;
+import org.eclipse.cdt.core.model.ICProject;
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.ui.editor.CDocumentProvider;
+import org.eclipse.cdt.internal.ui.editor.ITranslationUnitEditorInput;
+import org.eclipse.cdt.internal.ui.text.CCommentScanner;
+import org.eclipse.cdt.internal.ui.text.CTextTools;
+import org.eclipse.cdt.internal.ui.text.ICColorConstants;
+import org.eclipse.cdt.internal.ui.text.IColorManager;
+import org.eclipse.cdt.internal.ui.text.SimpleCSourceViewerConfiguration;
+import org.eclipse.cdt.internal.ui.text.TokenStore;
+import org.eclipse.cdt.internal.ui.util.EditorUtility;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.text.ICPartitions;
+import org.eclipse.cdt.ui.text.ITokenStore;
+import org.eclipse.cdt.ui.text.ITokenStoreFactory;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFileState;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.ITokenScanner;
+import org.eclipse.jface.text.rules.RuleBasedScanner;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * A presentation creator based on CDT syntax highlighting.
+ */
+@SuppressWarnings("restriction")
+public class CSourcePresentationCreator extends PresentationReconciler implements ISourcePresentationCreator, IPropertyChangeListener {
+
+ /**
+ *
+ */
+ private final static class CustomCSourceViewerConfiguration extends SimpleCSourceViewerConfiguration {
+ /**
+ * Comment for <code>fLanguage</code>
+ */
+ private final ILanguage fLanguage;
+
+ /**
+ * @param colorManager
+ * @param preferenceStore
+ * @param language
+ */
+ private CustomCSourceViewerConfiguration(
+ IColorManager colorManager, IPreferenceStore preferenceStore,
+ ILanguage language) {
+ super(colorManager, preferenceStore, null, ICPartitions.C_PARTITIONING, false);
+ fLanguage = language;
+ }
+
+ public void dispose() {
+ }
+
+ /*
+ * @see org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration#getLanguage()
+ */
+ @Override
+ protected ILanguage getLanguage() {
+ return fLanguage;
+ }
+
+ /**
+ * @param contentType
+ * @return
+ */
+ public ITokenScanner getScannerForContentType(String contentType) {
+ if (IDocument.DEFAULT_CONTENT_TYPE.equals(contentType)) {
+ return getLanguage() != null ? getCodeScanner(getLanguage()) : null;
+ } else if (ICPartitions.C_CHARACTER.equals(contentType)) {
+ return getStringScanner();
+ } else if (ICPartitions.C_STRING.equals(contentType)) {
+ return getStringScanner();
+ } else if (ICPartitions.C_SINGLE_LINE_COMMENT.equals(contentType)) {
+ return getSinglelineCommentScanner();
+ } else if (ICPartitions.C_SINGLE_LINE_DOC_COMMENT.equals(contentType)) {
+ return getSinglelineDocCommentScanner(getProject());
+ } else if (ICPartitions.C_MULTI_LINE_COMMENT.equals(contentType)) {
+ return getMultilineCommentScanner();
+ } else if (ICPartitions.C_MULTI_LINE_DOC_COMMENT.equals(contentType)) {
+ return getMultilineDocCommentScanner(getProject());
+ } else if (ICPartitions.C_PREPROCESSOR.equals(contentType)) {
+ return getPreprocessorScanner(getLanguage());
+ }
+ return null;
+ }
+
+ private ITokenScanner getMultilineCommentScanner() {
+ return new CCommentScanner(getTokenStoreFactory(), ICColorConstants.C_SINGLE_LINE_COMMENT);
+ }
+
+ private ITokenScanner getSinglelineCommentScanner() {
+ return new CCommentScanner(getTokenStoreFactory(), ICColorConstants.C_MULTI_LINE_COMMENT);
+ }
+
+ /**
+ * Returns the ICProject associated with this CSourceViewerConfiguration, or null if
+ * no ICProject could be determined
+ * @return
+ */
+ private ICProject internalGetCProject() {
+ ITextEditor editor= getEditor();
+ if (editor == null)
+ return null;
+
+ ICElement element= null;
+ IEditorInput input= editor.getEditorInput();
+ IDocumentProvider provider= editor.getDocumentProvider();
+ if (provider instanceof CDocumentProvider) {
+ CDocumentProvider cudp= (CDocumentProvider) provider;
+ element= cudp.getWorkingCopy(input);
+ }
+
+ if (element == null)
+ return null;
+
+ return element.getCProject();
+ }
+
+
+ /**
+ * @return the IProject associated with this CSourceViewerConfiguration, or null if
+ * no IProject could be determined
+ */
+ private IProject getProject() {
+ ICProject cproject= internalGetCProject();
+ return cproject!=null ? cproject.getProject() :null;
+ }
+
+ private ITokenStoreFactory getTokenStoreFactory() {
+ return new ITokenStoreFactory() {
+ public ITokenStore createTokenStore(String[] propertyColorNames) {
+ return new TokenStore(getColorManager(), fPreferenceStore, propertyColorNames);
+ }
+ };
+ }
+
+ /*
+ * @see org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration#getCodeScanner(org.eclipse.cdt.core.model.ILanguage)
+ */
+ @Override
+ protected RuleBasedScanner getCodeScanner(ILanguage language) {
+ if (language instanceof IAsmLanguage) {
+ return CUIPlugin.getDefault().getAsmTextTools().getCodeScanner();
+ }
+ return super.getCodeScanner(language);
+ }
+
+ /*
+ * @see org.eclipse.cdt.internal.ui.text.CSourceViewerConfiguration#getPreprocessorScanner(org.eclipse.cdt.core.model.ILanguage)
+ */
+ @Override
+ protected RuleBasedScanner getPreprocessorScanner(ILanguage language) {
+ if (language instanceof IAsmLanguage) {
+ return CUIPlugin.getDefault().getAsmTextTools().getPreprocessorScanner();
+ }
+ return super.getPreprocessorScanner(language);
+ }
+ }
+
+ private ITextViewer fViewer;
+ private ISourceTagProvider fSourceTagProvider;
+ private SourceTagDamagerRepairer fDamagerRepairer;
+ private ISourceTagListener fSourceTagListener;
+ private TextPresentation fPresentation;
+ private CustomCSourceViewerConfiguration fSourceViewerConfiguration;
+ private IPreferenceStore fPreferenceStore;
+
+ /**
+ * @param language
+ * @param storage
+ * @param textViewer
+ */
+ public CSourcePresentationCreator(ILanguage language, IStorage storage, ITextViewer textViewer) {
+ if (language != null) {
+ fViewer= textViewer;
+ fPreferenceStore= CUIPlugin.getDefault().getCombinedPreferenceStore();
+ CTextTools textTools = CUIPlugin.getDefault().getTextTools();
+ fSourceViewerConfiguration= new CustomCSourceViewerConfiguration(textTools.getColorManager(), fPreferenceStore, language);
+ setDocumentPartitioning(fSourceViewerConfiguration.getConfiguredDocumentPartitioning(null));
+ initializeDamagerRepairer(storage, textTools.getColorManager(), fPreferenceStore);
+ fPreferenceStore.addPropertyChangeListener(this);
+ }
+ }
+
+ private void initializeDamagerRepairer(IStorage storage, IColorManager colorManager, IPreferenceStore store) {
+ String[] contentTypes= fSourceViewerConfiguration.getConfiguredContentTypes(null);
+ for (int i = 0; i < contentTypes.length; ++i) {
+ String contentType = contentTypes[i];
+ ITokenScanner scanner;
+ scanner = fSourceViewerConfiguration.getScannerForContentType(contentType);
+ if (scanner != null) {
+ if (fDamagerRepairer == null) {
+ fSourceTagProvider = createSourceTagProvider(storage);
+ fDamagerRepairer= new SourceTagDamagerRepairer(scanner, fSourceTagProvider, colorManager, store);
+ if (fSourceTagProvider != null) {
+ if (fSourceTagListener == null) {
+ fSourceTagListener= new ISourceTagListener() {
+ public void sourceTagsChanged(ISourceTagProvider provider) {
+ handleSourceTagsChanged();
+ }};
+ }
+ fSourceTagProvider.addSourceTagListener(fSourceTagListener);
+ }
+ }
+ fDamagerRepairer.setScanner(contentType, scanner);
+ setDamager(fDamagerRepairer, contentType);
+ setRepairer(fDamagerRepairer, contentType);
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.ISourcePresentationCreator#dispose()
+ */
+ public void dispose() {
+ fViewer= null;
+ fPresentation= null;
+ if (fPreferenceStore != null) {
+ fPreferenceStore.removePropertyChangeListener(this);
+ fPreferenceStore= null;
+ }
+ if (fSourceViewerConfiguration != null) {
+ fSourceViewerConfiguration.dispose();
+ fSourceViewerConfiguration= null;
+ }
+ if (fSourceTagProvider != null) {
+ if (fSourceTagListener != null) {
+ fSourceTagProvider.removeSourceTagListener(fSourceTagListener);
+ fSourceTagListener= null;
+ }
+ fSourceTagProvider= null;
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.ISourcePresentationCreator#getPresentation(org.eclipse.jface.text.IRegion, org.eclipse.jface.text.IDocument)
+ */
+ public TextPresentation getPresentation(IRegion region, IDocument document) {
+ assert fViewer != null;
+ if (fViewer == null) {
+ return null;
+ }
+ if (fPresentation == null) {
+ setDocumentToDamagers(document);
+ setDocumentToRepairers(document);
+ int docLength= document.getLength();
+ if (docLength <= 128*1024) {
+ IRegion all= new Region(0, docLength);
+ fPresentation= createPresentation(all, document);
+ } else {
+ return createPresentation(region, document);
+ }
+ }
+ fPresentation.setResultWindow(region);
+ return fPresentation;
+ }
+
+ protected void handleSourceTagsChanged() {
+ invalidateTextPresentation();
+ }
+
+ private void invalidateTextPresentation() {
+ if (fPresentation != null) {
+ fPresentation= null;
+ if (fViewer != null) {
+ Display display= fViewer.getTextWidget().getDisplay();
+ if (display.getThread() != Thread.currentThread()) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (fViewer != null) {
+ fViewer.invalidateTextPresentation();
+ }
+ }});
+ } else {
+ fViewer.invalidateTextPresentation();
+ }
+ }
+ }
+ }
+
+ private ISourceTagProvider createSourceTagProvider(IStorage storage) {
+ ITranslationUnit tUnit= null;
+ if (storage instanceof IFile) {
+ tUnit= (ITranslationUnit) CoreModel.getDefault().create((IFile)storage);
+ } else if (storage instanceof IFileState) {
+ ICModel cModel= CoreModel.getDefault().getCModel();
+ ICProject[] cProjects;
+ try {
+ cProjects = cModel.getCProjects();
+ if (cProjects.length > 0) {
+ tUnit= CoreModel.getDefault().createTranslationUnitFrom(cProjects[0], storage.getFullPath());
+ }
+ } catch (CModelException e) {
+ }
+ } else {
+ IEditorInput input= EditorUtility.getEditorInputForLocation(storage.getFullPath(), null);
+ if (input instanceof ITranslationUnitEditorInput) {
+ tUnit= ((ITranslationUnitEditorInput)input).getTranslationUnit();
+ }
+ }
+ if (tUnit != null) {
+ return new CSourceTagProvider(tUnit);
+ }
+ return null;
+ }
+
+ /*
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ if (fSourceViewerConfiguration.affectsBehavior(event)) {
+ fSourceViewerConfiguration.handlePropertyChangeEvent(event);
+ invalidateTextPresentation();
+ } else if (fDamagerRepairer.affectsBahvior(event)) {
+ fDamagerRepairer.handlePropertyChangeEvent(event);
+ invalidateTextPresentation();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTag.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTag.java
new file mode 100644
index 00000000000..9cfd0021933
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTag.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.ISourceReference;
+
+/**
+ * A source tag based on C Model elements.
+ */
+public class CSourceTag implements ISourceTag {
+
+ /**
+ * The zero-length source range.
+ */
+ public class NullRange implements ISourceRange {
+
+ public boolean contains(int offset) {
+ return false;
+ }
+
+ public int getBeginOffset() {
+ return 0;
+ }
+
+ public int getEndOffset() {
+ return -1;
+ }
+
+ public int compareTo(ISourceRange other) {
+ if (this == other) {
+ return 0;
+ }
+ return -1;
+ }
+
+ }
+
+ /**
+ * The source range.
+ */
+ public class CSourceRange implements ISourceRange {
+
+ private org.eclipse.cdt.core.model.ISourceRange fRange;
+
+ /**
+ * @param sourceRange
+ */
+ public CSourceRange(org.eclipse.cdt.core.model.ISourceRange sourceRange) {
+ fRange= sourceRange;
+ }
+
+ public boolean contains(int offset) {
+ return fRange.getStartPos() <= offset && offset - fRange.getStartPos() < fRange.getLength();
+ }
+
+ public int getBeginOffset() {
+ return fRange.getStartPos();
+ }
+
+ public int getEndOffset() {
+ return fRange.getStartPos() + fRange.getLength() - 1;
+ }
+
+ public int compareTo(ISourceRange other) {
+ int delta= this.getBeginOffset() - other.getBeginOffset();
+ if (delta == 0) {
+ delta= this.getEndOffset() - other.getEndOffset();
+ }
+ return delta;
+ }
+
+ }
+
+ /**
+ * The identifier range.
+ */
+ public class CIdentifierRange implements ISourceRange {
+
+ private org.eclipse.cdt.core.model.ISourceRange fRange;
+
+ public CIdentifierRange(org.eclipse.cdt.core.model.ISourceRange sourceRange) {
+ fRange= sourceRange;
+ }
+
+ public boolean contains(int offset) {
+ return fRange.getIdStartPos() <= offset && offset - fRange.getIdStartPos() < fRange.getIdLength();
+ }
+
+ public int getBeginOffset() {
+ return fRange.getIdStartPos();
+ }
+
+ public int getEndOffset() {
+ return fRange.getIdStartPos() + fRange.getIdLength() - 1;
+ }
+
+ public int compareTo(ISourceRange other) {
+ int delta= this.getBeginOffset() - other.getBeginOffset();
+ if (delta == 0) {
+ delta= this.getEndOffset() - other.getEndOffset();
+ }
+ return delta;
+ }
+
+ }
+
+ private ISourceReference fReference;
+ private int fType;
+
+ /**
+ * Create a new source tag for the given element and type.
+ *
+ * @param element
+ * @param elementType
+ */
+ public CSourceTag(ISourceReference element, int elementType) {
+ fReference= element;
+ fType= elementType;
+ }
+
+ public ISourceRange getFullRange() {
+ try {
+ return new CSourceRange(fReference.getSourceRange());
+ } catch (CModelException e) {
+ }
+ return new NullRange();
+ }
+
+ public String getName() {
+ return ((ICElement)fReference).getElementName();
+ }
+
+ public String getQualifiedName() {
+ return getName();
+ }
+
+ public ISourceRange getRangeOfIdentifier() {
+ try {
+ return new CIdentifierRange(fReference.getSourceRange());
+ } catch (CModelException e) {
+ }
+ return new NullRange();
+ }
+
+ public long getSnapshotTime() {
+ return 0;
+ }
+
+ public int getStyleCode() {
+ switch (fType) {
+ case ICElement.C_METHOD :
+ case ICElement.C_METHOD_DECLARATION:
+ case ICElement.C_TEMPLATE_METHOD:
+ case ICElement.C_TEMPLATE_METHOD_DECLARATION:
+ return ISourceTag.STYLE_Method;
+ case ICElement.C_FUNCTION:
+ case ICElement.C_FUNCTION_DECLARATION:
+ case ICElement.C_TEMPLATE_FUNCTION:
+ case ICElement.C_TEMPLATE_FUNCTION_DECLARATION:
+ return ISourceTag.STYLE_Function;
+ case ICElement.C_FIELD :
+ return ISourceTag.STYLE_MemberVariable;
+ case ICElement.C_VARIABLE:
+ case ICElement.C_VARIABLE_DECLARATION:
+ return ISourceTag.STYLE_Variable;
+ case ICElement.C_CLASS:
+ case ICElement.C_TEMPLATE_CLASS:
+ case ICElement.C_TEMPLATE_CLASS_DECLARATION:
+ return ISourceTag.STYLE_Class;
+ case ICElement.C_STRUCT:
+ case ICElement.C_TEMPLATE_STRUCT:
+ case ICElement.C_TEMPLATE_STRUCT_DECLARATION:
+ return ISourceTag.STYLE_Struct;
+ case ICElement.C_UNION:
+ case ICElement.C_TEMPLATE_UNION:
+ case ICElement.C_TEMPLATE_UNION_DECLARATION:
+ return ISourceTag.STYLE_Union;
+ case ICElement.C_ENUMERATION:
+ return ISourceTag.STYLE_Enumeration;
+ case ICElement.C_ENUMERATOR:
+ return ISourceTag.STYLE_Enumerator;
+ case ICElement.C_NAMESPACE:
+ return ISourceTag.STYLE_None;
+ case ICElement.C_TYPEDEF:
+ return ISourceTag.STYLE_Typedef;
+ case ICElement.C_MACRO:
+ return ISourceTag.STYLE_Macro;
+ default:
+ return ISourceTag.STYLE_None;
+ }
+ }
+
+ public ISourceTag getSourceTagAdapter() {
+ return this;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTagProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTagProvider.java
new file mode 100644
index 00000000000..3d90ad3dc92
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/CSourceTagProvider.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import java.util.Collection;
+
+import org.eclipse.cdt.core.model.CModelException;
+import org.eclipse.cdt.core.model.ICElement;
+import org.eclipse.cdt.core.model.IParent;
+import org.eclipse.cdt.core.model.ISourceReference;
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.core.runtime.ListenerList;
+
+/**
+ * A source tag provider based on the C Model.
+ */
+public class CSourceTagProvider implements ISourceTagProvider {
+
+ private ListenerList fListenerList= new ListenerList(ListenerList.IDENTITY);
+ private ITranslationUnit fUnit;
+
+ /**
+ * Create a new source tag provider for the given translation unit.
+ *
+ * @param unit
+ */
+ public CSourceTagProvider(ITranslationUnit unit) {
+ fUnit= unit;
+ }
+
+ public void addSourceTagListener(ISourceTagListener listener) {
+ fListenerList.add(listener);
+ }
+
+ public int[] getActiveCodePositions() {
+ // unsupported
+ return null;
+ }
+
+ public long getSnapshotTime() {
+ return 0;
+ }
+
+ public void getSourceTags(Collection<ISourceTag> target) {
+ try {
+ convertToSourceTags(fUnit.getChildren(), target);
+ } catch (CModelException e) {
+ }
+ }
+
+ /**
+ * @param element
+ * @return
+ */
+ private ISourceTag convertToSourceTag(ICElement element) {
+ if (element instanceof ISourceReference) {
+ return new CSourceTag((ISourceReference)element, element.getElementType());
+ }
+ return null;
+ }
+
+ /**
+ * @param children
+ * @param target
+ * @throws CModelException
+ */
+ private void convertToSourceTags(ICElement[] children, Collection<ISourceTag> target) throws CModelException {
+ for (int i = 0; i < children.length; i++) {
+ ICElement element= children[i];
+ ISourceTag tag= convertToSourceTag(element);
+ if (tag != null) {
+ target.add(tag);
+ }
+ if (element instanceof IParent) {
+ convertToSourceTags(((IParent)element).getChildren(), target);
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.ISourceTagProvider#removeSourceTagListener(org.eclipse.cdt.dsf.debug.internal.ui.disassembly.presentation.ISourceTagListener)
+ */
+ public void removeSourceTagListener(ISourceTagListener listener) {
+ fListenerList.remove(listener);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/DisassemblyIPAnnotation.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/DisassemblyIPAnnotation.java
new file mode 100644
index 00000000000..27e6dca2a36
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/DisassemblyIPAnnotation.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.DisassemblyMessages;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationPresentation;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+
+/**
+ * DisassemblyIPAnnotation
+ */
+public class DisassemblyIPAnnotation extends Annotation implements IAnnotationPresentation {
+
+ public static final String ID_TOP = "org.eclipse.cdt.dsf.debug.currentIP"; //$NON-NLS-1$
+ public static final String ID_SECONDARY = "org.eclipse.cdt.dsf.debug.secondaryIP"; //$NON-NLS-1$
+
+ private Image fImage;
+ private int fContext = Integer.MIN_VALUE;
+
+ /**
+ * Annotation denoting the current instruction pointer.
+ */
+ public DisassemblyIPAnnotation(boolean isTopFrame, int context) {
+ super(
+ isTopFrame ? ID_TOP : ID_SECONDARY,
+ false,
+ isTopFrame ? DisassemblyMessages.DisassemblyIPAnnotation_primary
+ : DisassemblyMessages.DisassemblyIPAnnotation_secondary
+ );
+ setContext(context);
+ }
+
+ public boolean isTopFrame() {
+ return ID_TOP.equals(getType());
+ }
+
+ public void setContext(int context) {
+ if (context == fContext) {
+ return;
+ }
+ fContext = context;
+ // TLETODO [disassembly] context dependent IP icon
+ if (isTopFrame()) {
+ fImage = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER_TOP);
+ } else {
+ fImage = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER);
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
+ */
+ public int getLayer() {
+ return 5;
+ }
+
+ /*
+ * @see org.eclipse.jface.text.source.IAnnotationPresentation#paint(org.eclipse.swt.graphics.GC, org.eclipse.swt.widgets.Canvas, org.eclipse.swt.graphics.Rectangle)
+ */
+ public void paint(GC gc, Canvas canvas, Rectangle bounds) {
+ Rectangle imageBounds = fImage.getBounds();
+ gc.drawImage(fImage, bounds.x + (bounds.width - imageBounds.width) / 2 , bounds.y + (bounds.height - imageBounds.height) / 2);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourcePresentationCreator.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourcePresentationCreator.java
new file mode 100644
index 00000000000..c174ca3d972
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourcePresentationCreator.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.TextPresentation;
+
+/**
+ * A source presentation creator is used to create a {@link TextPresentation} of a document range.
+ */
+public interface ISourcePresentationCreator {
+
+ /**
+ * Dispose of this presentation creator.
+ */
+ public abstract void dispose();
+
+ /**
+ * Get a text presentation for the given region and document.
+ * @param region
+ * @param document
+ * @return a text presentation
+ */
+ public abstract TextPresentation getPresentation(IRegion region, IDocument document);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceRange.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceRange.java
new file mode 100644
index 00000000000..6e4e71d5c8d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceRange.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+/**
+ * Represents a range within a source file.
+ */
+
+public interface ISourceRange extends Comparable<ISourceRange> {
+ /**
+ * Returns 0-based absolute number for the inclusive start of the range.
+ */
+ int getBeginOffset();
+ /**
+ * Returns 0-based absolute number for the inclusive end of the range.
+ */
+ int getEndOffset();
+ /**
+ * Checks whether the range contains the given offset.
+ */
+ boolean contains(int offset);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTag.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTag.java
new file mode 100644
index 00000000000..4232362c241
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTag.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+/**
+ * Specifies the style of part of some text source.
+ */
+public interface ISourceTag {
+ // style codes
+ final static int STYLE_None = 0;
+ final static int STYLE_Class = 1;
+ final static int STYLE_Struct = 2;
+ final static int STYLE_Union = 3;
+ final static int STYLE_Interface = 4;
+ final static int STYLE_Package = 5;
+ final static int STYLE_Function = 6;
+ final static int STYLE_ProtectedFunction = 7;
+ final static int STYLE_Method = 8;
+ final static int STYLE_Exception = 9;
+ final static int STYLE_Variable = 10;
+ final static int STYLE_MemberVariable = 11;
+ final static int STYLE_Enumerator = 12;
+ final static int STYLE_Macro = 13;
+ final static int STYLE_Include = 14;
+ final static int STYLE_Undefined = 15;
+ final static int STYLE_Enumeration = 16;
+ final static int STYLE_Typedef = 17;
+ final static int STYLE_Type3 = 18;
+ final static int STYLE_Type4 = 19;
+ final static int STYLE_Type5 = 20;
+ final static int STYLE_File = 21;
+ final static int STYLE_Project = 22;
+ final static int STYLE_IncludeContainer = 23;
+ final static int STYLE_LocalVariable = 24;
+ final static int STYLE_Label = 25;
+ final static int STYLE_Record = 26;
+ final static int STYLE_TaggedType = 27;
+ final static int STYLE_Subtype = 28;
+ final static int STYLE_Warning = 29;
+ final static int STYLE_Count = 30;
+
+ /**
+ * Returns the unqualified name of the source tag. Files return their base name.
+ */
+ String getName();
+
+ /**
+ * Returns the fully qualified name of the source tag. Files return their path.
+ */
+ String getQualifiedName();
+
+ /**
+ * Returns the range of the symbol within the file.
+ */
+ ISourceRange getFullRange();
+
+ /**
+ * Returns the range of the identifier of the symbol within the file.
+ */
+ ISourceRange getRangeOfIdentifier();
+
+ /**
+ * Computes the style code. Style codes are language dependent. You
+ * cannot derive any information from the style-code of a symbol. It
+ * may only be used to influence the visualization of a symbol. You
+ * may select color, font or icon depending on the style code.
+ * @return the style code of the symbol
+ */
+ int getStyleCode();
+
+ /**
+ * Returns the timestamp of the file at the time the sourcetag was generated.
+ */
+ long getSnapshotTime();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagListener.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagListener.java
new file mode 100644
index 00000000000..f471cf862ae
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagListener.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+/**
+ * ISourceTagListener
+ */
+public interface ISourceTagListener {
+
+ /**
+ * Notifies this listener that the source tags have changed.
+ * @param provider the provider generating this event.
+ */
+ void sourceTagsChanged(ISourceTagProvider provider);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagProvider.java
new file mode 100644
index 00000000000..08b5b9a0d3e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/ISourceTagProvider.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import java.util.Collection;
+
+/**
+ * A source tag provider provides access to source tags.
+ */
+public interface ISourceTagProvider {
+
+ /**
+ * Add a source tag listener to receive source tag changed notifications.
+ * @param listener
+ */
+ public void addSourceTagListener(ISourceTagListener listener);
+
+ /**
+ * Remove a source tag listener to stop receiving source tag changed notifications.
+ * @param listener
+ */
+ public void removeSourceTagListener(ISourceTagListener listener);
+
+ /**
+ * Retrieves all symbols of the current file.
+ */
+ public void getSourceTags(Collection<ISourceTag> target);
+
+ /**
+ * Get the time stamp of the current symbol content.
+ * @return the modification time of the source file or 0L if no symbols available.
+ */
+ public long getSnapshotTime();
+
+ /**
+ * Retrieves the active code positions of the current file. Null if the
+ * information cannot be obtained.
+ */
+ public int[] getActiveCodePositions();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourcePresentationCreatorFactory.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourcePresentationCreatorFactory.java
new file mode 100644
index 00000000000..fe06d6ec698
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourcePresentationCreatorFactory.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import org.eclipse.cdt.core.model.ILanguage;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.jface.text.ITextViewer;
+
+/**
+ * A factory for source presentation creators.
+ */
+public final class SourcePresentationCreatorFactory {
+
+ public static ISourcePresentationCreator create(ILanguage language, IStorage storage, ITextViewer textViewer) {
+ return new CSourcePresentationCreator(language, storage, textViewer);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourceTagDamagerRepairer.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourceTagDamagerRepairer.java
new file mode 100644
index 00000000000..5aa049b3856
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/presentation/SourceTagDamagerRepairer.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.presentation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings;
+import org.eclipse.cdt.internal.ui.text.IColorManager;
+import org.eclipse.cdt.internal.ui.text.IColorManagerExtension;
+import org.eclipse.cdt.ui.PreferenceConstants;
+import org.eclipse.cdt.ui.text.ICPartitions;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITypedRegion;
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.TextPresentation;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.rules.IToken;
+import org.eclipse.jface.text.rules.ITokenScanner;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class SourceTagDamagerRepairer extends DefaultDamagerRepairer implements ISourceTagListener {
+
+ private ISourceTagProvider fSourceTagProvider;
+ private Map<String, ITokenScanner> fScannerMap= new HashMap<String, ITokenScanner>();
+ private List<ISourceTag> fSourceTags = new ArrayList<ISourceTag>();
+ private IColorManager fColorManager;
+ private IPreferenceStore fPreferenceStore;
+ private Map<String, TextAttribute> fAttributeMap= new HashMap<String, TextAttribute>();
+
+ private final static String[] KEYS= {
+ SemanticHighlightings.CLASS,
+ SemanticHighlightings.METHOD_DECLARATION,
+ SemanticHighlightings.FUNCTION_DECLARATION,
+ SemanticHighlightings.FIELD,
+ SemanticHighlightings.GLOBAL_VARIABLE,
+ SemanticHighlightings.TYPEDEF,
+ SemanticHighlightings.MACRO_DEFINITION,
+ SemanticHighlightings.ENUMERATOR,
+ SemanticHighlightings.ENUM,
+ };
+
+ /**
+ * @param scanner
+ * @param sourceTagProvider
+ */
+ public SourceTagDamagerRepairer(ITokenScanner scanner, ISourceTagProvider sourceTagProvider, IColorManager colorManager, IPreferenceStore store) {
+ super(scanner);
+ fSourceTagProvider= sourceTagProvider;
+ fColorManager= colorManager;
+ fPreferenceStore= store;
+ fDefaultTextAttribute = new TextAttribute(null, null, SWT.NORMAL);
+ if (fSourceTagProvider != null) {
+ fSourceTagProvider.addSourceTagListener(this);
+ sourceTagsChanged(fSourceTagProvider);
+ }
+ }
+
+ private void initTextAttributes() {
+ boolean shEnabled= fPreferenceStore.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED);
+ for (int i= 0; i < KEYS.length; i++) {
+ String enabledKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX;
+ String colorKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX;
+ boolean enabled= shEnabled && fPreferenceStore.getBoolean(enabledKey);
+ if (enabled) {
+ String boldKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_BOLD_SUFFIX;
+ String italicKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ITALIC_SUFFIX;
+ String strikethroughKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_STRIKETHROUGH_SUFFIX;
+ String underlineKey= PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + KEYS[i] + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_UNDERLINE_SUFFIX;
+ addTextAttribute(KEYS[i], colorKey, boldKey, italicKey, strikethroughKey, underlineKey);
+ } else {
+ removeTextAttribute(KEYS[i], colorKey);
+ }
+ }
+ }
+
+ private void removeTextAttribute(String key, String colorKey) {
+ if (fColorManager != null && colorKey != null) {
+ Color color= fColorManager.getColor(colorKey);
+ if (fColorManager instanceof IColorManagerExtension && color != null) {
+ IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
+ ext.unbindColor(colorKey);
+ }
+ }
+
+ fAttributeMap.remove(key);
+ }
+
+ private void addTextAttribute(String key, String colorKey, String boldKey, String italicKey, String strikethroughKey, String underlineKey) {
+ if (fColorManager != null && colorKey != null && fColorManager instanceof IColorManagerExtension) {
+ RGB rgb= PreferenceConverter.getColor(fPreferenceStore, colorKey);
+ Color color= fColorManager.getColor(colorKey);
+ if (color == null || !rgb.equals(color.getRGB())) {
+ IColorManagerExtension ext= (IColorManagerExtension) fColorManager;
+ ext.unbindColor(colorKey);
+ ext.bindColor(colorKey, rgb);
+ }
+ }
+
+ TextAttribute textAttribute= createTextAttribute(colorKey, boldKey, italicKey, strikethroughKey, underlineKey);
+ fAttributeMap.put(key, textAttribute);
+ }
+
+ private TextAttribute createTextAttribute(String colorKey, String boldKey, String italicKey, String strikethroughKey, String underlineKey) {
+ Color color= null;
+ if (colorKey != null)
+ color= fColorManager.getColor(colorKey);
+
+ int style= fPreferenceStore.getBoolean(boldKey) ? SWT.BOLD : SWT.NORMAL;
+ if (fPreferenceStore.getBoolean(italicKey))
+ style |= SWT.ITALIC;
+
+ if (fPreferenceStore.getBoolean(strikethroughKey))
+ style |= TextAttribute.STRIKETHROUGH;
+
+ if (fPreferenceStore.getBoolean(underlineKey))
+ style |= TextAttribute.UNDERLINE;
+
+ return new TextAttribute(color, null, style);
+ }
+
+ /**
+ * Set scanner for contentType.
+ * @param contentType
+ * @param scanner
+ */
+ public void setScanner(String contentType, ITokenScanner scanner) {
+ fScannerMap.put(contentType, scanner);
+ }
+
+ /*
+ * @see org.eclipse.jface.text.presentation.IPresentationRepairer#createPresentation(org.eclipse.jface.text.TextPresentation, org.eclipse.jface.text.ITypedRegion)
+ */
+ @Override
+ public void createPresentation(TextPresentation presentation, ITypedRegion region) {
+ if (fAttributeMap.isEmpty()) {
+ initTextAttributes();
+ }
+ String contentType= region.getType();
+ fScanner = fScannerMap.get(contentType);
+ if (!contentType.equals(IDocument.DEFAULT_CONTENT_TYPE) && !contentType.equals(ICPartitions.C_PREPROCESSOR)) {
+ super.createPresentation(presentation, region);
+ return;
+ }
+ if (fScanner == null) {
+ return;
+ }
+
+ int lastStart = region.getOffset();
+ int regionEnd = lastStart + region.getLength();
+ int length = 0;
+
+ int sourceTagCount = fSourceTags.size();
+ int sourceTagIdx = 0;
+
+ ISourceTag sourceTag = null;
+ ISourceRange range = null;
+ int sourceTagStart = 0;
+ int sourceTagEnd = 0;
+
+ if (sourceTagCount > 0 && fDocument.getLength() > 0) {
+ int left = 0;
+ int mid = (int) (sourceTagCount * ((float)lastStart / fDocument.getLength()));
+ int right = sourceTagCount - 1;
+ while (true) {
+ sourceTag = fSourceTags.get(mid);
+ range = sourceTag.getRangeOfIdentifier();
+ sourceTagStart = range.getBeginOffset();
+ sourceTagEnd = range.getEndOffset() + 1;
+ if (mid == left) {
+ break;
+ } else if (mid < right && sourceTagEnd < lastStart) {
+ left = mid;
+ mid = (mid + right) / 2;
+ } else if (sourceTagStart >= regionEnd) {
+ right = mid;
+ mid = (left + mid) / 2;
+ } else if (sourceTagStart > lastStart) {
+ --mid;
+ right = mid;
+ } else {
+ break;
+ }
+ }
+ // set to next index
+ sourceTagIdx = mid + 1;
+ }
+
+ TextAttribute lastAttribute = fDefaultTextAttribute;
+
+ fScanner.setRange(fDocument, lastStart, region.getLength());
+
+ while (true) {
+ IToken token = fScanner.nextToken();
+
+ // if the attribute is the same as the previous, extend range and continue
+ TextAttribute attribute = getTokenTextAttribute(token);
+ int tokenLength = fScanner.getTokenLength();
+ if (tokenLength > 0
+ && (lastAttribute == attribute || lastAttribute != null && lastAttribute.equals(attribute))) {
+ length += tokenLength;
+ continue;
+ }
+ // attribute has changed, now add the style range
+ while (sourceTag != null && length > 0) {
+ if (sourceTagStart >= regionEnd) {
+ // we are past the region boundary -> no more source tags
+ sourceTag = null;
+ break;
+ }
+ if (sourceTagStart >= lastStart) {
+ if (sourceTagStart < lastStart + length) {
+ String sourceTagStyle = getSourceTagStyle(sourceTag.getStyleCode());
+ if (sourceTagStyle != null) {
+ if (sourceTagStart > lastStart) {
+ addRange(presentation, lastStart, Math.min(sourceTagStart - lastStart, length), lastAttribute);
+ }
+ int rangeEnd = Math.min(sourceTagEnd, regionEnd);
+ addRange(
+ presentation,
+ sourceTagStart,
+ rangeEnd - sourceTagStart,
+ getSourceTagTextAttribute(sourceTagStyle));
+ length = lastStart + length - rangeEnd;
+ lastStart = rangeEnd;
+ } else {
+ fSourceTags.remove(--sourceTagIdx);
+ --sourceTagCount;
+ }
+ } else {
+ break;
+ }
+ }
+ sourceTag = sourceTagIdx < sourceTagCount ? fSourceTags.get(sourceTagIdx++) : null;
+ if (sourceTag != null) {
+ range = sourceTag.getRangeOfIdentifier();
+ sourceTagStart = range.getBeginOffset();
+ sourceTagEnd = range.getEndOffset() + 1;
+ }
+ }
+ if (token.isEOF()) {
+ break;
+ }
+
+ if (length > 0) {
+ addRange(presentation, lastStart, length, lastAttribute);
+ lastAttribute = attribute;
+ lastStart = fScanner.getTokenOffset();
+ length = tokenLength;
+ } else {
+ lastAttribute = attribute;
+ length = fScanner.getTokenOffset() - lastStart + tokenLength;
+ }
+
+ }
+
+ addRange(presentation, lastStart, length, lastAttribute);
+ }
+
+ /**
+ * @param sourceTagStyle
+ * @return
+ */
+ private TextAttribute getSourceTagTextAttribute(String sourceTagStyle) {
+ return fAttributeMap.get(sourceTagStyle);
+ }
+
+ /**
+ * Get the style id for a source tag style code.
+ * @param styleCode
+ * @return the associated style id or <code>null</code>
+ */
+ private String getSourceTagStyle(int styleCode) {
+ switch (styleCode) {
+ case ISourceTag.STYLE_None :
+ return null;
+ case ISourceTag.STYLE_Class :
+ return SemanticHighlightings.CLASS;
+ case ISourceTag.STYLE_Struct :
+ return SemanticHighlightings.CLASS;
+ case ISourceTag.STYLE_Union :
+ return SemanticHighlightings.CLASS;
+ case ISourceTag.STYLE_Function :
+ return SemanticHighlightings.FUNCTION_DECLARATION;
+ case ISourceTag.STYLE_Method :
+ return SemanticHighlightings.METHOD_DECLARATION;
+ case ISourceTag.STYLE_Variable :
+ return SemanticHighlightings.GLOBAL_VARIABLE;
+ case ISourceTag.STYLE_MemberVariable :
+ return SemanticHighlightings.FIELD;
+ case ISourceTag.STYLE_Enumerator :
+ return SemanticHighlightings.ENUMERATOR;
+ case ISourceTag.STYLE_Macro :
+ return SemanticHighlightings.MACRO_DEFINITION;
+ case ISourceTag.STYLE_Include :
+ // include is colored by the scanner
+ return null;
+ case ISourceTag.STYLE_Enumeration :
+ return SemanticHighlightings.ENUM;
+ case ISourceTag.STYLE_Undefined :
+ return null;
+ case ISourceTag.STYLE_Typedef :
+ return SemanticHighlightings.TYPEDEF;
+ default :
+ return null;
+ }
+ }
+
+ public void sourceTagsChanged(ISourceTagProvider sourceTagProvider) {
+ fSourceTags.clear();
+ if (sourceTagProvider != null) {
+ sourceTagProvider.getSourceTags(fSourceTags);
+ Collections.sort(fSourceTags, new Comparator<Object>() {
+ public int compare(Object o1, Object o2) {
+ ISourceRange sr1 = ((ISourceTag)o1).getRangeOfIdentifier();
+ ISourceRange sr2 = ((ISourceTag)o2).getRangeOfIdentifier();
+ return (sr1.getBeginOffset() - sr2.getBeginOffset());
+ }
+ });
+ }
+ }
+
+ /*
+ * @see org.eclipse.jface.text.rules.DefaultDamagerRepairer#addRange(org.eclipse.jface.text.TextPresentation, int, int, org.eclipse.jface.text.TextAttribute)
+ */
+ @Override
+ protected void addRange(TextPresentation presentation, int offset, int length, TextAttribute attr) {
+ if (length > 0 && attr != null) {
+ presentation.addStyleRange(
+ new StyleRange(offset, length, attr.getForeground(), attr.getBackground(), attr.getStyle()));
+ }
+ }
+
+ /**
+ * Test whether the given preference change affects us.
+ *
+ * @param event
+ * @return <code>true</code> if the given event affects the behavior.
+ */
+ public boolean affectsBahvior(PropertyChangeEvent event) {
+ return event.getProperty().startsWith(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX);
+ }
+
+ /**
+ * Adapt to changes in the preferences.
+ *
+ * @param event
+ */
+ public void handlePropertyChangeEvent(PropertyChangeEvent event) {
+ initTextAttributes();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/IFileRider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/IFileRider.java
new file mode 100644
index 00000000000..80a36ad0d58
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/IFileRider.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.IOException;
+
+/**
+ * IFileRider
+ */
+public interface IFileRider {
+
+ /** Set rider to position
+ * @param pos is normalized to be in range [0, f.length()]
+ */
+ public abstract void seek(int pos) throws IOException;
+
+ /**
+ * Write a char.
+ * @param c
+ */
+ public abstract void writeChar(char c) throws IOException;
+
+ /**
+ * Write a character array.
+ * @param buf
+ * @throws IOException
+ */
+ public abstract void writeChars(char[] buf) throws IOException;
+
+ /**
+ * Write n characters of an array of characters.
+ * @param buf
+ * @param n
+ * @throws IOException
+ */
+ public abstract void writeChars(char[] buf, int n) throws IOException;
+
+ /**
+ * Write n characters of an array of characters starting at an offset.
+ * @param buf
+ * @param off
+ * @param n
+ * @throws IOException
+ */
+ public abstract void writeChars(char[] buf, int off, int n) throws IOException;
+
+ /**
+ * Write n characters of a String starting at an offset.
+ * @param buf
+ * @param off
+ * @param n
+ * @throws IOException
+ */
+ public abstract void writeChars(String buf, int off, int n) throws IOException;
+
+ /**
+ * Read next character.
+ * @return next char in buffer.
+ * @throws IOException
+ */
+ public abstract char readChar() throws IOException;
+
+ /**
+ * Read as much characters as possible into a char array.
+ * @param buf
+ * @throws IOException
+ */
+ public abstract void readChars(char[] buf) throws IOException;
+
+ /**
+ * Read n characters into character array.
+ * @param buf
+ * @param n
+ * @throws IOException
+ */
+ public abstract void readChars(char[] buf, int n) throws IOException;
+
+ /**
+ * Read n characters into char array.
+ * @param buf
+ * @param off
+ * @param n
+ * @throws IOException
+ */
+ public abstract void readChars(char[] buf, int off, int n) throws IOException;
+
+ /**
+ * Read n characters into StringBuffer.
+ * @param buf
+ * @param from
+ * @param n
+ * @throws IOException
+ */
+ public abstract void readChars(StringBuffer buf, int n) throws IOException;
+
+ /**
+ * @return length of file
+ */
+ public abstract int length();
+
+ /**
+ * @return length limit of file
+ */
+ public abstract int limit();
+
+ /**
+ * @return whether this rider is readonly or not
+ */
+ public abstract boolean isReadonly();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDDocument.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDDocument.java
new file mode 100644
index 00000000000..21d8a2b8e2f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDDocument.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import org.eclipse.jface.text.AbstractDocument;
+import org.eclipse.jface.text.DefaultLineTracker;
+import org.eclipse.jface.text.ITextStore;
+
+/**
+ * Standard Document implementation with REDTextStore (splice texts)
+ * as text storage.
+ */
+public class REDDocument extends AbstractDocument {
+
+ public REDDocument() {
+ setTextStore(new REDTextStore());
+ setLineTracker(new DefaultLineTracker());
+ completeInitialization();
+ }
+
+ @Override
+ protected void finalize() {
+ dispose();
+ }
+
+ /**
+ * Free text store (delete scratchfiles).
+ */
+ public void dispose() {
+ ITextStore store = getStore();
+ if (store instanceof REDTextStore) {
+ ((REDTextStore)store).dispose();
+ setTextStore(new StringTextStore());
+ getTracker().set(""); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFile.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFile.java
new file mode 100644
index 00000000000..1f76daba692
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFile.java
@@ -0,0 +1,480 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * File with buffered character access.
+ */
+public final class REDFile {
+
+ /**
+ * File cache object.
+ * TLETODO Use CharBuffer?
+ * @invariant fSize <= fcBufSize
+ * @invariant fSize >= 0
+ * @invariant fOffset <= fFile.length()
+ */
+ private final static class Buffer {
+
+ final static int fcBufSize = 2048;
+
+ boolean fDirty;
+ int fOffset = -1;
+ int fPos;
+ int fSize;
+ char fData[] = new char[fcBufSize];
+
+ Buffer() {
+ }
+
+ /**
+ * Check if the file offset is contained in this buffer.
+ * @param pos
+ * @return
+ */
+ boolean containsOffset(int pos) {
+ return fOffset < pos || fOffset + fSize <= pos;
+ }
+
+ /**
+ * @return number of available characters.
+ */
+ public int avail() {
+ return fSize - fPos;
+ }
+
+ /**
+ * @return number of free space.
+ */
+ public int free() {
+ return fcBufSize - fPos;
+ }
+ }
+
+ final static private boolean DEBUG = false;
+
+ /** The maximum number of buffers for this file. */
+ final static public int fcNrBufs = 4;
+
+ private RandomAccessFile fFile;
+ private int fPosition;
+ private int fLength;
+ private Buffer fBuffer[] = new Buffer[fcNrBufs];
+ private byte[] fByteBuffer = new byte[2 * Buffer.fcBufSize];
+ private int fSwapper;
+ private String fName;
+ private boolean fReadonly;
+ private boolean fDeleteOnDispose;
+
+ private REDFile(File file, boolean readonly) {
+ assert !readonly || file != null;
+ fReadonly = readonly;
+ fDeleteOnDispose = file == null;
+ if (file != null) {
+ try {
+ setFile(file);
+ fLength = (int)(fFile.length() / 2);
+ } catch (IOException ioe) {
+ throw new Error(ioe);
+ }
+ }
+ }
+
+ public REDFile() {
+ this((File)null, false);
+ }
+
+ public REDFile(String name, boolean readonly) {
+ this(new File(name), readonly);
+ }
+
+ public REDFile(String name) {
+ this(name, false);
+ }
+
+ private void setFile(File file) throws IOException {
+ assert file != null;
+ if (fReadonly) {
+ fFile = new RandomAccessFile(file, "r"); //$NON-NLS-1$
+ fName = file.toString();
+ } else if (file != null) {
+ fFile = new RandomAccessFile(file, "rw"); //$NON-NLS-1$
+ fName = file.toString();
+ }
+ }
+
+ /**
+ * Free resources.
+ */
+ public void dispose() {
+ if (fFile != null) {
+ try {
+ close();
+ } catch (IOException e) {
+ }
+ fFile = null;
+ if (fDeleteOnDispose) {
+ new File(fName).delete();
+ }
+ }
+ }
+
+ public void close() throws IOException {
+ flush();
+ if (fFile != null) {
+ fFile.close();
+ }
+ }
+
+ /**
+ * Flush buffers.
+ * @throws IOException
+ */
+ public void flush() throws IOException {
+ for (int i = 0; i < fcNrBufs; i++) {
+ if (fBuffer[i] != null) {
+ if (fBuffer[i].fDirty) {
+ flush(fBuffer[i]);
+ }
+ fBuffer[i] = null;
+ }
+ }
+ }
+
+ /**
+ * Flush a dirty buffer.
+ * @param buffer
+ */
+ private void flush(Buffer buffer) throws IOException {
+ assert buffer.fDirty;
+ write(buffer.fOffset, buffer.fData, 0, buffer.fSize);
+ buffer.fDirty = false;
+ }
+
+ /**
+ * @return true if this file is readonly.
+ */
+ public boolean isReadonly() {
+ return fReadonly;
+ }
+
+ /**
+ * @return the length in char units.
+ */
+ public int length() {
+ if (fLength < 0) {
+ if (fFile == null) {
+ fLength = 0;
+ } else {
+ try {
+ fLength = (int)(fFile.length() / 2);
+ } catch (IOException e) {
+ fLength = 0;
+ }
+ }
+ }
+ return fLength;
+ }
+
+ /** erase file content
+ * @return true, if successful; false otherwise
+ * @post return == true implies length() == 0
+ */
+ public boolean purge() throws IOException {
+ if (isReadonly()) {
+ return false;
+ }
+ fFile.setLength(0);
+ for (int i = 0; i < fcNrBufs; i++) {
+ if (fBuffer[i] != null) {
+ fBuffer[i].fOffset = -1;
+ fBuffer[i].fDirty = false;
+ if (i > 0) {
+ fBuffer[i] = null;
+ }
+ }
+ }
+ fLength = 0;
+ return true;
+ }
+
+ @Override
+ protected void finalize() {
+ dispose();
+ }
+
+ private File createTmpFile() {
+ try {
+ File file = File.createTempFile("scratch", ".tmp"); //$NON-NLS-1$ //$NON-NLS-2$
+ file.deleteOnExit();
+ return file;
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ }
+
+ /**
+ * copy file - Convenience method.
+ * @pre src != null
+ * @pre dest != null
+ */
+ public static void copyFile(REDFile src, REDFile dest) throws IOException {
+ dest.purge();
+ byte buf[] = new byte[4096];
+ int n = src.fFile.read(buf);
+ while (n >= 0) {
+ if (n > 0) {
+ dest.fFile.write(buf, 0, n);
+ }
+ n = src.fFile.read(buf);
+ }
+ dest.fLength = src.length();
+ }
+
+ /**
+ * @param offset
+ */
+ public void seek(int offset) throws IOException {
+ if (offset < 0) {
+ throw new IOException("Negative seek position"); //$NON-NLS-1$
+ }
+ fPosition = offset;
+ }
+
+ /**
+ * Write char array as 16-bit Unicode at absolute position.
+ * @param position File position
+ * @param data
+ * @param offset
+ * @param length
+ * @throws IOException
+ */
+ private void write(int position, char[] data, int offset, int length) throws IOException {
+ if (DEBUG)
+ System.out.println("REDFile.write " + length + " at " + position); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fFile == null) {
+ setFile(createTmpFile());
+ }
+ fFile.seek(position * 2);
+ int blen = 0;
+ for (int clen = 0; clen < length; ++clen) {
+ char c = data[offset + clen];
+ fByteBuffer[blen++] = (byte) ((c >>> 8) & 0xff);
+ fByteBuffer[blen++] = (byte) ((c >>> 0) & 0xff);
+ if (blen == fByteBuffer.length) {
+ fFile.write(fByteBuffer, 0, blen);
+ blen = 0;
+ }
+ }
+ if (blen > 0) {
+ fFile.write(fByteBuffer, 0, blen);
+ }
+ }
+
+ /**
+ * Write char array as UTF-16 bytes (2 bytes each).
+ * @param data
+ * @param offset
+ * @param length
+ * @throws IOException
+ */
+ public void writeBuffered(char[] data, int offset, int length) throws IOException {
+ if (isReadonly()) {
+ throw new IOException("Cannot write to readonly file"); //$NON-NLS-1$
+ }
+ Buffer buffer = null;
+ int clen = 0;
+ while (clen < length) {
+ buffer = getBufferForOffset(fPosition, true);
+ int count = Math.min(length - clen, buffer.free());
+ if (count == 0) {
+ break;
+ }
+ System.arraycopy(data, offset, buffer.fData, buffer.fPos, count);
+ buffer.fPos += count;
+ if (buffer.fPos > buffer.fSize) {
+ buffer.fSize = buffer.fPos;
+ }
+ buffer.fDirty = true;
+ offset += count;
+ clen += count;
+ fPosition += count;
+ }
+ if (fPosition > fLength) {
+ fLength = fPosition;
+ }
+ }
+
+ /**
+ * Write String as UTF-16 bytes (2 bytes each).
+ * @param data
+ * @param offset
+ * @param length
+ * @throws IOException
+ */
+ public void writeBuffered(String data, int offset, int length) throws IOException {
+ if (isReadonly()) {
+ throw new IOException("Cannot write to readonly file"); //$NON-NLS-1$
+ }
+ Buffer buffer = null;
+ int clen = 0;
+ while (clen < length) {
+ buffer = getBufferForOffset(fPosition, true);
+ int count = Math.min(length - clen, buffer.free());
+ if (count == 0) {
+ break;
+ }
+ data.getChars(offset, offset + count, buffer.fData, buffer.fPos);
+ buffer.fPos += count;
+ if (buffer.fPos > buffer.fSize) {
+ buffer.fSize = buffer.fPos;
+ }
+ buffer.fDirty = true;
+ offset += count;
+ clen += count;
+ fPosition += count;
+ }
+ if (fPosition > fLength) {
+ fLength = fPosition;
+ }
+ }
+
+ /**
+ * Update the content of a buffer.
+ * @param buffer
+ * @throws IOException
+ */
+ private void update(Buffer buffer) throws IOException {
+ assert !buffer.fDirty;
+ buffer.fSize = read(buffer.fOffset, buffer.fData, 0, buffer.fData.length);
+ }
+
+ /**
+ * Read an array of characters at absolute position.
+ * @param position File position
+ * @param data
+ * @param offset
+ * @param length
+ * @return number of characters read.
+ */
+ private int read(int position, char[] data, int offset, int length) throws IOException {
+ fFile.seek(position * 2);
+ int blen = 0;
+ int bsize = length * 2;
+ while (blen < bsize) {
+ int count = fFile.read(fByteBuffer, 0, Math.min(fByteBuffer.length, bsize - blen));
+ if (count < 0) {
+ break;
+ }
+ for (int i = 0; i < count; i += 2) {
+ int hiByte = fByteBuffer[i] & 0xff;
+ int loByte = fByteBuffer[i + 1] & 0xff;
+ data[offset++] = (char) ((hiByte << 8) | (loByte << 0));
+ }
+ blen += count;
+ }
+ if (DEBUG)
+ System.out.println("REDFile.read " + length + " at " + position + " = " + blen / 2); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ // convert to character length
+ return blen / 2;
+ }
+
+ /**
+ * Read an array of characters.
+ * @param data
+ * @param offset
+ * @param length
+ * @return number of characters read.
+ */
+ public int readBuffered(char[] data, int offset, int length) throws IOException {
+ Buffer buffer;
+ int clen = 0;
+ while (clen < length) {
+ buffer = getBufferForOffset(fPosition, false);
+ int count = Math.min(length - clen, buffer.avail());
+ if (count <= 0) {
+ break;
+ }
+ System.arraycopy(buffer.fData, buffer.fPos, data, offset, count);
+ buffer.fPos += count;
+ offset += count;
+ clen += count;
+ fPosition += count;
+ }
+ return clen;
+ }
+
+ /**
+ * Read characters into StringBuffer.
+ * @param strBuf
+ * @param length
+ * @return number of characters read.
+ */
+ public int readBuffered(StringBuffer strBuf, int length) throws IOException {
+ Buffer buffer;
+ int clen = 0;
+ while (clen < length) {
+ buffer = getBufferForOffset(fPosition, false);
+ int count = Math.min(length - clen, buffer.avail());
+ if (count <= 0) {
+ break;
+ }
+ strBuf.append(buffer.fData, buffer.fPos, count);
+ buffer.fPos += count;
+ clen += count;
+ fPosition += count;
+ }
+ return clen;
+ }
+
+ /**
+ * Get a REDFileBuffer for an offset.
+ * @param pos
+ * @return
+ */
+ private Buffer getBufferForOffset(int offset, boolean write) throws IOException {
+ Buffer buffer = null;
+ int bufferOffset = (offset / Buffer.fcBufSize) * Buffer.fcBufSize;
+ int i;
+ for (i = 0; i < fcNrBufs && fBuffer[i] != null; ++i) {
+ if (bufferOffset == fBuffer[i].fOffset) {
+ buffer = fBuffer[i];
+ break;
+ }
+ }
+ if (buffer == null) {
+ if (i < REDFile.fcNrBufs) {
+ buffer = new Buffer();
+ fBuffer[i] = buffer;
+ } else {
+ fSwapper = (fSwapper + 1) % REDFile.fcNrBufs;
+ buffer = fBuffer[fSwapper];
+ if (buffer.fDirty) {
+ flush(buffer);
+ }
+ }
+ buffer.fOffset = bufferOffset;
+ buffer.fSize = 0;
+ }
+ buffer.fPos = offset - buffer.fOffset;
+ if (write && buffer.fSize < buffer.fPos || !write && buffer.avail() <= 0) {
+ if (buffer.fDirty) {
+ flush(buffer);
+ }
+ update(buffer);
+ }
+ return buffer;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFileRider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFileRider.java
new file mode 100644
index 00000000000..b75a5f7ff75
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDFileRider.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.IOException;
+
+/**
+ * Accessor to <code>REDFile</code>s.
+ */
+public final class REDFileRider implements IFileRider {
+
+ private REDFile fFile;
+ private int fLimit = Integer.MAX_VALUE;
+ private int fResult;
+ private boolean fEof;
+ private char[] fOneCharBuf = new char[1];
+
+ /** @pre f != null */
+ public REDFileRider(REDFile f) throws IOException {
+ set(f, 0);
+ }
+ public REDFileRider(REDFile f, int limit) throws IOException {
+ fLimit = limit;
+ set(f, 0);
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.internal.ui.disassembly.text.IFileRider#seek(int)
+ */
+ public void seek(int pos) throws IOException {
+ fFile.seek(pos);
+ fEof = false;
+ fResult = 0;
+ }
+
+ /**
+ * Set rider to file and position
+ *
+ * @param f the file the rider should operate on
+ * @param pos is normalized to be in range [0, f.length()]
+ * @pre f != null
+ * @pre pos >= 0 && pos <= f.length()
+ * @post fBuffer != null
+ */
+ private void set(REDFile f, int pos) throws IOException {
+
+ assert f != null;
+ assert pos >= 0 && pos <= f.length();
+
+ fFile = f;
+ fFile.seek(pos);
+ fEof = false;
+ fResult = 0;
+ }
+
+ /**
+ * Get end of file status
+ * @return true, if rider has tried to read beyond the end of file
+ */
+ public boolean eof() {
+ return fEof;
+ }
+
+ /**
+ * Get result of last operation
+ * will be 0 after successful write operation
+ * will contain nr. of characters requested but unavailable read after read operation
+ */
+ public int getResult() {
+ return fResult;
+ }
+
+ /**
+ * Get the REDFile the rider operates on.
+ * @post return != null
+ */
+ public REDFile getFile() {
+ return fFile;
+ }
+
+ public void writeChar(char c) throws IOException {
+ fOneCharBuf[0] = c;
+ writeChars(fOneCharBuf, 0, 1);
+ }
+
+ public void writeChars(char[] buf) throws IOException {
+ writeChars(buf, 0, buf.length);
+ }
+
+ public void writeChars(char[] buf, int n) throws IOException {
+ writeChars(buf, 0, n);
+ }
+
+ public void writeChars(char[] buf, int off, int n) throws IOException {
+ fFile.writeBuffered(buf, off, n);
+ fResult = 0;
+ }
+
+ public void writeChars(String buf, int off, int n) throws IOException {
+ fFile.writeBuffered(buf, off, n);
+ fResult = 0;
+ }
+
+ public char readChar() throws IOException {
+ readChars(fOneCharBuf, 0, 1);
+ return fEof ? '\0' : fOneCharBuf[0];
+ }
+
+ public void readChars(char[] buf) throws IOException {
+ readChars(buf, 0, buf.length);
+ }
+
+ public void readChars(char[] buf, int n) throws IOException {
+ readChars(buf, 0, n);
+ }
+
+ public void readChars(char[] buf, int off, int n) throws IOException {
+ int count = fFile.readBuffered(buf, off, n);
+ fResult = n-count;
+ fEof = fResult > 0;
+ }
+
+ public void readChars(StringBuffer buf, int n) throws IOException {
+ int count = fFile.readBuffered(buf, n);
+ fResult = n-count;
+ fEof = fResult > 0;
+ }
+
+ public int length() {
+ return fFile.length();
+ }
+
+ public int limit() {
+ return fLimit;
+ }
+
+ public boolean isReadonly() {
+ return fFile.isReadonly();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDRun.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDRun.java
new file mode 100644
index 00000000000..9bd27fb423c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDRun.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.IOException;
+
+/**
+ * A piece of text on a scratch file.
+ */
+public class REDRun implements CharSequence {
+
+ IFileRider fRider;
+ int fOffset;
+ int fLength;
+
+ /**
+ * @pre rider != null
+ * @pre style != null
+ * @pre length > 0
+ */
+ public REDRun(IFileRider rider, int offset, int length) {
+ fRider = rider;
+ fOffset = offset;
+ fLength = length;
+ }
+
+ /**
+ * @pre rider != null
+ * @pre style != null
+ * @pre str.length() > 0
+ */
+ public REDRun(IFileRider rider, String str) throws IOException {
+ fRider = rider;
+ fLength = str.length();
+ fOffset = fRider.length();
+ fRider.seek(fOffset);
+ fRider.writeChars(str, 0, fLength);
+ }
+
+ /**
+ * @param rider
+ * @param buf
+ * @param off
+ * @param n
+ */
+ public REDRun(IFileRider rider, char[] buf, int off, int n) throws IOException {
+ fRider = rider;
+ fLength = n;
+ fOffset = fRider.length();
+ fRider.seek(fOffset);
+ fRider.writeChars(buf, off, n);
+ }
+
+ /**
+ * @post return.length() == length()
+ */
+ public String asString() throws IOException {
+ String retVal;
+ char[] buf = new char[fLength];
+ fRider.seek(fOffset);
+ fRider.readChars(buf);
+ retVal = new String(buf);
+ return retVal;
+ }
+
+ /**
+ * Copy parts of run into char-array
+ * @param arr array to copy into
+ * @param from offset of arr to copy bytes to
+ * @param arrSize max offset of arr to write into
+ * @param myOff offset of run to start reading at
+ * @return the number of bytes copied
+ */
+ public int copyInto(char[] arr, int from, int arrSize, int myOff) throws IOException {
+ fRider.seek(fOffset + myOff);
+ int readAmount = Math.min(arrSize - from, fLength - myOff);
+ fRider.readChars(arr, from, readAmount);
+ return readAmount;
+ }
+
+ /**
+ * Append parts of run to a StringBuffer
+ * @param buffer StringBuffer to append to
+ * @param length number of characters to append
+ * @param myOff offset of run to start reading at
+ * @return the number of bytes appended
+ */
+ public int appendTo(StringBuffer buffer, int length, int myOff) throws IOException {
+ fRider.seek(fOffset + myOff);
+ int readAmount = Math.min(length, fLength - myOff);
+ fRider.readChars(buffer, readAmount);
+ return readAmount;
+ }
+
+ /**
+ * A run is mergable with another if the other a direct successor in the scratch file.
+ * @pre r != null
+ */
+ public boolean isMergeableWith(REDRun r) {
+ return r.fRider == fRider && r.fOffset == fOffset + fLength;
+ }
+
+
+ /*
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ try {
+ return asString();
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ /*
+ * @see java.lang.CharSequence#charAt(int)
+ */
+ public char charAt(int pos) {
+ try {
+ fRider.seek(fOffset + pos);
+ return fRider.readChar();
+ } catch (IOException e) {
+ return 0;
+ }
+ }
+
+ /*
+ * @see java.lang.CharSequence#subSequence(int, int)
+ */
+ public CharSequence subSequence(int start, int end) {
+ return new REDRun(fRider, fOffset + start, end - start);
+ }
+
+ /*
+ * @see java.lang.CharSequence#length()
+ */
+ public int length() {
+ return fLength;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDTextStore.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDTextStore.java
new file mode 100644
index 00000000000..cbd85dc3763
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/REDTextStore.java
@@ -0,0 +1,874 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.CharBuffer;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.text.ITextStore;
+
+/**
+ * Piece list text store implementation with scratch files.
+ */
+public final class REDTextStore implements ITextStore {
+
+ private static final int SCRATCH_FILE_THRESHOLD = 1024 * 1024;
+ private static final int MAX_SCRATCH_FILES = 4;
+ private static final int RECYCLE_THRESHOLD = 20;
+ private static final int IN_MEMORY_LIMIT = 1024 * 32;
+ private final static int CHUNK_SIZE = 1024 * 4;
+ private REDFileRider[] fScratchFiles = new REDFileRider[MAX_SCRATCH_FILES];
+ private LinkedRun fHead;
+ private LinkedRun fSpare;
+ private LinkedRun fCache;
+ private int fCachePos;
+ private int fLength;
+ private int fDeadLength;
+ private final RunSpec fRunSpec = new RunSpec();
+ private Job fSwapper;
+
+ /**
+ * This job swaps readonly IFileRider to disk.
+ */
+ private final class TextStoreSwapper extends Job {
+ private IFileRider fRider;
+ private String fText;
+
+ private TextStoreSwapper(IFileRider rider, String text) {
+ super(""); //$NON-NLS-1$
+ fRider = rider;
+ fText = text;
+ setName("Swapping editor buffer to disk"); //$NON-NLS-1$
+ setPriority(Job.LONG);
+// setSystem(true);
+ }
+
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ REDFileRider fileRider = null;
+ if (!monitor.isCanceled()) {
+ try {
+// System.out.println("TextStoreSwapper.run() creating swap file");
+ fileRider = new REDFileRider(new REDFile());
+ int size = fText.length();
+ monitor.beginTask(getName(), size+1);
+ int written = 0;
+ while (written < size && !monitor.isCanceled()) {
+ int n = Math.min(size-written, CHUNK_SIZE);
+ fileRider.writeChars(fText, written, n);
+ monitor.worked(n);
+ written += n;
+ }
+ } catch (IOException e) {
+ cancel();
+ }
+ }
+ if (!monitor.isCanceled()) {
+// System.out.println("TextStoreSwapper.run() swapping");
+ fileRider = swap(fRider, fileRider);
+ monitor.done();
+ }
+ // something went wrong, dispose the file
+ if (fileRider != null) {
+// System.out.println("TextStoreSwapper.run() disposing");
+ fileRider.getFile().dispose();
+ }
+ // remove references
+ fText = null;
+ fRider = null;
+// System.out.println("TextStoreSwapper.run() done");
+ return Status.OK_STATUS;
+ }
+ }
+
+ private final static class LinkedRun extends REDRun {
+ LinkedRun fNext;
+ LinkedRun fPrev;
+
+ LinkedRun(IFileRider rider, String str) throws IOException {
+ super(rider, str);
+ }
+ LinkedRun(IFileRider rider, char[] buf, int off, int n) throws IOException {
+ super(rider, buf, off, n);
+ }
+ LinkedRun(IFileRider rider, int offset, int length) {
+ super(rider, offset, length);
+ }
+ }
+
+ /**
+ * Create an empty text store.
+ */
+ public REDTextStore() {
+ }
+
+ /**
+ * Create a text store with intial content.
+ */
+ public REDTextStore(String text) {
+ set(text);
+ }
+
+ @Override
+ protected void finalize() {
+ dispose();
+ }
+
+ /**
+ * Free resources.
+ * Can be reactivated by calling <code>set(String)</code>.
+ */
+ public void dispose() {
+ synchronized (fRunSpec) {
+ if (fSwapper != null) {
+ fSwapper.cancel();
+ fSwapper = null;
+ }
+ for (int i = 0; i < fScratchFiles.length; ++i) {
+ if (fScratchFiles[i] != null) {
+ fScratchFiles[i].getFile().dispose();
+ fScratchFiles[i] = null;
+ }
+ }
+ fHead = null;
+ fCache = null;
+ fSpare = null;
+ fRunSpec.fRun = null;
+ fCachePos = 0;
+ fLength = 0;
+ fDeadLength = 0;
+ }
+ }
+
+ // ---- ITextStore interface ------------------------------------
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#get(int)
+ */
+ public char get(int offset) {
+ synchronized (fRunSpec) {
+ RunSpec spec = findNextRun(offset, null);
+ if (spec.fRun != null) {
+ return spec.fRun.charAt(spec.fOff);
+ }
+ return 0;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#get(int, int)
+ */
+ public String get(int offset, int length) {
+ synchronized (fRunSpec) {
+ // special case: long in-memory text in full length (about to be swapped)
+ if (length == fLength && fSwapper != null && fHead != null && fHead.fNext == null) {
+ ((StringRider)fHead.fRider).fBuffer.position(0);
+ return ((StringRider)fHead.fRider).fBuffer.toString();
+ }
+ return toString(offset, offset + length);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#getLength()
+ */
+ public int getLength() {
+ synchronized (fRunSpec) {
+ return fLength;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#set(java.lang.String)
+ */
+ public void set(String text) {
+ synchronized (fRunSpec) {
+ dispose();
+ if (text != null) {
+ fHead = new LinkedRun(new StringRider(text), 0, text.length());
+ fLength = text.length();
+ if (fLength > IN_MEMORY_LIMIT) {
+ fSwapper = new TextStoreSwapper(fHead.fRider, text);
+ fSwapper.schedule(1000);
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#replace(int, int, java.lang.String)
+ */
+ public void replace(int offset, int length, String text) {
+ synchronized (fRunSpec) {
+ if (text == null || text.length() == 0) {
+ // delete only
+ replace(offset, length, null, 0, 0);
+ } else {
+ replace(offset, length, text, 0, text.length());
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ synchronized (fRunSpec) {
+ return toString(0, getLength());
+ }
+ }
+
+ // --- implementation ----------------------------------------------------
+
+ /** Get part of the text as string.
+ * The parameters from and to are normalized to be in range: [0, fLength]
+ * Not MT-safe!
+ * @param from The beginning of the stretch of text to be returned; for from == n, the nth character is included.
+ * @param to The end of the stretch of text to be returned; for to == n, the nth character is not included.
+ * @return The stretch [from, to[ as String.
+ */
+ private String toString(int from, int to) {
+ assert from >= 0 && from <= to && to <= fLength;
+
+ int len = to - from;
+ StringBuffer strBuf = new StringBuffer(len);
+ if (len > 0) {
+ RunSpec spec = findPrevRun(from, fRunSpec);
+ try {
+ int done = spec.fRun.appendTo(strBuf, len, spec.fOff);
+ while (done < len) {
+ spec.fRun = spec.fRun.fNext;
+ assert spec.fRun != null;
+ done += spec.fRun.appendTo(strBuf, len - done, 0);
+ }
+ } catch (IOException e) {
+ internalError(e);
+ }
+ }
+ assert strBuf.length() == len;
+ return strBuf.toString();
+ }
+
+ /**
+ * Replace [from;deleteLen[ with buf[off;insertLen[
+ * Not MT-safe!
+ * @param from
+ * @param deleteLen
+ * @param buf
+ * @param off
+ * @param insertLen
+ */
+ private void replace(int from, int deleteLen, Object buf, int off, int insertLen) {
+ assert from >= 0 && from <= fLength;
+ assert deleteLen >= 0;
+ assert from + deleteLen <= fLength;
+
+ RunPair split = null;
+ if (deleteLen > 0) {
+ split = delete(from, from + deleteLen);
+ }
+ if (buf == null || insertLen == 0) {
+ return;
+ }
+// assert off >= 0 && off < buf.length;
+// assert insertLen >= 0 && off+insertLen <= buf.length;
+ if (split == null) {
+ split = splitRun(from);
+ }
+ RunPair insert = makeRuns(split.fBefore, buf, off, insertLen);
+// assert runLength(insert.fBefore, insert.fAfter) == insertLen;
+ insertRuns(split, insert.fBefore, insert.fAfter);
+ fLength += insertLen;
+// assert runLength(fHead, null) == fLength;
+ fCache = insert.fAfter;
+ fCachePos = from+insertLen-insert.fAfter.fLength;
+// assert checkConsistency();
+ if (split.fBefore != null) {
+ mergeRuns(split.fBefore, split.fAfter);
+ } else {
+ mergeRuns(fHead, split.fAfter);
+ }
+ if (fDeadLength > fLength / 10) {
+ reconcile();
+ }
+ }
+
+ /**
+ * Recreate text store by reinserting all runs.
+ * Not MT-safe!
+ */
+ public void reconcile() {
+ LinkedRun run = fHead;
+ REDFileRider[] scratchFiles = fScratchFiles;
+ fScratchFiles = new REDFileRider[MAX_SCRATCH_FILES];
+ fHead = null;
+ fCache = null;
+ fCachePos = -1;
+ fSpare = null;
+ fLength = 0;
+ fDeadLength = 0;
+ char[] buf = new char[CHUNK_SIZE];
+ int offset = 0;
+ int runOffset = 0;
+ while (run != null) {
+ int n;
+ try {
+ do {
+ n = run.copyInto(buf, 0, buf.length, runOffset);
+ replace(offset, 0, buf, 0, n);
+ offset += n;
+ runOffset += n;
+ } while (runOffset < run.fLength);
+ } catch (IOException e) {
+ internalError(e);
+ }
+ run = run.fNext;
+ runOffset = 0;
+ }
+ for (int i = 0; i < scratchFiles.length; ++i) {
+ if (scratchFiles[i] != null) {
+ scratchFiles[i].getFile().dispose();
+ scratchFiles[i] = null;
+ }
+ }
+ }
+
+ // *******************************************************************************************************************************************************
+ // P R I V A T E - L I N E
+ // *******************************************************************************************************************************************************
+
+ /**
+ * Create a new LinkedRun
+ * @param before LinkedRun before new run
+ * @param n length of content
+ * @return new LinkedRun
+ */
+ private LinkedRun createRun(LinkedRun before, int n) {
+ IFileRider scratchFile;
+ if (before != null && before.fRider.length() == before.fOffset + before.fLength && before.fRider.limit() >= before.fRider.length() + n) {
+ scratchFile = before.fRider;
+ } else {
+ scratchFile = getScratchFile();
+ }
+ return new LinkedRun(scratchFile, scratchFile.length(), n);
+ }
+
+ private REDFileRider getScratchFile() {
+ REDFileRider rider = null;
+ for (int i = 0; i < fScratchFiles.length; ++i) {
+ rider = fScratchFiles[i];
+ if (rider == null) {
+ try {
+ rider = new REDFileRider(new REDFile());
+ } catch (IOException e) {
+ internalError(e);
+ }
+ fScratchFiles[i] = rider;
+ break;
+ } else if (rider.length() < SCRATCH_FILE_THRESHOLD) {
+ break;
+ }
+ }
+ return rider;
+ }
+
+ /**
+ * Save run for later recycling.
+ * @param run
+ */
+ private void spareRun(LinkedRun run, LinkedRun last) {
+ // remove readonly runs first
+ if (last != null) {
+ last.fNext = null;
+ }
+ LinkedRun cur = run;
+ LinkedRun prev = null;
+ while (cur != null) {
+ if (cur.fRider.isReadonly()) {
+ if (prev != null) {
+ prev.fNext = cur.fNext;
+ } else {
+ run = cur.fNext;
+ }
+ if (cur.fNext != null) {
+ cur.fNext.fPrev = prev;
+ }
+ } else {
+ prev = cur;
+ }
+ cur = cur.fNext;
+ }
+ if (run == null) {
+ return;
+ }
+ last = prev;
+ if (last != null) {
+ last.fNext = fSpare;
+ }
+ if (fSpare != null) {
+ fSpare.fPrev = last;
+ }
+ fSpare = run;
+ fSpare.fPrev = null;
+ }
+
+ /**
+ * Recycle a run.
+ * @returns run
+ */
+ private LinkedRun recycleRun() {
+ LinkedRun recycled = fSpare;
+ fSpare = null;
+ return recycled;
+ }
+
+ /**
+ * @param e
+ */
+ private void internalError(Exception e) {
+ throw new Error("Internal error", e); //$NON-NLS-1$
+ }
+
+ /**
+ * REDRunSpec represents a specification of a run, including the run itself, its origin and offset.
+ * It is used for findRun - operations.
+ */
+ private final static class RunSpec {
+ public LinkedRun fRun = null;
+ public int fOrg = -1;
+ public int fOff = -1;
+ public boolean isValid() {
+ return fRun != null;
+ }
+ }
+
+ /**
+ * auxiliary class: pair of red runs
+ */
+ private final static class RunPair {
+ public LinkedRun fBefore;
+ public LinkedRun fAfter;
+ }
+
+ /**
+ * Auxiliary method to delete part of the text.
+ * from and to have gap semantics.
+ * @param from start of the stretch to be deleted.
+ * @param to end of the stretch to be deleted.
+ * @return split pos for insertion
+ */
+ private RunPair delete(int from, int to) {
+ RunPair start = splitRun(from);
+ RunPair end = splitRun(to);
+ if (start.fBefore != null) {
+ start.fBefore.fNext = end.fAfter;
+ } else {
+ fHead = end.fAfter;
+ }
+ if (end.fAfter != null) {
+ end.fAfter.fPrev = start.fBefore;
+ }
+ if (end.fAfter != null) {
+ fCache = end.fAfter;
+ fCachePos = from;
+ } else {
+ fCache = fHead;
+ fCachePos = 0;
+ }
+ fLength -= (to - from);
+ if (fLength == 0) {
+ dispose();
+ return null;
+ }
+ spareRun(start.fAfter, end.fBefore);
+ start.fAfter = end.fAfter;
+ return start;
+ }
+
+ /**
+ * Find the run which contains given position.
+ * caveat: if the given position lies between run a and b, a is returned
+ * @param pos The position to find the run for
+ * @return A run specification representing the found run. May be invalid (if given position was larger than text)
+ * @pre pos >= 0
+ * @pre pos <= length()
+ * @post return != null
+ * @post return.fOff > 0 || pos == 0
+ * @post return.fOff <= return.fRun.fLength
+ * @post return.fOrg >= 0
+ */
+ private RunSpec findPrevRun(int pos, RunSpec spec) {
+ assert pos >= 0 && pos <= fLength;
+ LinkedRun cur;
+ int curPos;
+
+ if (fCache != null && fCachePos - pos < pos) {
+ assert fCache != null;
+ cur = fCache;
+ curPos = fCachePos;
+ } else {
+ cur = fHead;
+ curPos = 0;
+ }
+ while (cur != null && pos - curPos > cur.fLength) {
+ curPos += cur.fLength;
+ cur = cur.fNext;
+ }
+ if (pos != 0) {
+ while (pos - curPos <= 0) {
+ cur = cur.fPrev;
+ curPos -= cur.fLength;
+ }
+ }
+
+ fCache = cur;
+ fCachePos = curPos;
+
+ if (spec == null) {
+ spec = fRunSpec;
+ }
+ spec.fRun = cur;
+ spec.fOrg = curPos;
+ spec.fOff = pos - curPos;
+
+ return spec;
+ }
+
+ /**
+ * Find the run which contains given position.
+ * caveat: if the given position lies between run a and b, b is returned
+ * @param pos The position to find the run for
+ * @return A run specification representing the found run. May be invalid (if given position was larger than text)
+ * @pre pos >= 0
+ * @pre pos <= length()
+ * @post return != null
+ * @post return.fOff >= 0
+ * @post return.fOff < return.fRun.fLength
+ */
+ private RunSpec findNextRun(int pos, RunSpec spec) {
+ if (pos < fLength) {
+ spec = findPrevRun(pos + 1, spec);
+ spec.fOff--;
+ } else {
+ spec = findPrevRun(pos, spec);
+ }
+ return spec;
+ }
+
+ /** Split run at pos and return pair of runs. */
+ private RunPair splitRun(int pos) {
+ RunPair p = new RunPair();
+ if (pos == 0) {
+ p.fBefore = null;
+ p.fAfter = fHead;
+ } else {
+ RunSpec spec = findPrevRun(pos, null);
+ assert spec.isValid();
+ p.fBefore = spec.fRun;
+ int len = spec.fRun.length();
+ if (spec.fOff != len) { // need to split
+ p.fAfter = new LinkedRun(p.fBefore.fRider, p.fBefore.fOffset + spec.fOff, p.fBefore.fLength - spec.fOff);
+ p.fBefore.fLength = spec.fOff;
+ p.fAfter.fNext = p.fBefore.fNext;
+ if (p.fAfter.fNext != null) {
+ p.fAfter.fNext.fPrev = p.fAfter;
+ }
+ p.fBefore.fNext = p.fAfter;
+ p.fAfter.fPrev = p.fBefore;
+ } else { // we already have a split
+ p.fAfter = p.fBefore.fNext;
+ }
+ }
+ return p;
+ }
+
+ /**
+ * Merge all runs between start and end where possible.
+ * @pre start != null
+ */
+ private void mergeRuns(LinkedRun start, LinkedRun end) {
+ LinkedRun cur = start;
+ LinkedRun next = cur.fNext;
+
+ while (cur != end && next != null) {
+ if (cur.isMergeableWith(next)) {
+ if (next == fCache) {
+ fCache = cur;
+ fCachePos -= cur.fLength;
+ }
+ cur.fLength += next.fLength;
+ cur.fNext = next.fNext;
+ if (cur.fNext != null) {
+ cur.fNext.fPrev = cur;
+ }
+ if (next == end) {
+ break;
+ }
+ } else {
+ cur = next;
+ }
+ next = cur.fNext;
+ }
+ }
+
+ private RunPair makeRuns(LinkedRun before, Object buf, int off, int n) {
+ RunPair result = new RunPair();
+ LinkedRun run;
+ LinkedRun recycled = recycleRun();
+ if (recycled != null) {
+ result.fBefore = recycled;
+ run = recycled;
+ do {
+ int count = Math.min(run.fLength, n);
+ try {
+ assert !run.fRider.isReadonly();
+ // safeguard
+ if (run.fRider.isReadonly()) {
+ run = null;
+ break;
+ }
+ run.fRider.seek(run.fOffset);
+ if (buf instanceof char[]) {
+ run.fRider.writeChars((char[])buf, off, count);
+ } else {
+ run.fRider.writeChars((String)buf, off, count);
+ }
+ if (run.fLength - count >= RECYCLE_THRESHOLD) {
+ LinkedRun next = run.fNext;
+ LinkedRun newRun = new LinkedRun(run.fRider, run.fOffset+count, run.fLength-count);
+ joinRuns(run, newRun);
+ joinRuns(newRun, next);
+ } else {
+ fDeadLength += run.fLength - count;
+ }
+ run.fLength = count;
+ off += count;
+ n -= count;
+ before = run;
+ run = run.fNext;
+ } catch (IOException e) {
+ run = null;
+// internalError(e);
+ break;
+ }
+ } while (run != null && n > 0);
+ if (run != null) {
+ // shortcut for spareRun(run, null)
+ fSpare = run;
+ }
+ }
+ if (n > 0) {
+ run = createRun(before, n);
+ if (buf instanceof char[]) {
+ try {
+ run.fRider.seek(run.fOffset);
+ run.fRider.writeChars((char[])buf, off, n);
+ } catch (IOException e) {
+// internalError(e);
+ run = new LinkedRun(new StringRider(CharBuffer.wrap((char[])buf, off, off+n)), 0, n);
+ }
+ } else {
+ try {
+ run.fRider.seek(run.fOffset);
+ run.fRider.writeChars((String)buf, off, n);
+ } catch (IOException e) {
+// internalError(e);
+ run = new LinkedRun(new StringRider(CharBuffer.wrap((String)buf, off, off+n)), 0, n);
+ }
+ }
+ if (result.fBefore == null) {
+ result.fBefore = run;
+ } else {
+ joinRuns(before, run);
+ }
+ result.fAfter = run;
+ } else {
+ result.fAfter = before;
+ }
+ return result;
+ }
+
+ private void joinRuns(LinkedRun start, LinkedRun next) {
+ assert start != next;
+ start.fNext = next;
+ if (next != null) {
+ next.fPrev = start;
+ }
+ }
+ private void insertRuns(RunPair pos, LinkedRun start, LinkedRun end) {
+ assert pos.fBefore == null || pos.fBefore != pos.fAfter;
+ start.fPrev = pos.fBefore;
+ if (pos.fBefore != null) {
+ pos.fBefore.fNext = start;
+ } else {
+ fHead = start;
+ }
+ end.fNext = pos.fAfter;
+ if (pos.fAfter != null) {
+ pos.fAfter.fPrev = end;
+ }
+ }
+
+ /**
+ * Swap given old (readonly) rider with the new (writable) one.
+ * @param oldRider
+ * @param newRider
+ * @return <code>null</code> if the new rider was consumed
+ */
+ private REDFileRider swap(IFileRider oldRider, REDFileRider newRider) {
+ synchronized(fRunSpec) {
+ // search linked run list starting from head and replace
+ // all instances of oldRider with newRider
+ // in the general case, spare list should be searched, too
+ LinkedRun cur = fHead;
+ while (cur != null) {
+ if (cur.fRider == oldRider) {
+ cur.fRider = newRider;
+ }
+ cur = cur.fNext;
+ }
+ for (int i = 0; i < fScratchFiles.length; i++) {
+ if (fScratchFiles[i] == null) {
+ fScratchFiles[i] = newRider;
+ newRider = null;
+ }
+ }
+ if (newRider != null) {
+ // unlikely, but possible: need to increase array
+ REDFileRider[] scratchFiles = new REDFileRider[fScratchFiles.length+1];
+ System.arraycopy(fScratchFiles, 0, scratchFiles, 0, fScratchFiles.length);
+ scratchFiles[fScratchFiles.length] = newRider;
+ fScratchFiles = scratchFiles;
+ newRider = null;
+ }
+ // clean out fRunSpec reference (just in case)
+ fRunSpec.fRun = null;
+ // clean out swapper reference
+ fSwapper = null;
+ }
+ return newRider;
+ }
+
+ // ---- For debugging purposes
+
+ public void printStatistics(PrintStream out) {
+ int nRuns = 0;
+ int nSpare = 0;
+ int spareLength = 0;
+ LinkedRun run = fHead;
+ while(run != null) {
+ ++nRuns;
+ run = run.fNext;
+ }
+ run = fSpare;
+ while(run != null) {
+ ++nSpare;
+ spareLength += run.fLength;
+ run = run.fNext;
+ }
+ double runMean = nRuns > 0 ? (double)fLength / nRuns : Double.NaN;
+ double spareMean = nSpare > 0 ? spareLength / nSpare : Double.NaN;
+ out.println("Length: "+fLength); //$NON-NLS-1$
+ out.println("Number of runs: "+nRuns); //$NON-NLS-1$
+ out.println("Mean length of runs: " + runMean); //$NON-NLS-1$
+ out.println("Length of spare runs: "+spareLength); //$NON-NLS-1$
+ out.println("Number of spare runs: "+nSpare); //$NON-NLS-1$
+ out.println("Mean length of spare runs: " + spareMean); //$NON-NLS-1$
+ out.println("Length of dead runs: " + fDeadLength); //$NON-NLS-1$
+ }
+
+ /**
+ * Get structure.
+ * Returns the structure (Runs) as a single string. The Runs are separated
+ * by "->\n". At the end the string "null" is added to indicate, that no
+ * more runs exist. This implies that the string "null" is returned for an
+ * empty text.
+ */
+ String getStructure() {
+ LinkedRun cur = fHead;
+ String structure = ""; //$NON-NLS-1$
+ while (cur != null) {
+ try {
+ structure += cur.asString() + "->\n"; //$NON-NLS-1$
+ } catch (IOException e) {
+ internalError(e);
+ }
+ cur = cur.fNext;
+ }
+ structure += "null"; //$NON-NLS-1$
+ return structure;
+ }
+
+ /**
+ * For debugging purposes only.
+ */
+ boolean checkConsistency() {
+ LinkedRun run = fHead;
+ int length = 0;
+ while (run != null) {
+ LinkedRun prev = run.fPrev;
+ LinkedRun next = run.fNext;
+ assert prev != run;
+ assert next != run;
+ assert prev == null || prev.fNext == run;
+ assert next == null || next.fPrev == run;
+ while (prev != null) {
+ prev = prev.fPrev;
+ assert run != prev;
+ }
+ LinkedRun spare = fSpare;
+ while (spare != null) {
+ assert run != spare;
+ spare = spare.fPrev;
+ }
+ length += run.fLength;
+ run = next;
+ }
+ assert length == fLength;
+ if (fCache != null) {
+ int pos = fCachePos;
+ run = fCache;
+ while (run.fPrev != null) {
+ run = run.fPrev;
+ pos -= run.fLength;
+ }
+ assert pos == 0;
+ pos = fCachePos;
+ run = fCache;
+ while (run != null) {
+ pos += run.fLength;
+ run = run.fNext;
+ }
+ assert pos == fLength;
+ }
+ return true;
+ }
+
+ int runLength(LinkedRun first, LinkedRun last) {
+ LinkedRun run = first;
+ int length = 0;
+ while (run != null) {
+ length += run.fLength;
+ if (run == last) {
+ break;
+ }
+ run = run.fNext;
+ }
+ return length;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringRider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringRider.java
new file mode 100644
index 00000000000..20c2eacac08
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringRider.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+
+/**
+ * StringRider
+ */
+public class StringRider implements IFileRider {
+
+ CharBuffer fBuffer;
+
+ public StringRider(CharSequence text) {
+ super();
+ // create a readonly buffer
+ fBuffer = CharBuffer.wrap(text);
+ }
+
+ public StringRider(CharBuffer buffer) {
+ super();
+ fBuffer = buffer;
+ }
+
+ public void seek(int pos) throws IOException {
+ fBuffer.position(pos);
+ }
+
+ public void writeChar(char c) throws IOException {
+ fBuffer.put(c);
+ }
+
+ public void writeChars(char[] buf) throws IOException {
+ fBuffer.put(buf);
+ }
+
+ public void writeChars(char[] buf, int n) throws IOException {
+ fBuffer.put(buf, 0, n);
+ }
+
+ public void writeChars(char[] buf, int off, int n) throws IOException {
+ fBuffer.put(buf, off, n);
+ }
+
+ public void writeChars(String buf, int off, int n) throws IOException {
+ fBuffer.put(buf, off, off+n);
+ }
+
+ public char readChar() throws IOException {
+ return fBuffer.get();
+ }
+
+ public void readChars(char[] buf) throws IOException {
+ fBuffer.get(buf, 0, buf.length);
+ }
+
+ public void readChars(char[] buf, int n) throws IOException {
+ fBuffer.get(buf, 0, n);
+ }
+
+ public void readChars(char[] buf, int off, int n) throws IOException {
+ fBuffer.get(buf, off, n);
+ }
+
+ public void readChars(StringBuffer buf, int n) throws IOException {
+ int pos = fBuffer.position();
+ if (fBuffer.hasArray()) {
+ buf.append(fBuffer.array(), fBuffer.arrayOffset() + pos, n);
+ } else {
+ fBuffer.limit(pos+n);
+ String str = fBuffer.toString();
+ assert str.length() == n;
+ buf.append(str);
+ fBuffer.limit(fBuffer.capacity());
+ }
+ fBuffer.position(pos + n);
+ }
+
+ public int length() {
+ return fBuffer.length();
+ }
+
+ public int limit() {
+ return fBuffer.limit();
+ }
+
+ public boolean isReadonly() {
+ return fBuffer.isReadOnly();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringTextStore.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringTextStore.java
new file mode 100644
index 00000000000..aea07d43213
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/text/StringTextStore.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.text;
+
+import org.eclipse.jface.text.ITextStore;
+
+/**
+ * Readonly ITextStore implementation.
+ */
+public class StringTextStore implements ITextStore {
+
+ private String fText = ""; //$NON-NLS-1$
+
+ public StringTextStore() {
+ super();
+ }
+
+ public StringTextStore(String text) {
+ super();
+ fText = text;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#get(int)
+ */
+ public char get(int offset) {
+ return fText.charAt(offset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#get(int, int)
+ */
+ public String get(int offset, int length) {
+ if (length == fText.length()) {
+ return fText;
+ }
+ return new String(fText.substring(offset, offset+length));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#getLength()
+ */
+ public int getLength() {
+ return fText.length();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#replace(int, int, java.lang.String)
+ */
+ public void replace(int offset, int length, String text) {
+ // unmodifiable
+ throw new UnsupportedOperationException();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextStore#set(java.lang.String)
+ */
+ public void set(String text) {
+ fText = text != null ? text : ""; //$NON-NLS-1$
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/HSL.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/HSL.java
new file mode 100644
index 00000000000..152ccffb0c4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/HSL.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.util;
+
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * HSL (Hue, Saturation, Luminance) color model.
+ */
+public class HSL {
+
+ public double hue;
+ public double saturation;
+ public double luminance;
+
+ /**
+ * Create HSL from RGB.
+ */
+ public HSL(RGB rgb) {
+ super();
+ double red = rgb.red / 255.0;
+ double green = rgb.green / 255.0;
+ double blue = rgb.blue / 255.0;
+ double cmax= Math.max(Math.max(red, green), blue);
+ double cmin= Math.min(Math.min(red, green), blue);
+ luminance = (cmax+cmin)/2;
+ if (cmax == cmin) {
+ hue = 0;
+ saturation = 0;
+ } else {
+ double delta = cmax-cmin;
+ if (luminance < 0.5) {
+ saturation = delta / (cmax + cmin);
+ } else {
+ saturation = delta / (2 - cmax - cmin);
+ }
+ if (red == cmax) {
+ hue = (green - blue) / delta;
+ } else if (green == cmax) {
+ hue = 2 + (blue - red) / delta;
+ } else {
+ hue = 4 + (red - green) / delta;
+ }
+ hue /= 6;
+ if (hue < 0) {
+ hue += 1;
+ } else if (hue > 1) {
+ hue -= 1;
+ }
+ }
+ }
+
+ public RGB toRGB() {
+ int red,green,blue;
+ if (saturation == 0) {
+ red = (int)Math.round(255*luminance);
+ green = red;
+ blue = red;
+ } else {
+ double m1, m2;
+ if (luminance <= 0.5) {
+ m2 = luminance * (1 + saturation);
+ } else {
+ m2 = luminance + saturation - luminance * saturation;
+ }
+ m1 = 2 * luminance - m2;
+ red = hueToColorValue(hue + 1./3., m1, m2);
+ green = hueToColorValue(hue, m1, m2);
+ blue = hueToColorValue(hue - 1./3., m1, m2);
+ }
+ return new RGB(red, green, blue);
+ }
+
+ private static int hueToColorValue(double hue, double m1, double m2) {
+ double v;
+ if (hue < 0) {
+ hue += 1;
+ } else if (hue > 1) {
+ hue -= 1;
+ }
+ if (6*hue < 1) {
+ v = m1 + (m2-m1) * hue * 6;
+ } else if (2*hue < 1) {
+ v = m2;
+ } else if (3*hue < 2) {
+ v = m1 + (m2-m1) * (2./3. - hue) * 6;
+ } else {
+ v = m1;
+ }
+ return (int)Math.round(255 * v);
+ }
+
+ /**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the <code>HSL</code>
+ */
+ @Override
+ public String toString () {
+ return "HSL {" + hue + ", " + saturation + ", " + luminance + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/StorageEditorInput.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/StorageEditorInput.java
new file mode 100644
index 00000000000..c8b8e9bbeaa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/disassembly/util/StorageEditorInput.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.disassembly.util;
+
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IPersistableElement;
+import org.eclipse.ui.IStorageEditorInput;
+
+
+/**
+ * Abstract implementation of <code>IStorageEditorInput</code>.
+ */
+abstract public class StorageEditorInput implements IStorageEditorInput {
+
+ /**
+ * Storage associated with this editor input
+ */
+ private IStorage fStorage;
+
+ /**
+ * Constructs an editor input on the given storage
+ */
+ public StorageEditorInput(IStorage storage) {
+ fStorage = storage;
+ }
+
+ /**
+ * @see IStorageEditorInput#getStorage()
+ */
+ public IStorage getStorage() {
+ return fStorage;
+ }
+
+ /**
+ * Set new storage. For subclasses only.
+ * @param storage
+ */
+ protected void setStorage(IStorage storage) {
+ assert storage != null;
+ fStorage = storage;
+ }
+
+ /**
+ * @see IEditorInput#getImageDescriptor()
+ */
+ public ImageDescriptor getImageDescriptor() {
+ return null;
+ }
+
+ /**
+ * @see IEditorInput#getName()
+ */
+ public String getName() {
+ return getStorage().getName();
+ }
+
+ /**
+ * @see IEditorInput#getPersistable()
+ */
+ public IPersistableElement getPersistable() {
+ return null;
+ }
+
+ /**
+ * @see IEditorInput#getToolTipText()
+ */
+ public String getToolTipText() {
+ return getStorage().getFullPath().toOSString();
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+ try {
+ return object instanceof IStorageEditorInput
+ && getStorage().equals(((IStorageEditorInput)object).getStorage());
+ } catch (CoreException e) {
+ }
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getStorage().hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingIntegerFieldEditor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingIntegerFieldEditor.java
new file mode 100644
index 00000000000..7d155967292
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingIntegerFieldEditor.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * An {@link IntegerFieldEditor} with field decoration.
+ *
+ * @since 1.1
+ */
+public class DecoratingIntegerFieldEditor extends IntegerFieldEditor {
+
+ private ControlDecoration fDecoration;
+
+ protected DecoratingIntegerFieldEditor() {
+ }
+
+ /**
+ * Creates an integer field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param parent the parent of the field editor's control
+ */
+ public DecoratingIntegerFieldEditor(String name, String labelText, Composite parent) {
+ super(name, labelText, parent);
+ }
+
+ /**
+ * Creates an integer field editor.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param parent the parent of the field editor's control
+ * @param textLimit the maximum number of characters in the text.
+ */
+ public DecoratingIntegerFieldEditor(String name, String labelText, Composite parent, int textLimit) {
+ super(name, labelText, parent, textLimit);
+ }
+
+ @Override
+ public Text getTextControl(Composite parent) {
+ Text control = super.getTextControl(parent);
+ if (fDecoration == null) {
+ fDecoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
+ FieldDecoration errorDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
+ fDecoration.setImage(errorDecoration.getImage());
+ fDecoration.setDescriptionText(getErrorMessage());
+
+ // validate on focus gain
+ control.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ refreshValidState();
+ }
+ });
+ }
+ return control;
+ }
+
+ @Override
+ protected void showErrorMessage(String msg) {
+ super.showErrorMessage(msg);
+ if (fDecoration != null) {
+ fDecoration.setDescriptionText(msg);
+ fDecoration.show();
+ }
+ }
+
+ @Override
+ protected void clearErrorMessage() {
+ super.clearErrorMessage();
+ if (fDecoration != null) {
+ fDecoration.hide();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingStringFieldEditor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingStringFieldEditor.java
new file mode 100644
index 00000000000..251d63b9cbe
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DecoratingStringFieldEditor.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.jface.fieldassist.ControlDecoration;
+import org.eclipse.jface.fieldassist.FieldDecoration;
+import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * A {@link StringFieldEditor} with field decoration.
+ * @since 1.1
+ */
+public class DecoratingStringFieldEditor extends StringFieldEditor {
+
+ private ControlDecoration fDecoration;
+
+ protected DecoratingStringFieldEditor() {
+ }
+
+ /**
+ * Creates a string field editor of unlimited width.
+ * Use the method <code>setTextLimit</code> to limit the text.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param parent the parent of the field editor's control
+ */
+ public DecoratingStringFieldEditor(String name, String labelText, Composite parent) {
+ super(name, labelText, parent);
+ }
+
+ /**
+ * Creates a string field editor.
+ * Use the method <code>setTextLimit</code> to limit the text.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param width the width of the text input field in characters,
+ * or <code>UNLIMITED</code> for no limit
+ * @param parent the parent of the field editor's control
+ */
+ public DecoratingStringFieldEditor(String name, String labelText, int width, Composite parent) {
+ super(name, labelText, width, parent);
+ }
+
+ /**
+ * Creates a string field editor.
+ * Use the method <code>setTextLimit</code> to limit the text.
+ *
+ * @param name the name of the preference this field editor works on
+ * @param labelText the label text of the field editor
+ * @param width the width of the text input field in characters,
+ * or <code>UNLIMITED</code> for no limit
+ * @param strategy either <code>VALIDATE_ON_KEY_STROKE</code> to perform
+ * on the fly checking (the default), or <code>VALIDATE_ON_FOCUS_LOST</code> to
+ * perform validation only after the text has been typed in
+ * @param parent the parent of the field editor's control
+ */
+ public DecoratingStringFieldEditor(String name, String labelText, int width, int strategy, Composite parent) {
+ super(name, labelText, width, strategy, parent);
+ }
+
+ @Override
+ public Text getTextControl(Composite parent) {
+ Text control = super.getTextControl(parent);
+ if (fDecoration == null) {
+ fDecoration = new ControlDecoration(control, SWT.LEFT | SWT.TOP);
+ FieldDecoration errorDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
+ fDecoration.setImage(errorDecoration.getImage());
+ fDecoration.setDescriptionText(getErrorMessage());
+
+ // validate on focus gain
+ control.addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ refreshValidState();
+ }
+ });
+ }
+ return control;
+ }
+
+ @Override
+ protected void showErrorMessage(String msg) {
+ super.showErrorMessage(msg);
+ if (fDecoration != null) {
+ fDecoration.setDescriptionText(msg);
+ fDecoration.show();
+ }
+ }
+
+ @Override
+ protected void clearErrorMessage() {
+ super.clearErrorMessage();
+ if (fDecoration != null) {
+ fDecoration.hide();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DsfDebugPreferencePage.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DsfDebugPreferencePage.java
new file mode 100644
index 00000000000..257e240bb81
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/DsfDebugPreferencePage.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.StringFieldEditor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * DSF debug preference page.
+ */
+public class DsfDebugPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+
+ /**
+ * Mandatory default constructor (executable extension).
+ */
+ public DsfDebugPreferencePage() {
+ super(FLAT);
+ IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore();
+ setPreferenceStore(store);
+ setDescription(MessagesForPreferences.DsfDebugPreferencePage_description);
+ }
+
+ /*
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ public void init(IWorkbench workbench) {
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ super.createControl(parent);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IDsfDebugUIConstants.PREFERENCE_PAGE);
+ }
+
+ @Override
+ protected void createFieldEditors() {
+ final Composite parent= getFieldEditorParent();
+ final GridLayout layout= new GridLayout();
+ layout.marginWidth= 0;
+ parent.setLayout(layout);
+
+ Group performanceGroup= new Group(parent, SWT.NONE);
+ performanceGroup.setText(MessagesForPreferences.DsfDebugPreferencePage_performanceGroup_label);
+ GridLayout groupLayout= new GridLayout(3, false);
+ performanceGroup.setLayout(groupLayout);
+ performanceGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ // stack frame limit
+ IntegerFieldEditor limitEditor= new IntegerWithBooleanFieldEditor(
+ IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE,
+ IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT,
+ MessagesForPreferences.DsfDebugPreferencePage_limitStackFrames_label,
+ performanceGroup);
+
+ limitEditor.setValidRange(1, Integer.MAX_VALUE);
+ limitEditor.setValidateStrategy(StringFieldEditor.VALIDATE_ON_FOCUS_LOST);
+ limitEditor.fillIntoGrid(performanceGroup, 3);
+ addField(limitEditor);
+
+ // sync stepping speed
+ BooleanFieldEditor syncSteppingEditor= new BooleanFieldEditor(
+ IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE,
+ MessagesForPreferences.DsfDebugPreferencePage_waitForViewUpdate_label,
+ performanceGroup);
+
+ syncSteppingEditor.fillIntoGrid(performanceGroup, 3);
+ addField(syncSteppingEditor);
+
+ // minimum step interval
+ IntegerFieldEditor minIntervalEditor= new DecoratingIntegerFieldEditor(
+ IDsfDebugUIConstants.PREF_MIN_STEP_INTERVAL,
+ MessagesForPreferences.DsfDebugPreferencePage_minStepInterval_label,
+ performanceGroup);
+
+ minIntervalEditor.setValidRange(0, 10000);
+ minIntervalEditor.fillIntoGrid(performanceGroup, 3);
+ addField(minIntervalEditor);
+
+ // need to set layout again
+ performanceGroup.setLayout(groupLayout);
+}
+
+ @Override
+ protected void adjustGridLayout() {
+ // do nothing
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/IntegerWithBooleanFieldEditor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/IntegerWithBooleanFieldEditor.java
new file mode 100644
index 00000000000..758e3ac0947
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/IntegerWithBooleanFieldEditor.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * An integer field editor with an enablement check box.
+ */
+public class IntegerWithBooleanFieldEditor extends DecoratingIntegerFieldEditor {
+
+ private final String fEnableKey;
+ private Button fCheckbox;
+ private boolean fWasSelected;
+
+ public IntegerWithBooleanFieldEditor(String enableKey, String nameKey, String labelText, Composite parent) {
+ super(nameKey, labelText, parent);
+ fEnableKey= enableKey;
+ }
+
+ public IntegerWithBooleanFieldEditor(String enableKey, String nameKey, String labelText, Composite parent, int textLimit) {
+ super(nameKey, labelText, parent, textLimit);
+ fEnableKey= enableKey;
+ }
+
+ @Override
+ protected void doFillIntoGrid(Composite parent, int numColumns) {
+ getCheckboxControl(parent);
+ super.doFillIntoGrid(parent, numColumns);
+ }
+
+ private Button getCheckboxControl(Composite parent) {
+ if (fCheckbox == null) {
+ Composite inner= new Composite(parent, SWT.NULL);
+ final GridLayout layout= new GridLayout(2, false);
+ layout.marginWidth = 0;
+ inner.setLayout(layout);
+ fCheckbox= new Button(inner, SWT.CHECK);
+ fCheckbox.setFont(parent.getFont());
+ fCheckbox.setText(getLabelText());
+ // create and hide label from base class
+ Label label = getLabelControl(inner);
+ label.setText(""); //$NON-NLS-1$
+ label.setVisible(false);
+ fCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean isSelected = fCheckbox.getSelection();
+ valueChanged(fWasSelected, isSelected);
+ fWasSelected = isSelected;
+ }
+ });
+ } else {
+ checkParent(fCheckbox.getParent(), parent);
+ }
+ return fCheckbox;
+ }
+
+ @Override
+ public Label getLabelControl(Composite parent) {
+ final Label label= getLabelControl();
+ if (label == null) {
+ return super.getLabelControl(parent);
+ } else {
+ checkParent(label.getParent(), parent);
+ }
+ return label;
+ }
+
+ protected void valueChanged(boolean oldValue, boolean newValue) {
+ if (oldValue != newValue) {
+ valueChanged();
+ fireStateChanged(VALUE, oldValue, newValue);
+ getTextControl().setEnabled(newValue);
+ getLabelControl().setEnabled(newValue);
+ }
+ }
+
+ @Override
+ protected boolean checkState() {
+ if (fCheckbox != null && !fCheckbox.getSelection()) {
+ clearErrorMessage();
+ return true;
+ }
+ return super.checkState();
+ }
+
+ @Override
+ protected void doLoad() {
+ super.doLoad();
+ if (fCheckbox != null) {
+ boolean value = getPreferenceStore().getBoolean(fEnableKey);
+ fCheckbox.setSelection(value);
+ fWasSelected = value;
+ getTextControl().setEnabled(value);
+ getLabelControl().setEnabled(value);
+ }
+ }
+
+ @Override
+ protected void doLoadDefault() {
+ super.doLoadDefault();
+ if (fCheckbox != null) {
+ boolean value = getPreferenceStore().getDefaultBoolean(fEnableKey);
+ fCheckbox.setSelection(value);
+ fWasSelected = value;
+ getTextControl().setEnabled(value);
+ getLabelControl().setEnabled(value);
+ }
+ }
+
+ @Override
+ protected void doStore() {
+ super.doStore();
+ getPreferenceStore().setValue(fEnableKey, fCheckbox.getSelection());
+ }
+
+ /**
+ * Returns this field editor's current boolean value.
+ *
+ * @return the value
+ */
+ public boolean getBooleanValue() {
+ return fCheckbox.getSelection();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/MessagesForPreferences.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/MessagesForPreferences.java
new file mode 100644
index 00000000000..24495fd1cc8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/MessagesForPreferences.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Preference strings.
+ */
+class MessagesForPreferences extends NLS {
+ private static final String BUNDLE_NAME= "org.eclipse.cdt.dsf.debug.internal.ui.preferences.messages"; //$NON-NLS-1$
+
+ public static String DsfDebugPreferencePage_description;
+ public static String DsfDebugPreferencePage_limitStackFrames_label;
+
+ public static String DsfDebugPreferencePage_minStepInterval_label;
+ public static String DsfDebugPreferencePage_performanceGroup_label;
+
+ public static String DsfDebugPreferencePage_waitForViewUpdate_label;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForPreferences.class);
+ }
+
+ private MessagesForPreferences() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/StringWithBooleanFieldEditor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/StringWithBooleanFieldEditor.java
new file mode 100644
index 00000000000..0a131ba1ce1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/StringWithBooleanFieldEditor.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.internal.ui.preferences;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * A string field editor with an enablement check box.
+ */
+public class StringWithBooleanFieldEditor extends DecoratingStringFieldEditor {
+
+ private final String fEnableKey;
+ private Button fCheckbox;
+ private boolean fWasSelected;
+
+ public StringWithBooleanFieldEditor(String enableKey, String nameKey, String labelText, Composite parent) {
+ super(nameKey, labelText, parent);
+ fEnableKey= enableKey;
+ }
+
+ public StringWithBooleanFieldEditor(String enableKey, String nameKey, String labelText, int width, Composite parent) {
+ super(nameKey, labelText, width, parent);
+ fEnableKey= enableKey;
+ }
+
+ public StringWithBooleanFieldEditor(String enableKey, String nameKey, String labelText, int width, int strategy, Composite parent) {
+ super(nameKey, labelText, width, strategy, parent);
+ fEnableKey= enableKey;
+ }
+
+ @Override
+ protected void doFillIntoGrid(Composite parent, int numColumns) {
+ getCheckboxControl(parent);
+ super.doFillIntoGrid(parent, numColumns);
+ }
+
+ private Button getCheckboxControl(Composite parent) {
+ if (fCheckbox == null) {
+ Composite inner= new Composite(parent, SWT.NULL);
+ final GridLayout layout= new GridLayout(2, false);
+ layout.marginWidth = 0;
+ inner.setLayout(layout);
+ fCheckbox= new Button(inner, SWT.CHECK);
+ fCheckbox.setFont(parent.getFont());
+ fCheckbox.setText(getLabelText());
+ // create and hide label from base class
+ Label label = getLabelControl(inner);
+ label.setText(""); //$NON-NLS-1$
+ label.setVisible(false);
+ fCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean isSelected = fCheckbox.getSelection();
+ valueChanged(fWasSelected, isSelected);
+ fWasSelected = isSelected;
+ }
+ });
+ } else {
+ checkParent(fCheckbox.getParent(), parent);
+ }
+ return fCheckbox;
+ }
+
+ @Override
+ public Label getLabelControl(Composite parent) {
+ final Label label= getLabelControl();
+ if (label == null) {
+ return super.getLabelControl(parent);
+ } else {
+ checkParent(label.getParent(), parent);
+ }
+ return label;
+ }
+
+ protected void valueChanged(boolean oldValue, boolean newValue) {
+ if (oldValue != newValue) {
+ valueChanged();
+ fireStateChanged(VALUE, oldValue, newValue);
+ getTextControl().setEnabled(newValue);
+ getLabelControl().setEnabled(newValue);
+ }
+ }
+
+ @Override
+ protected boolean checkState() {
+ if (fCheckbox != null && !fCheckbox.getSelection()) {
+ clearErrorMessage();
+ return true;
+ }
+ return super.checkState();
+ }
+
+ @Override
+ protected void doLoad() {
+ super.doLoad();
+ if (fCheckbox != null) {
+ boolean value = getPreferenceStore().getBoolean(fEnableKey);
+ fCheckbox.setSelection(value);
+ fWasSelected = value;
+ getTextControl().setEnabled(value);
+ getLabelControl().setEnabled(value);
+ }
+ }
+
+ @Override
+ protected void doLoadDefault() {
+ super.doLoadDefault();
+ if (fCheckbox != null) {
+ boolean value = getPreferenceStore().getDefaultBoolean(fEnableKey);
+ fCheckbox.setSelection(value);
+ fWasSelected = value;
+ getTextControl().setEnabled(value);
+ getLabelControl().setEnabled(value);
+ }
+ }
+
+ @Override
+ protected void doStore() {
+ super.doStore();
+ getPreferenceStore().setValue(fEnableKey, fCheckbox.getSelection());
+ }
+
+ /**
+ * Returns this field editor's current boolean value.
+ *
+ * @return the value
+ */
+ public boolean getBooleanValue() {
+ return fCheckbox.getSelection();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/messages.properties
new file mode 100644
index 00000000000..9452d1f5779
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/preferences/messages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2008 Wind River Systems 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
+###############################################################################
+
+DsfDebugPreferencePage_description=General settings for debuggers using Debug Services Framework (DSF):
+DsfDebugPreferencePage_limitStackFrames_label=Limit number of stack frames to
+DsfDebugPreferencePage_minStepInterval_label=Minimum interval between steps (in milliseconds)
+DsfDebugPreferencePage_performanceGroup_label=Performance
+DsfDebugPreferencePage_waitForViewUpdate_label=Wait for views to update after every step
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/MessagesForVMActions.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/MessagesForVMActions.java
new file mode 100644
index 00000000000..267f2f0db79
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/MessagesForVMActions.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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:
+ * Wind River Systems, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForVMActions extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions.messages"; //$NON-NLS-1$
+
+ public static String RetargetDebugContextAction_ErrorDialog_title;
+ public static String RetargetDebugContextAction_ErrorDialog_message;
+
+ public static String UpdatePoliciesContribution_EmptyPoliciesList_label;
+ public static String UpdateScopesContribution_EmptyScopesList_label;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForVMActions.class);
+ }
+
+ private MessagesForVMActions() {}
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshActionDelegate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshActionDelegate.java
new file mode 100644
index 00000000000..2c8be222e94
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshActionDelegate.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IViewPart;
+
+/**
+ *
+ */
+public class RefreshActionDelegate extends AbstractVMProviderActionDelegate {
+
+ public void run(IAction action) {
+ IVMProvider provider = getVMProvider();
+ if (provider instanceof ICachingVMProvider) {
+ ((ICachingVMProvider)provider).refresh();
+ }
+ }
+
+ @Override
+ public void init(IViewPart view) {
+ super.init(view);
+ getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
+ }
+
+ @Override
+ public void debugContextChanged(DebugContextEvent event) {
+ super.debugContextChanged(event);
+ getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ getAction().setEnabled(getVMProvider() instanceof ICachingVMProvider);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshAllRetargetAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshAllRetargetAction.java
new file mode 100644
index 00000000000..b07ab995be6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshAllRetargetAction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.IRefreshAllTarget;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ *
+ */
+public class RefreshAllRetargetAction extends RetargetDebugContextAction {
+
+ @Override
+ protected boolean canPerformAction(Object target, ISelection selection) {
+ return true;
+ }
+
+ @Override
+ protected Class<?> getAdapterClass() {
+ return IRefreshAllTarget.class;
+ }
+
+ @Override
+ protected void performAction(Object target, ISelection debugContext) throws CoreException {
+ ((IRefreshAllTarget)target).refresh(debugContext);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshHandler.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshHandler.java
new file mode 100644
index 00000000000..46ab3da66e7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RefreshHandler.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+
+public class RefreshHandler extends AbstractHandler {
+
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IVMProvider vmProvider = VMHandlerUtils.getActiveVMProvider(event);
+
+ if (vmProvider instanceof ICachingVMProvider) {
+ ((ICachingVMProvider)vmProvider).refresh();
+ }
+
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RetargetDebugContextAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RetargetDebugContextAction.java
new file mode 100644
index 00000000000..ed46192c29d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/RetargetDebugContextAction.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems, Inc. - initial implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IAdapterManager;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.debug.ui.contexts.IDebugContextService;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+
+/**
+ * Base class for actions which delegate functionality to an adapter retrieved
+ * from the current debug context.
+ *
+ * @since 1.1
+ */
+abstract public class RetargetDebugContextAction implements IWorkbenchWindowActionDelegate, IDebugContextListener, IActionDelegate2 {
+
+ private IWorkbenchWindow fWindow = null;
+ private IAction fAction = null;
+ private ISelection fDebugContext;
+ private Object fTargetAdapter = null;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
+ */
+ public void init(IWorkbenchWindow window) {
+ fWindow = window;
+ IDebugContextService debugContextService = DebugUITools.getDebugContextManager().getContextService(fWindow);
+ debugContextService.addPostDebugContextListener(this);
+ fDebugContext = debugContextService.getActiveContext();
+ update();
+ }
+
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if (fAction != action) {
+ fAction = action;
+ }
+ // Update on debug context changed events
+ }
+
+ public void runWithEvent(IAction action, Event event) {
+ run(action);
+ }
+
+ public void run(IAction action) {
+ if (fTargetAdapter != null) {
+ try {
+ performAction(fTargetAdapter, fDebugContext);
+ } catch (CoreException e) {
+ ErrorDialog.openError(fWindow.getShell(), MessagesForVMActions.RetargetDebugContextAction_ErrorDialog_title, MessagesForVMActions.RetargetDebugContextAction_ErrorDialog_message, e.getStatus());
+ }
+ }
+ }
+
+ /**
+ * Returns whether the specific operation is supported.
+ *
+ * @param target the target adapter
+ * @param selection the selection to verify the operation on
+ * @param part the part the operation has been requested on
+ * @return whether the operation can be performed
+ */
+ protected abstract boolean canPerformAction(Object target, ISelection debugContext);
+
+ /**
+ * Performs the specific breakpoint toggling.
+ *
+ * @param selection selection in the active part
+ * @param part active part
+ * @throws CoreException if an exception occurrs
+ */
+ protected abstract void performAction(Object target, ISelection debugContext) throws CoreException;
+
+ /**
+ * Returns the type of adapter (target) this action works on.
+ *
+ * @return the type of adapter this action works on
+ */
+ protected abstract Class<?> getAdapterClass();
+
+ public void init(IAction action) {
+ fAction = action;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ */
+ public void update() {
+ if (fAction == null) {
+ return;
+ }
+ fTargetAdapter = null;
+ if (fDebugContext instanceof IStructuredSelection) {
+ IStructuredSelection ss = (IStructuredSelection) fDebugContext;
+ if (!ss.isEmpty()) {
+ Object object = ss.getFirstElement();
+ if (object instanceof IAdaptable) {
+ fTargetAdapter = getAdapter((IAdaptable) object);
+ if (fTargetAdapter != null) {
+ fAction.setEnabled(canPerformAction(fTargetAdapter, fDebugContext));
+ return;
+ }
+ }
+ }
+ }
+ fAction.setEnabled(false);
+ }
+
+ public void dispose() {
+ DebugUITools.getDebugContextManager().getContextService(fWindow).removePostDebugContextListener(this);
+ fTargetAdapter = null;
+ }
+
+ public void debugContextChanged(DebugContextEvent event) {
+ fDebugContext = event.getContext();
+ update();
+ }
+
+ protected Object getAdapter(IAdaptable adaptable) {
+ Object adapter = adaptable.getAdapter(getAdapterClass());
+ if (adapter == null) {
+ IAdapterManager adapterManager = Platform.getAdapterManager();
+ if (adapterManager.hasAdapter(adaptable, getAdapterClass().getName())) {
+ fTargetAdapter = adapterManager.loadAdapter(adaptable, getAdapterClass().getName());
+ }
+ }
+ return adapter;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesContribution.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesContribution.java
new file mode 100644
index 00000000000..93a79b5d819
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesContribution.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.actions.CompoundContributionItem;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Dynamic menu contribution that shows available update policies
+ * in the current view.
+ *
+ * @since 1.1
+ */
+public class UpdatePoliciesContribution extends CompoundContributionItem implements IWorkbenchContribution {
+
+ private class SelectUpdatePolicyAction extends Action {
+ private final ICachingVMProvider fProvider;
+ private final IVMUpdatePolicy fPolicy;
+ SelectUpdatePolicyAction(ICachingVMProvider provider, IVMUpdatePolicy policy) {
+ super(policy.getName(), AS_RADIO_BUTTON);
+ fProvider = provider;
+ fPolicy = policy;
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ fProvider.setActiveUpdatePolicy(fPolicy);
+ }
+ }
+ }
+
+ private IServiceLocator fServiceLocator;
+
+ private static IContributionItem[] NO_UPDATE_POLICIES_CONTRIBUTION_ITEMS = new IContributionItem[] {
+ new ContributionItem() {
+ @Override
+ public void fill(Menu menu, int index) {
+ MenuItem item = new MenuItem(menu, SWT.NONE);
+ item.setEnabled(false);
+ item.setText(MessagesForVMActions.UpdatePoliciesContribution_EmptyPoliciesList_label);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+ }
+ };
+
+ @Override
+ protected IContributionItem[] getContributionItems() {
+ IVMProvider provider = VMHandlerUtils.getActiveVMProvider(fServiceLocator);
+
+ // If no part or selection, disable all.
+ if (provider == null || !(provider instanceof ICachingVMProvider)) {
+ return NO_UPDATE_POLICIES_CONTRIBUTION_ITEMS;
+ }
+ ICachingVMProvider cachingProvider = (ICachingVMProvider)provider;
+
+ IVMUpdatePolicy[] policies = cachingProvider.getAvailableUpdatePolicies();
+ IVMUpdatePolicy activePolicy = cachingProvider.getActiveUpdatePolicy();
+
+ List<Action> actions = new ArrayList<Action>(policies.length);
+ for (IVMUpdatePolicy policy : policies) {
+ Action action = new SelectUpdatePolicyAction(cachingProvider, policy);
+ if (policy.getID().equals(activePolicy.getID())) {
+ action.setChecked(true);
+ }
+ actions.add(action);
+ }
+
+ if ( actions.isEmpty() ) {
+ return NO_UPDATE_POLICIES_CONTRIBUTION_ITEMS;
+ }
+
+ IContributionItem[] items = new IContributionItem[actions.size()];
+ for (int i = 0; i < actions.size(); i++) {
+ items[i] = new ActionContributionItem(actions.get(i));
+ }
+ return items;
+ }
+
+ public void initialize(IServiceLocator serviceLocator) {
+ fServiceLocator = serviceLocator;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesPropertyTester.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesPropertyTester.java
new file mode 100644
index 00000000000..dd2d48aa675
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdatePoliciesPropertyTester.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Property tester for update policy information available through the given
+ * object. The object being tested should be either an {@link IVMContext},
+ * through which an instance of {@link ICachingVMProvider} could be obtained.
+ * Or it could be an {@link IWorkbenchPart}, which is tested to see if it
+ * is a debug view through which a caching VM provider can be obtained.
+ * The Caching View Model provider is used to test the given property.
+ * <p>
+ * Three properties are supported:
+ * <ul>
+ * <li> "areUpdatePoliciesSupported" - Checks whether update policies are
+ * available at all given the receiver.</li>
+ * <li> "isUpdatePolicyAvailable" - Checks whether the update policy in the
+ * expected value is available for the given receiver.</li>
+ * <li> "isUpdatePolicyActive" - Checks whether the policy given in the expected
+ * value is the currently active policy for the given receiver.</li>
+ * </ul>
+ * </p>
+ */
+public class UpdatePoliciesPropertyTester extends PropertyTester {
+
+ private static final String SUPPORTED = "areUpdatePoliciesSupported"; //$NON-NLS-1$
+ private static final String AVAILABLE = "isUpdatePolicyAvailable"; //$NON-NLS-1$
+ private static final String ACTIVE = "isUpdatePolicyActive"; //$NON-NLS-1$
+
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ if (receiver instanceof IVMContext) {
+ IVMProvider provider = ((IVMContext)receiver).getVMNode().getVMProvider();
+ if (provider instanceof ICachingVMProvider) {
+ return testProvider((ICachingVMProvider)provider, property, expectedValue);
+ }
+ } else if (receiver instanceof IDebugView) {
+ IVMProvider provider = VMHandlerUtils.getVMProviderForPart((IDebugView)receiver);
+ if (provider instanceof ICachingVMProvider) {
+ return testProvider((ICachingVMProvider)provider, property, expectedValue);
+ }
+ }
+ return false;
+ }
+
+ private boolean testProvider(ICachingVMProvider provider, String property, Object expectedValue) {
+ if (SUPPORTED.equals(property)) {
+ return true;
+ } else if (AVAILABLE.equals(property)) {
+ for (IVMUpdatePolicy policy : provider.getAvailableUpdatePolicies()) {
+ if (policy.getID().equals(expectedValue)) {
+ return true;
+ }
+ return false;
+ }
+ } else if (ACTIVE.equals(property)) {
+ return expectedValue != null && expectedValue.equals(provider.getActiveUpdatePolicy().getID());
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesContribution.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesContribution.java
new file mode 100644
index 00000000000..a4770e0ff34
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesContribution.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProviderExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdateScope;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.actions.CompoundContributionItem;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Dynamic menu contribution that shows available update scopes
+ * in the current view.
+ *
+ * @since 1.1
+ */
+public class UpdateScopesContribution extends CompoundContributionItem implements IWorkbenchContribution {
+
+ private class SelectUpdateScopeAction extends Action {
+ private final ICachingVMProviderExtension fProvider;
+ private final IVMUpdateScope fScope;
+ SelectUpdateScopeAction(ICachingVMProviderExtension provider, IVMUpdateScope scope) {
+ super(scope.getName(), AS_RADIO_BUTTON);
+ fProvider = provider;
+ fScope = scope;
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ fProvider.setActiveUpdateScope(fScope);
+ }
+ }
+ }
+
+ private IServiceLocator fServiceLocator;
+
+ private static IContributionItem[] NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS = new IContributionItem[] {
+ new ContributionItem() {
+ @Override
+ public void fill(Menu menu, int index) {
+ MenuItem item = new MenuItem(menu, SWT.NONE);
+ item.setEnabled(false);
+ item.setText(MessagesForVMActions.UpdateScopesContribution_EmptyScopesList_label);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+ }
+ };
+
+ @Override
+ protected IContributionItem[] getContributionItems() {
+ IVMProvider provider = VMHandlerUtils.getActiveVMProvider(fServiceLocator);
+
+ // If no part or selection, disable all.
+ if (provider == null || !(provider instanceof ICachingVMProviderExtension)) {
+ return NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS;
+ }
+ ICachingVMProviderExtension cachingProvider = (ICachingVMProviderExtension)provider;
+
+ IVMUpdateScope[] scopes = cachingProvider.getAvailableUpdateScopes();
+ IVMUpdateScope activeScope = cachingProvider.getActiveUpdateScope();
+
+ List<Action> actions = new ArrayList<Action>(scopes.length);
+ for (IVMUpdateScope scope : scopes) {
+ Action action = new SelectUpdateScopeAction(cachingProvider, scope);
+ if (scope.getID().equals(activeScope.getID())) {
+ action.setChecked(true);
+ }
+ actions.add(action);
+ }
+
+ if ( actions.isEmpty() ) {
+ return NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS;
+ }
+
+ IContributionItem[] items = new IContributionItem[actions.size()];
+ for (int i = 0; i < actions.size(); i++) {
+ items[i] = new ActionContributionItem(actions.get(i));
+ }
+ return items;
+ }
+
+ public void initialize(IServiceLocator serviceLocator) {
+ fServiceLocator = serviceLocator;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesPropertyTester.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesPropertyTester.java
new file mode 100644
index 00000000000..752c71ce86d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/UpdateScopesPropertyTester.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.internal.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProviderExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdateScope;
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Property tester for update scope information available through the given
+ * object. The object being tested should be either an {@link IVMContext},
+ * through which an instance of {@link ICachingVMProviderExtension} could be obtained.
+ * Or it could be an {@link IWorkbenchPart}, which is tested to see if it
+ * is a debug view through which a caching VM provider can be obtained.
+ * The Caching View Model provider is used to test the given property.
+ * <p>
+ * Three properties are supported:
+ * <ul>
+ * <li> "areUpdateScopesSupported" - Checks whether update scopes are
+ * available at all given the receiver.</li>
+ * <li> "isUpdateScopeAvailable" - Checks whether the update scope in the
+ * expected value is available for the given receiver.</li>
+ * <li> "isUpdateScopeActive" - Checks whether the scope given in the expected
+ * value is the currently active scope for the given receiver.</li>
+ * </ul>
+ * </p>
+ */
+public class UpdateScopesPropertyTester extends PropertyTester {
+
+ private static final String SUPPORTED = "areUpdateScopesSupported"; //$NON-NLS-1$
+ private static final String AVAILABLE = "isUpdateScopeAvailable"; //$NON-NLS-1$
+ private static final String ACTIVE = "isUpdateScopeActive"; //$NON-NLS-1$
+
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ if (receiver instanceof IVMContext) {
+ IVMProvider provider = ((IVMContext)receiver).getVMNode().getVMProvider();
+ if (provider instanceof ICachingVMProviderExtension) {
+ return testProvider((ICachingVMProviderExtension)provider, property, expectedValue);
+ }
+ } else if (receiver instanceof IDebugView) {
+ IVMProvider provider = VMHandlerUtils.getVMProviderForPart((IDebugView)receiver);
+ if (provider instanceof ICachingVMProviderExtension) {
+ return testProvider((ICachingVMProviderExtension)provider, property, expectedValue);
+ }
+ }
+ return false;
+ }
+
+ private boolean testProvider(ICachingVMProviderExtension provider, String property, Object expectedValue) {
+ if (SUPPORTED.equals(property)) {
+ return true;
+ } else if (AVAILABLE.equals(property)) {
+ for (IVMUpdateScope scope : provider.getAvailableUpdateScopes()) {
+ if (scope.getID().equals(expectedValue)) {
+ return true;
+ }
+ return false;
+ }
+ } else if (ACTIVE.equals(property)) {
+ return expectedValue != null && expectedValue.equals(provider.getActiveUpdateScope().getID());
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/messages.properties
new file mode 100644
index 00000000000..2d2ad435bfd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/actions/messages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2006, 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:
+# Wind River Systems Inc - copied for non-restricted version for DSDP/DD/DSF
+###############################################################################
+
+RetargetDebugContextAction_ErrorDialog_title=Error
+RetargetDebugContextAction_ErrorDialog_message=Operation failed
+
+UpdatePoliciesContribution_EmptyPoliciesList_label=No update policies for current selection
+UpdateScopesContribution_EmptyScopesList_label=No update scopes for current selection
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthAction.java
new file mode 100644
index 00000000000..b6ac175becc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthAction.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;
+
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.jface.action.Action;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Opens a dialog so that the user can enter the maximum length in characters that
+ * the detail pane should display.
+ *
+ * @see DetailPaneMaxLengthDialog
+ * @since 3.0
+ */
+public class DetailPaneMaxLengthAction extends Action {
+
+ private Shell fDialogShell;
+
+ public DetailPaneMaxLengthAction(Shell dialogShell){
+ super(MessagesForDetailPane.PaneMaxLengthAction_MaxLength);
+ fDialogShell = dialogShell;
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDsfDebugUIConstants.DETAIL_PANE_MAX_LENGTH_ACTION);
+
+ }
+
+ @Override
+ public void run() {
+ DetailPaneMaxLengthDialog dialog = new DetailPaneMaxLengthDialog(fDialogShell);
+ dialog.open();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthDialog.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthDialog.java
new file mode 100644
index 00000000000..6d12c00ace1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneMaxLengthDialog.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;
+
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.TrayDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Provides a dialog for changing the maximum length allowed in the detail pane
+ *
+ * @since 3.0
+ */
+public class DetailPaneMaxLengthDialog extends TrayDialog {
+
+ private static final String SETTINGS_ID = DsfUIPlugin.PLUGIN_ID + ".MAX_DETAILS_LENGTH_DIALOG"; //$NON-NLS-1$
+
+ private Text fTextWidget;
+ private Text fErrorTextWidget;
+ private String fErrorMessage;
+ private String fValue;
+ private IInputValidator fValidator;
+
+ /**
+ * Constructs a new dialog on the given shell.
+ *
+ * @param parent shell
+ */
+ public DetailPaneMaxLengthDialog(Shell parent) {
+ super(parent);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ fValue = Integer.toString(DsfUIPlugin.getDefault().getPreferenceStore().getInt(IDsfDebugUIConstants.PREF_MAX_DETAIL_LENGTH));
+ fValidator = new IInputValidator() {
+ public String isValid(String newText) {
+ try {
+ int num = Integer.parseInt(newText);
+ if (num < 0) {
+ return MessagesForDetailPane.PaneMaxLengthDialog_IntegerCannotBeNegative;
+ }
+ } catch (NumberFormatException e) {
+ return MessagesForDetailPane.PaneMaxLengthDialog_EnterAnInteger;
+ }
+ return null;
+ }
+
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.dialogs.SelectionDialog#getDialogBoundsSettings()
+ */
+ @Override
+ protected IDialogSettings getDialogBoundsSettings() {
+ IDialogSettings settings = DsfUIPlugin.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(SETTINGS_ID);
+ if (section == null) {
+ section = settings.addNewSection(SETTINGS_ID);
+ }
+ return section;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#createContents(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createContents(Composite parent) {
+ getShell().setText(MessagesForDetailPane.PaneMaxLengthDialog_ConfigureDetails);
+ Control contents = super.createContents(parent);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(getDialogArea(), IDsfDebugUIConstants.DETAIL_PANE_MAX_LENGTH_ACTION);
+ return contents;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ Label label = new Label(composite, SWT.WRAP);
+ label.setText(MessagesForDetailPane.PaneMaxLengthDialog_MaxCharactersToDisplay);
+ GridData data = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
+ data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+ label.setLayoutData(data);
+ label.setFont(parent.getFont());
+ fTextWidget = new Text(composite, SWT.SINGLE | SWT.BORDER);
+ fTextWidget.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
+ fTextWidget.setText(fValue);
+ fTextWidget.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validateInput();
+ fValue = fTextWidget.getText();
+ }
+ });
+ fErrorTextWidget = new Text(composite, SWT.READ_ONLY);
+ fErrorTextWidget.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
+ | GridData.HORIZONTAL_ALIGN_FILL));
+ fErrorTextWidget.setBackground(fErrorTextWidget.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+ setErrorMessage(fErrorMessage);
+ applyDialogFont(composite);
+ return composite;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.Dialog#okPressed()
+ */
+ @Override
+ protected void okPressed() {
+ String text = getValue();
+ try {
+ DsfUIPlugin.getDefault().getPreferenceStore().setValue(IDsfDebugUIConstants.PREF_MAX_DETAIL_LENGTH, Integer.parseInt(text));
+ }
+ catch (NumberFormatException e) {
+ DsfUIPlugin.log(e);
+ }
+ super.okPressed();
+ }
+
+ /**
+ * Returns the string typed into this input dialog.
+ *
+ * @return the input string
+ * @since 3.3
+ */
+ public String getValue() {
+ return fValue;
+ }
+
+ /**
+ * Validates the current input
+ * @since 3.3
+ */
+ private void validateInput() {
+ String errorMessage = null;
+ if (fValidator != null) {
+ errorMessage = fValidator.isValid(fTextWidget.getText());
+ }
+ setErrorMessage(errorMessage);
+ }
+
+ /**
+ * Sets the current error message or none if null
+ * @param errorMessage
+ * @since 3.3
+ */
+ public void setErrorMessage(String errorMessage) {
+ fErrorMessage = errorMessage;
+ if (fErrorTextWidget != null && !fErrorTextWidget.isDisposed()) {
+ fErrorTextWidget.setText(errorMessage == null ? "" : errorMessage); //$NON-NLS-1$
+ fErrorTextWidget.getParent().update();
+ // Access the ok button by id, in case clients have overridden button creation.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=113643
+ Control button = getButton(IDialogConstants.OK_ID);
+ if (button != null) {
+ button.setEnabled(errorMessage == null);
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneWordWrapAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneWordWrapAction.java
new file mode 100644
index 00000000000..1458aeb22fc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/DetailPaneWordWrapAction.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;
+
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * An check box action that allows the word wrap property to be set, determining if the detail pane
+ * should wrap text.
+ */
+public class DetailPaneWordWrapAction extends Action {
+
+ ITextViewer fTextViewer;
+
+ public DetailPaneWordWrapAction(ITextViewer textViewer) {
+ super(MessagesForDetailPane.PaneWordWrapAction_WrapText,IAction.AS_CHECK_BOX);
+
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IDsfDebugUIConstants.DETAIL_PANE_WORD_WRAP_ACTION);
+
+ fTextViewer = textViewer;
+ setEnabled(true);
+
+ boolean prefSetting = DsfUIPlugin.getDefault().getPreferenceStore().getBoolean(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP);
+ fTextViewer.getTextWidget().setWordWrap(prefSetting);
+ setChecked(prefSetting);
+
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ @Override
+ public void run() {
+ fTextViewer.getTextWidget().setWordWrap(isChecked());
+ DsfUIPlugin.getDefault().getPreferenceStore().setValue(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP,isChecked());
+ DsfUIPlugin.getDefault().savePluginPreferences();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/MessagesForDetailPane.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/MessagesForDetailPane.java
new file mode 100644
index 00000000000..a5a76e64684
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/MessagesForDetailPane.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForDetailPane extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.messages"; //$NON-NLS-1$
+
+ public static String NumberFormatDetailPane_Name;
+ public static String NumberFormatDetailPane_Description;
+
+ public static String DetailPane_Copy;
+ public static String DetailPane_LabelPattern;
+ public static String DetailPane_Select_All;
+ public static String PaneWordWrapAction_WrapText;
+ public static String PaneMaxLengthAction_MaxLength;
+ public static String PaneMaxLengthDialog_ConfigureDetails;
+ public static String PaneMaxLengthDialog_MaxCharactersToDisplay;
+ public static String PaneMaxLengthDialog_IntegerCannotBeNegative;
+ public static String PaneMaxLengthDialog_EnterAnInteger;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForDetailPane.class);
+ }
+
+ private MessagesForDetailPane() {}
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/TextViewerAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/TextViewerAction.java
new file mode 100644
index 00000000000..77d74a60db1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/TextViewerAction.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.ui.texteditor.IUpdate;
+
+/**
+ * Common function for actions that operate on a text viewer.
+ * <p>
+ * Clients may subclass this class.
+ * </p>
+ * @since 3.0
+ */
+public class TextViewerAction extends Action implements IUpdate {
+
+ private int fOperationCode= -1;
+ private ITextOperationTarget fOperationTarget;
+
+ /**
+ * Constructs a new action in the given text viewer with
+ * the specified operation code.
+ *
+ * @param viewer
+ * @param operationCode
+ */
+ public TextViewerAction(ITextViewer viewer, int operationCode) {
+ fOperationCode= operationCode;
+ fOperationTarget= viewer.getTextOperationTarget();
+ update();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IUpdate#update()
+ *
+ * Updates the enabled state of the action.
+ * Fires a property change if the enabled state changes.
+ *
+ * @see org.eclipse.jface.action.Action#firePropertyChange(String, Object, Object)
+ */
+ public void update() {
+
+ boolean wasEnabled= isEnabled();
+ boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
+ setEnabled(isEnabled);
+
+ if (wasEnabled != isEnabled) {
+ firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.action.IAction#run()
+ */
+ @Override
+ public void run() {
+ if (fOperationCode != -1 && fOperationTarget != null) {
+ fOperationTarget.doOperation(fOperationCode);
+ }
+ }
+
+ /**
+ * Configures this action with a label, tool tip, and description.
+ *
+ * @param text action label
+ * @param toolTipText action tool tip
+ * @param description action description
+ */
+ public void configureAction(String text, String toolTipText, String description) {
+ setText(text);
+ setToolTipText(toolTipText);
+ setDescription(description);
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/messages.properties
new file mode 100644
index 00000000000..1995fe0865d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/detailsupport/messages.properties
@@ -0,0 +1,25 @@
+###############################################################################
+# Copyright (c) 2006, 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
+# Wind River Systems Inc - copied for non-restricted version for DSDP/DD/DSF
+###############################################################################
+
+NumberFormatDetailPane_Name=Number Formats Viewer
+NumberFormatDetailPane_Description=Detail viewer showing selected variable in all available formats.
+
+DetailPane_LabelPattern={0} : {1}
+DetailPane_Select_All=Select &All
+DetailPane_Copy=&Copy
+
+PaneWordWrapAction_WrapText=&Wrap Text
+PaneMaxLengthAction_MaxLength=&Max Length...
+PaneMaxLengthDialog_ConfigureDetails=Configure Details Pane
+PaneMaxLengthDialog_MaxCharactersToDisplay=&Maximum characters to display in details pane (0 = unlimited):
+PaneMaxLengthDialog_IntegerCannotBeNegative=Integer must be non-negative
+PaneMaxLengthDialog_EnterAnInteger=Enter an integer
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java
new file mode 100644
index 00000000000..8c355996444
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPane.java
@@ -0,0 +1,1218 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.numberformat.detail;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.DetailPaneMaxLengthAction;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.DetailPaneWordWrapAction;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.MessagesForDetailPane;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.TextViewerAction;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
+import org.eclipse.core.commands.operations.IUndoContext;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.model.IDebugModelProvider;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.debug.ui.IDetailPane;
+import org.eclipse.debug.ui.IValueDetailListener;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.jface.text.IFindReplaceTarget;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.IUndoManager;
+import org.eclipse.jface.text.IUndoManagerExtension;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.text.source.SourceViewerConfiguration;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.operations.OperationHistoryActionHandler;
+import org.eclipse.ui.operations.RedoActionHandler;
+import org.eclipse.ui.operations.UndoActionHandler;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds;
+import org.eclipse.ui.texteditor.ITextEditorActionConstants;
+import org.eclipse.ui.texteditor.IUpdate;
+import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
+import org.eclipse.ui.texteditor.StatusLineContributionItem;
+
+@SuppressWarnings("restriction")
+public class NumberFormatDetailPane implements IDetailPane, IAdaptable, IPropertyChangeListener {
+
+ /**
+ * The <code>IWorkbenchPartSite</code> that the details area (and the
+ * variables view) belongs to.
+ */
+ private IWorkbenchPartSite fWorkbenchPartSite;
+
+ /**
+ * Map of actions. Keys are strings, values
+ * are <code>IAction</code>.
+ */
+ private Map<String, IAction> fActionMap = new HashMap<String, IAction>();
+
+ /**
+ * Collection to track actions that should be updated when selection occurs.
+ */
+ private List<String> fSelectionActions = new ArrayList<String>();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#init(org.eclipse.ui.IWorkbenchPartSite)
+ */
+ public void init(IWorkbenchPartSite workbench) {
+ fWorkbenchPartSite = workbench;
+
+ }
+
+ /**
+ * Adds an action to the Map storing actions. Removes it if action is null.
+ *
+ * @param actionID The ID of the action, used as the key in the Map
+ * @param action The action associated with the ID
+ */
+ protected void setAction(String actionID, IAction action) {
+ if (action == null) {
+ fActionMap.remove(actionID);
+ } else {
+ fActionMap.put(actionID, action);
+ }
+ }
+
+ /**
+ * Adds the given action to the global action handler for the ViewSite.
+ * A call to <code>updateActionBars()</code> must be called after changes
+ * to propagate changes through the workbench.
+ *
+ * @param actionID The ID of the action
+ * @param action The action to be set globally
+ */
+ protected void setGlobalAction(String actionID, IAction action){
+ getViewSite().getActionBars().setGlobalActionHandler(actionID, action);
+ }
+
+ /**
+ * Adds the given action to the list of actions that will be updated when
+ * <code>updateSelectionDependentActions()</code> is called. If the string
+ * is null it will not be added to the list.
+ *
+ * @param actionID The ID of the action which should be updated
+ */
+ protected void setSelectionDependantAction(String actionID){
+ if (actionID != null) fSelectionActions.add(actionID);
+ }
+
+ /**
+ * Gets the action out of the map, casts it to an <code>IAction</code>
+ *
+ * @param actionID The ID of the action to find
+ * @return The action associated with the ID or null if none is found.
+ */
+ protected IAction getAction(String actionID) {
+ return fActionMap.get(actionID);
+ }
+
+ /**
+ * Calls the update method of the action with the given action ID.
+ * The action must exist in the action map and must be an instance of
+ * </code>IUpdate</code>
+ *
+ * @param actionId The ID of the action to update
+ */
+ protected void updateAction(String actionId) {
+ IAction action= getAction(actionId);
+ if (action instanceof IUpdate) {
+ ((IUpdate) action).update();
+ }
+ }
+
+ /**
+ * Iterates through the list of selection dependent actions and
+ * updates them. Use <code>setSelectionDependentAction(String actionID)</code>
+ * to add an action to the list. The action must have been added to the known
+ * actions map by calling <code>setAction(String actionID, IAction action)</code>
+ * before it can be updated by this method.
+ */
+ protected void updateSelectionDependentActions() {
+ Iterator<String> iterator= fSelectionActions.iterator();
+ while (iterator.hasNext()) {
+ updateAction(iterator.next());
+ }
+ }
+
+ /**
+ * Gets the view site for this view. May be null if this detail pane
+ * is not part of a view.
+ *
+ * @return The site for this view or <code>null</code>
+ */
+ protected IViewSite getViewSite(){
+ if (fWorkbenchPartSite == null){
+ return null;
+ } else {
+ return (IViewSite) fWorkbenchPartSite.getPart().getSite();
+ }
+ }
+
+ /**
+ * Gets the workbench part site for this view. May be null if this detail pane
+ * is not part of a view.
+ *
+ * @return The workbench part site or <code>null</code>
+ */
+ protected IWorkbenchPartSite getWorkbenchPartSite() {
+ return fWorkbenchPartSite;
+ }
+
+ /**
+ * Returns whether this detail pane is being displayed in a view with a workbench part site.
+ *
+ * @return whether this detail pane is being displayed in a view with a workbench part site.
+ */
+ protected boolean isInView(){
+ return fWorkbenchPartSite != null;
+ }
+
+ /**
+ * These are the IDs for the actions in the context menu
+ */
+ protected static final String DETAIL_COPY_ACTION = ActionFactory.COPY.getId() + ".SourceDetailPane"; //$NON-NLS-1$
+ protected static final String DETAIL_SELECT_ALL_ACTION = IDebugView.SELECT_ALL_ACTION + ".SourceDetailPane"; //$NON-NLS-1$
+ protected static final String DETAIL_WORD_WRAP_ACTION = DsfUIPlugin.PLUGIN_ID + ".detail_pane_word_wrap"; //$NON-NLS-1$
+ protected static final String DETAIL_MAX_LENGTH_ACTION = "MaxLength"; //$NON-NLS-1$
+
+ /**
+ * The ID, name and description of this pane are stored in constants so that the class
+ * does not have to be instantiated to access them.
+ */
+ public static final String ID = "NumberFormatPane"; //$NON-NLS-1$
+
+ /**
+ * Data structure for the position label value.
+ */
+ private static class PositionLabelValue {
+
+ public int fValue;
+
+ @Override
+ public String toString() {
+ return String.valueOf(fValue);
+ }
+ }
+
+ /**
+ * Internal interface for a cursor listener. I.e. aggregation
+ * of mouse and key listener.
+ * @since 3.0
+ */
+ interface ICursorListener extends MouseListener, KeyListener {
+ }
+
+ /**
+ * Job to compute the details for a selection
+ */
+ class DetailJob extends Job implements IValueDetailListener {
+ private IPresentationContext fPresentationContext;
+ private Object fViewerInput;
+ private ITreeSelection fElements;
+ private boolean fFirst = true;
+ private IProgressMonitor fMonitor;
+ private boolean fComputed = false;
+
+ public DetailJob(IPresentationContext context, Object viewerInput, ITreeSelection elements,
+ IDebugModelPresentation model)
+ {
+ super("compute variable details"); //$NON-NLS-1$
+ setSystem(true);
+ fPresentationContext = context;
+ fViewerInput = viewerInput;
+ fElements = elements;
+ }
+
+ /*
+ * This is the routine which will actually process the various format requests
+ * for a given element. It is expected and required that this routine will be
+ * called from within a DSF executor.
+ */
+ private void putInformationIntoDetailPane( final AbstractCachingVMProvider provider,
+ final IVMNode node,
+ final TreePath path,
+ final IFormattedDataDMContext finalDmc ,
+ final IFormattedValues service,
+ final IProgressMonitor monitor,
+ final String name ) {
+
+ /*
+ * Now that we can process this one. Find out how many formats we can
+ * show this in. We will choose to show all of the supported formats.
+ * Since we are doing this in the background and the debug engines do
+ * typically cache the results so producing multiple formats will not
+ * typically be a burden. We should probably consider perhaps doing a
+ * preference where they can select what formats they want to show.
+ */
+
+ final DataRequestMonitor<String[]> getAvailableFormatsDone =
+ new DataRequestMonitor<String[]>(service.getExecutor(), null) {
+ @Override
+ protected void handleSuccess() {
+ if (monitor.isCanceled()) {
+ notifyAll();
+ return;
+ }
+
+ /*
+ * Now we have a set of formats for each one fire up an independent
+ * asynchronous request to get the data in that format. We do not
+ * go through the cache manager here because when the values are
+ * edited and written the cache is bypassed.
+ */
+ String[] formats = getData();
+
+ final List<String> completedFormatStrings = new ArrayList<String>();
+
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(service.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+
+ if (monitor.isCanceled()) {
+ notifyAll();
+ return;
+ }
+
+ /*
+ * We sort the array to make the strings appear always in the same order.
+ */
+
+ java.util.Collections.sort( completedFormatStrings );
+
+ int len = completedFormatStrings.size() ;
+
+ if ( len == 0 ) {
+ detailComputed(null,""); //$NON-NLS-1$
+ }
+ else {
+ /*
+ * Add the HEADER which identifies what is being represented. When there
+ * are multiple selections in the view the detail pane contains multiple
+ * entries. They would be all compressed together and even though the
+ * order of the entries is the order of the selections in the view and
+ * it is very hard to know what goes with what. This makes it easy.
+ */
+ String finalResult = "Name : " + name + "\n"; //$NON-NLS-1$ //$NON-NLS-2$
+ int cnt = 0 ;
+
+ for (String str : completedFormatStrings) {
+
+ finalResult += " " + str ; //$NON-NLS-1$
+
+ if ( ( ++ cnt ) < len ) {
+ finalResult += "\n" ; //$NON-NLS-1$
+ }
+ }
+
+ detailComputed(null,finalResult);
+ }
+ }
+ };
+
+ countingRm.setDoneCount(formats.length);
+
+ for ( final String str : formats ) {
+ /*
+ * Format has been validated. Get the formatted value.
+ */
+ final FormattedValueDMContext valueDmc = service.getFormattedValueContext(finalDmc, str);
+
+ provider.getModelData(
+ node,
+ new IViewerUpdate() {
+ public void cancel() {}
+ public void done() {}
+ public Object getViewerInput() { return fViewerInput; }
+ public TreePath getElementPath() { return path; }
+ public Object getElement() { return path.getLastSegment(); }
+ public IPresentationContext getPresentationContext() { return fPresentationContext; }
+ public boolean isCanceled() { return monitor.isCanceled(); }
+ public void setStatus(IStatus status) {}
+ public IStatus getStatus() { return null; }
+ },
+ service, valueDmc,
+ new DataRequestMonitor<FormattedValueDMData>(service.getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (getStatus().isOK()) {
+ /*
+ * Show the information indicating the format.
+ */
+ if ( str == IFormattedValues.HEX_FORMAT) {
+ completedFormatStrings.add("Hex.... : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else if ( str == IFormattedValues.OCTAL_FORMAT) {
+ completedFormatStrings.add("Octal.. : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else if ( str == IFormattedValues.NATURAL_FORMAT) {
+ completedFormatStrings.add("Natural : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else if ( str == IFormattedValues.BINARY_FORMAT) {
+ completedFormatStrings.add("Binary. : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else if ( str == IFormattedValues.DECIMAL_FORMAT) {
+ completedFormatStrings.add("Decimal : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else if ( str == IFormattedValues.STRING_FORMAT) {
+ completedFormatStrings.add("String : " + getData().getFormattedValue()); //$NON-NLS-1$
+ }
+ else {
+ completedFormatStrings.add("Other.. : (" + str + ") " + getData().getFormattedValue()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+ countingRm.done();
+ }
+ },
+ provider.getExecutor());
+ }
+ }
+ };
+
+ /*
+ * Get the supported formats.
+ */
+ service.getAvailableFormats(finalDmc, getAvailableFormatsDone);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+
+ String message = null;
+ if ( fMonitor != null && ! fMonitor.isCanceled() ) {
+ fMonitor.setCanceled(true);
+ }
+ fMonitor = monitor;
+ TreePath[] paths = fElements.getPaths();
+ for (int i = 0; i < paths.length; i++) {
+ if (monitor.isCanceled()) {
+ break;
+ }
+ final TreePath path = paths[i];
+ Object element = paths[i].getLastSegment();
+
+ /*
+ * Make sure this is an element we want to deal with.
+ */
+ if ( element instanceof IDMVMContext) {
+ IDMVMContext vmc = (IDMVMContext)element;
+ /*
+ * We are specifically looking to support the following Data Model Contexts
+ *
+ * IRegisterDMContext
+ * IBitFieldDMContext
+ * IExpressionDMContext
+ *
+ * At first you might think that we should just use the service which is
+ * associated with the dmc. But there are implementations where the data
+ * model contexts are extended but the services do not extend each other
+ * ( this is the case with the WindRiver OCD extensions for example ).
+ *
+ * So here we specifically look for the service which knows how to deal
+ * with the formatted data.
+ *
+ * Please note that the order or searching for the ancestor is important.
+ * A BitField Data Model Context will have a Register Data Model Context
+ * as its parent so if we search for a Register DMC first when we actually
+ * have a BitField DMC we will get the register and show the value of the
+ * register not the bit field.
+ */
+
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), vmc.getDMContext().getSessionId());
+
+ final AbstractCachingVMProvider provider = (AbstractCachingVMProvider)vmc.getAdapter(AbstractCachingVMProvider.class);
+ final IVMNode node = (IVMNode)vmc.getAdapter(IVMNode.class);
+
+ final IBitFieldDMContext bitfieldDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IBitFieldDMContext.class);
+ if ( bitfieldDmc != null ) {
+ /*
+ * Get the name so we can construct the header which identifies the detail
+ * set of values.
+ */
+ final IRegisters regService = tracker.getService(IRegisters.class);
+
+ regService.getExecutor().submit(
+ new Runnable() {
+ public void run() {
+ regService.getBitFieldData(
+ bitfieldDmc,
+ new DataRequestMonitor<IBitFieldDMData>(regService.getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (getStatus().isOK()) {
+ putInformationIntoDetailPane(provider, node, path, bitfieldDmc , regService, monitor, getData().getName());
+ }
+ }
+ }
+ );
+ }
+ }
+ );
+ }
+ else {
+ final IRegisterDMContext regDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IRegisterDMContext.class);
+
+ if ( regDmc != null ) {
+ /*
+ * Get the name so we can construct the header which identifies the detail
+ * set of values.
+ */
+ final IRegisters regService = tracker.getService(IRegisters.class);
+
+ regService.getExecutor().submit(
+ new Runnable() {
+ public void run() {
+ regService.getRegisterData(
+ regDmc,
+ new DataRequestMonitor<IRegisterDMData>(regService.getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (getStatus().isOK()) {
+ putInformationIntoDetailPane(provider, node, path, regDmc , regService, monitor, getData().getName());
+ }
+ }
+ }
+ );
+ }
+ }
+ );
+ }
+ else {
+ final IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(((IDMVMContext) element).getDMContext(), IExpressionDMContext.class);
+
+ if ( exprDmc != null ) {
+ final IExpressions exprService = tracker.getService(IExpressions.class);;
+
+ exprService.getExecutor().submit(
+ new Runnable() {
+ public void run() {
+ putInformationIntoDetailPane(provider, node, path, exprDmc , exprService, monitor, exprDmc.getExpression());
+ }
+ }
+ );
+ }
+ else {
+ /*
+ * For whatever reason we are seeing some form of context we do not handle. So we
+ * will skip this one and try and process any remaining ones. At least this way
+ * we can fill the detail pane with those we do understand.
+ */
+ continue;
+ }
+ }
+ }
+ tracker.dispose();
+
+ /*
+ * We need to wait until all the values are in. This causes the work
+ * to in effect be synchronous, but if we do not wait then when we
+ * are stepping fast if we exit before the job is finished then we
+ * will enter and start to update the pane before the previous work
+ * is actually done. This causes the data to be screwed up in an
+ * overlapped way. It should be the case that most of the jobs that
+ * occur in the middle will be cancelled, so there is not a lot of
+ * waste actually going on.
+ */
+
+ synchronized (this) {
+ try {
+ // wait for a max of 30 seconds for result, then cancel
+ wait(30000);
+ if (!fComputed) {
+ fMonitor.setCanceled(true);
+ }
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ else {
+// IValue val = null;
+// if (element instanceof IVariable) {
+// try {
+// val = ((IVariable)element).getValue();
+// } catch (DebugException e) {
+// detailComputed(null, e.getStatus().getMessage());
+// }
+// } else if (element instanceof IExpression) {
+// val = ((IExpression)element).getValue();
+// }
+ if (element instanceof String) {
+ message = (String) element;
+ }
+ else {
+ message = element.toString();
+ }
+ fComputed = true;
+ }
+ // If no details were computed for the selected variable, clear the pane
+ // or use the message, if the variable was a java.lang.String
+ if (!fComputed){
+ if (message == null) {
+ detailComputed(null,""); //$NON-NLS-1$
+ } else {
+ detailComputed(null, message);
+ }
+ }
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#canceling()
+ */
+ @Override
+ protected void canceling() {
+ super.canceling();
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IValueDetailListener#detailComputed(org.eclipse.debug.core.model.IValue, java.lang.String)
+ */
+ public void detailComputed(IValue value, final String result) {
+ synchronized (this) {
+ fComputed = true;
+ }
+ if (!fMonitor.isCanceled()) {
+ WorkbenchJob append = new WorkbenchJob("append details") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (!fMonitor.isCanceled()) {
+ String insert = result;
+ int length = 0;
+ if (!fFirst) {
+ length = getDetailDocument().getLength();
+ }
+ if (length > 0) {
+ insert = "\n" + result; //$NON-NLS-1$
+ }
+ try {
+ int max = DsfUIPlugin.getDefault().getPreferenceStore().getInt(IDebugUIConstants.PREF_MAX_DETAIL_LENGTH);
+ if (max > 0 && insert.length() > max) {
+ insert = insert.substring(0, max) + "..."; //$NON-NLS-1$
+ }
+ if (fFirst) {
+ getDetailDocument().set(insert);
+ fFirst = false;
+ } else {
+ getDetailDocument().replace(length, 0,insert);
+ }
+ } catch (BadLocationException e) {
+ DsfUIPlugin.log(e);
+ }
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ append.setSystem(true);
+ append.schedule();
+ }
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ }
+
+ /**
+ * The model presentation used to produce the string details for a
+ * selected variable.
+ */
+ private String fDebugModelIdentifier;
+
+ /**
+ * Controls the status line while the details area has focus.
+ * Displays the current cursor position in the text (line:character).
+ */
+ private StatusLineContributionItem fStatusLineItem;
+
+ /**
+ * The source viewer in which the computed string detail
+ * of selected variables will be displayed.
+ */
+ private SourceViewer fSourceViewer;
+
+ /**
+ * The last selection displayed in the source viewer.
+ */
+ private IStructuredSelection fLastDisplayed = null;
+
+ /**
+ * Variables used to create the detailed information for a selection
+ */
+ private IDocument fDetailDocument;
+ private DetailJob fDetailJob = null;
+ private final String fPositionLabelPattern = MessagesForDetailPane.DetailPane_LabelPattern;
+ private final PositionLabelValue fLineLabel = new PositionLabelValue();
+ private final PositionLabelValue fColumnLabel = new PositionLabelValue();
+ private final Object[] fPositionLabelPatternArguments = new Object[] {fLineLabel, fColumnLabel };
+ private ICursorListener fCursorListener;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public Control createControl(Composite parent) {
+
+ createSourceViewer(parent);
+
+ if (isInView()){
+ createViewSpecificComponents();
+ createActions();
+ DsfUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
+ JFaceResources.getFontRegistry().addListener(this);
+ }
+
+ return fSourceViewer.getControl();
+ }
+
+ /**
+ * Creates the source viewer in the given parent composite
+ *
+ * @param parent Parent composite to create the source viewer in
+ */
+ private void createSourceViewer(Composite parent) {
+
+ // Create & configure a SourceViewer
+ fSourceViewer = new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL);
+ fSourceViewer.setDocument(getDetailDocument());
+ fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IDsfDebugUIConstants.DETAIL_PANE_FONT));
+ fSourceViewer.getTextWidget().setWordWrap(DsfUIPlugin.getDefault().getPreferenceStore().getBoolean(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
+ fSourceViewer.setEditable(false);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(fSourceViewer.getTextWidget(), IDsfDebugUIConstants.DETAIL_PANE);
+ Control control = fSourceViewer.getControl();
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ control.setLayoutData(gd);
+ }
+
+ /**
+ * Creates listeners and other components that should only be added to the
+ * source viewer when this detail pane is inside a view.
+ */
+ private void createViewSpecificComponents(){
+
+ // Add a document listener so actions get updated when the document changes
+ getDetailDocument().addDocumentListener(new IDocumentListener() {
+ public void documentAboutToBeChanged(DocumentEvent event) {}
+ public void documentChanged(DocumentEvent event) {
+ updateSelectionDependentActions();
+ }
+ });
+
+ // Add the selection listener so selection dependent actions get updated.
+ fSourceViewer.getSelectionProvider().addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateSelectionDependentActions();
+ }
+ });
+
+ // Add a focus listener to update actions when details area gains focus
+ fSourceViewer.getControl().addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ getViewSite().setSelectionProvider(fSourceViewer.getSelectionProvider());
+
+ setGlobalAction(IDebugView.SELECT_ALL_ACTION, getAction(DETAIL_SELECT_ALL_ACTION));
+ setGlobalAction(IDebugView.COPY_ACTION, getAction(DETAIL_COPY_ACTION));
+
+ getViewSite().getActionBars().updateActionBars();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ getViewSite().setSelectionProvider(null);
+
+ setGlobalAction(IDebugView.SELECT_ALL_ACTION, null);
+ setGlobalAction(IDebugView.COPY_ACTION, null);
+
+ getViewSite().getActionBars().updateActionBars();
+ }
+ });
+
+ // Create a status line item displaying the current cursor location
+ fStatusLineItem = new StatusLineContributionItem("ModeContributionItem"); //$NON-NLS-1$
+ IStatusLineManager manager= getViewSite().getActionBars().getStatusLineManager();
+ manager.add(fStatusLineItem);
+ fSourceViewer.getTextWidget().addMouseListener(getCursorListener());
+ fSourceViewer.getTextWidget().addKeyListener(getCursorListener());
+
+ // Add a context menu to the detail area
+ createDetailContextMenu(fSourceViewer.getTextWidget());
+ }
+
+ /**
+ * Creates the actions to add to the context menu
+ */
+ private void createActions() {
+
+ TextViewerAction textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.SELECT_ALL);
+ textAction.configureAction(MessagesForDetailPane.DetailPane_Select_All, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDsfDebugUIConstants.DETAIL_PANE_SELECT_ALL_ACTION);
+ setAction(DETAIL_SELECT_ALL_ACTION, textAction);
+
+ textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.COPY);
+ textAction.configureAction(MessagesForDetailPane.DetailPane_Copy, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDsfDebugUIConstants.DETAIL_PANE_COPY_ACTION);
+ setAction(DETAIL_COPY_ACTION, textAction);
+
+ setSelectionDependantAction(DETAIL_COPY_ACTION);
+
+ updateSelectionDependentActions();
+
+ IAction action = new DetailPaneWordWrapAction(fSourceViewer);
+ setAction(DETAIL_WORD_WRAP_ACTION, action);
+
+ action = new DetailPaneMaxLengthAction(fSourceViewer.getControl().getShell());
+ setAction(DETAIL_MAX_LENGTH_ACTION,action);
+ }
+
+ /**
+ * Create the context menu particular to the detail pane. Note that anyone
+ * wishing to contribute an action to this menu must use
+ * <code>IDebugUIConstants.VARIABLE_VIEW_DETAIL_ID</code> as the
+ * <code>targetID</code> in the extension XML.
+ */
+ protected void createDetailContextMenu(Control menuControl) {
+ MenuManager menuMgr= new MenuManager();
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager mgr) {
+ fillDetailContextMenu(mgr);
+ }
+ });
+ Menu menu= menuMgr.createContextMenu(menuControl);
+ menuControl.setMenu(menu);
+
+ getViewSite().registerContextMenu(IDebugUIConstants.VARIABLE_VIEW_DETAIL_ID, menuMgr, fSourceViewer.getSelectionProvider());
+ }
+
+ /**
+ * Adds items to the detail pane's context menu including any extension defined
+ * actions.
+ *
+ * @param menu The menu to add the item to.
+ */
+ protected void fillDetailContextMenu(IMenuManager menu) {
+
+ menu.add(new Separator(IDebugUIConstants.VARIABLE_GROUP));
+ menu.add(new Separator());
+ menu.add(getAction(DETAIL_COPY_ACTION));
+ menu.add(getAction(DETAIL_SELECT_ALL_ACTION));
+ menu.add(new Separator());
+ menu.add(getAction(DETAIL_WORD_WRAP_ACTION));
+ menu.add(getAction(DETAIL_MAX_LENGTH_ACTION));
+ menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#display(org.eclipse.jface.viewers.IStructuredSelection)
+ */
+ public void display(IStructuredSelection selection) {
+
+ if (selection == null){
+ clearSourceViewer();
+ return;
+ }
+
+ fLastDisplayed = selection;
+
+ if ( selection.isEmpty() || !(selection instanceof ITreeSelection) ) {
+ clearSourceViewer();
+ return;
+ }
+
+ Object firstElement = selection.getFirstElement();
+ if (firstElement instanceof IAdaptable) {
+ IDebugModelProvider debugModelProvider =
+ (IDebugModelProvider)((IAdaptable)firstElement).getAdapter(IDebugModelProvider.class);
+ if (debugModelProvider != null) {
+ String[] ids = debugModelProvider.getModelIdentifiers();
+ if (ids != null && ids.length > 0) {
+ setDebugModel(ids[0]);
+ }
+ }
+ }
+
+ synchronized (this) {
+ if (fDetailJob != null) {
+ fDetailJob.cancel();
+ }
+ IWorkbenchPart part = fWorkbenchPartSite.getPart();
+ if (part instanceof IDebugView) {
+ Viewer viewer = ((IDebugView)part).getViewer();
+ Object input = viewer.getInput();
+ if (input != null && viewer instanceof TreeModelViewer) {
+ TreeModelViewer treeModelViewer = (TreeModelViewer)viewer;
+ fDetailJob = new DetailJob(treeModelViewer.getPresentationContext(), input,
+ (ITreeSelection)selection, null);
+ fDetailJob.schedule();
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#setFocus()
+ */
+ public boolean setFocus(){
+ if (fSourceViewer != null){
+ fSourceViewer.getTextWidget().setFocus();
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ *
+ */
+ public void dispose(){
+ fActionMap.clear();
+ fSelectionActions.clear();
+
+ if (fDetailJob != null) fDetailJob.cancel();
+ fDebugModelIdentifier = null; // Setting this to null makes sure the source viewer is reconfigured with the model presentation after disposal
+ if (fSourceViewer != null && fSourceViewer.getControl() != null) fSourceViewer.getControl().dispose();
+
+ if (isInView()){
+ disposeUndoRedoAction(ITextEditorActionConstants.UNDO);
+ disposeUndoRedoAction(ITextEditorActionConstants.REDO);
+
+ getViewSite().getActionBars().getStatusLineManager().remove(fStatusLineItem);
+
+ DsfUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
+ JFaceResources.getFontRegistry().removeListener(this);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#getDescription()
+ */
+ public String getDescription() {
+ return MessagesForDetailPane.NumberFormatDetailPane_Description;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#getID()
+ */
+ public String getID() {
+ return ID;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#getName()
+ */
+ public String getName() {
+ return MessagesForDetailPane.NumberFormatDetailPane_Name;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class required) {
+ if (IFindReplaceTarget.class.equals(required)) {
+ return fSourceViewer.getFindReplaceTarget();
+ }
+ if (ITextViewer.class.equals(required)) {
+ return fSourceViewer;
+ }
+ return null;
+ }
+
+ /**
+ * Lazily instantiate and return a Document for the detail pane text viewer.
+ */
+ protected IDocument getDetailDocument() {
+ if (fDetailDocument == null) {
+ fDetailDocument = new Document();
+ }
+ return fDetailDocument;
+ }
+
+ /**
+ * Clears the source viewer, removes all text.
+ */
+ protected void clearSourceViewer(){
+ if (fDetailJob != null) {
+ fDetailJob.cancel();
+ }
+ fLastDisplayed = null;
+ fDetailDocument.set(""); //$NON-NLS-1$
+ fSourceViewer.setEditable(false);
+ }
+
+ /**
+ * Configures the details viewer for the debug model
+ * currently being displayed
+ */
+ protected void configureDetailsViewer() {
+ SourceViewerConfiguration svc = new SourceViewerConfiguration();
+
+ fSourceViewer.setEditable(false);
+ fSourceViewer.unconfigure();
+ fSourceViewer.configure(svc);
+
+ if (isInView()){
+ createUndoRedoActions();
+ }
+ }
+
+ /**
+ * @return The formatted string describing cursor position
+ */
+ protected String getCursorPosition() {
+
+ if (fSourceViewer == null) {
+ return ""; //$NON-NLS-1$
+ }
+
+ StyledText styledText= fSourceViewer.getTextWidget();
+ int caret= styledText.getCaretOffset();
+ IDocument document= fSourceViewer.getDocument();
+
+ if (document == null) {
+ return ""; //$NON-NLS-1$
+ }
+
+ try {
+
+ int line= document.getLineOfOffset(caret);
+
+ int lineOffset= document.getLineOffset(line);
+ int tabWidth= styledText.getTabs();
+ int column= 0;
+ for (int i= lineOffset; i < caret; i++)
+ if ('\t' == document.getChar(i)) {
+ column += tabWidth - (tabWidth == 0 ? 0 : column % tabWidth);
+ } else {
+ column++;
+ }
+
+ fLineLabel.fValue= line + 1;
+ fColumnLabel.fValue= column + 1;
+ return MessageFormat.format(fPositionLabelPattern, fPositionLabelPatternArguments);
+
+ } catch (BadLocationException x) {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Returns this view's "cursor" listener to be installed on the view's
+ * associated details viewer. This listener is listening to key and mouse button events.
+ * It triggers the updating of the status line.
+ *
+ * @return the listener
+ */
+ private ICursorListener getCursorListener() {
+ if (fCursorListener == null) {
+ fCursorListener= new ICursorListener() {
+
+ public void keyPressed(KeyEvent e) {
+ fStatusLineItem.setText(getCursorPosition());
+ }
+
+ public void keyReleased(KeyEvent e) {
+ }
+
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ public void mouseDown(MouseEvent e) {
+ }
+
+ public void mouseUp(MouseEvent e) {
+ fStatusLineItem.setText(getCursorPosition());
+ }
+ };
+ }
+ return fCursorListener;
+ }
+
+ /**
+ * Returns the identifier of the debug model being displayed
+ * in this view, or <code>null</code> if none.
+ *
+ * @return debug model identifier
+ */
+ protected String getDebugModel() {
+ return fDebugModelIdentifier;
+ }
+
+ /**
+ * Sets the identifier of the debug model being displayed
+ * in this view, or <code>null</code> if none.
+ *
+ * @param id debug model identifier of the type of debug
+ * elements being displayed in this view
+ */
+ protected void setDebugModel(String id) {
+ if (id != fDebugModelIdentifier) {
+ fDebugModelIdentifier = id;
+ configureDetailsViewer();
+ }
+ }
+
+ /**
+ * Creates this editor's undo/re-do actions.
+ * <p>
+ * Subclasses may override or extend.</p>
+ *
+ * @since 3.2
+ */
+ protected void createUndoRedoActions() {
+ disposeUndoRedoAction(ITextEditorActionConstants.UNDO);
+ disposeUndoRedoAction(ITextEditorActionConstants.REDO);
+ IUndoContext undoContext= getUndoContext();
+ if (undoContext != null) {
+ // Use actions provided by global undo/re-do
+
+ // Create the undo action
+ OperationHistoryActionHandler undoAction= new UndoActionHandler(getViewSite(), undoContext);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(undoAction, IAbstractTextEditorHelpContextIds.UNDO_ACTION);
+ undoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.UNDO);
+ setAction(ITextEditorActionConstants.UNDO, undoAction);
+ setGlobalAction(ITextEditorActionConstants.UNDO, undoAction);
+
+ // Create the re-do action.
+ OperationHistoryActionHandler redoAction= new RedoActionHandler(getViewSite(), undoContext);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(redoAction, IAbstractTextEditorHelpContextIds.REDO_ACTION);
+ redoAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.REDO);
+ setAction(ITextEditorActionConstants.REDO, redoAction);
+ setGlobalAction(ITextEditorActionConstants.REDO, redoAction);
+
+ getViewSite().getActionBars().updateActionBars();
+ }
+ }
+
+ /**
+ * Disposes of the action with the specified ID
+ *
+ * @param actionId the ID of the action to disposed
+ */
+ protected void disposeUndoRedoAction(String actionId) {
+ OperationHistoryActionHandler action = (OperationHistoryActionHandler) getAction(actionId);
+ if (action != null) {
+ action.dispose();
+ setAction(actionId, null);
+ }
+ }
+
+ /**
+ * Returns this editor's viewer's undo manager undo context.
+ *
+ * @return the undo context or <code>null</code> if not available
+ * @since 3.2
+ */
+ private IUndoContext getUndoContext() {
+ IUndoManager undoManager= fSourceViewer.getUndoManager();
+ if (undoManager instanceof IUndoManagerExtension)
+ return ((IUndoManagerExtension)undoManager).getUndoContext();
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ public void propertyChange(PropertyChangeEvent event) {
+ String propertyName= event.getProperty();
+ if (propertyName.equals(IDsfDebugUIConstants.DETAIL_PANE_FONT)) {
+ fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IDsfDebugUIConstants.DETAIL_PANE_FONT));
+ } else if (propertyName.equals(IDsfDebugUIConstants.PREF_MAX_DETAIL_LENGTH)) {
+ display(fLastDisplayed);
+ } else if (propertyName.equals(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP)) {
+ fSourceViewer.getTextWidget().setWordWrap(DsfUIPlugin.getDefault().getPreferenceStore().getBoolean(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
+ getAction(DETAIL_WORD_WRAP_ACTION).setChecked(DsfUIPlugin.getDefault().getPreferenceStore().getBoolean(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPaneFactory.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPaneFactory.java
new file mode 100644
index 00000000000..fc62cdc6ebe
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/numberformat/detail/NumberFormatDetailPaneFactory.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems, Inc. - initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.numberformat.detail;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.MessagesForDetailPane;
+import org.eclipse.debug.ui.IDetailPane;
+import org.eclipse.debug.ui.IDetailPaneFactory;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+/**
+ * This provides a simple Detail Pane Factory for the core debug views for DSF.
+ */
+
+public class NumberFormatDetailPaneFactory implements IDetailPaneFactory {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.views.variables.IDetailsFactory#createDetailsArea(java.lang.String)
+ */
+ public IDetailPane createDetailPane(String id) {
+ return new NumberFormatDetailPane();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.views.variables.IDetailsFactory#getDetailsTypes(org.eclipse.jface.viewers.IStructuredSelection)
+ */
+ @SuppressWarnings("unchecked")
+ public Set getDetailPaneTypes(IStructuredSelection selection) {
+ Set<String> possibleIDs = new HashSet<String>(1);
+ possibleIDs.add(NumberFormatDetailPane.ID);
+ return possibleIDs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPaneFactory#getDefaultDetailPane(java.util.Set, org.eclipse.jface.viewers.IStructuredSelection)
+ */
+ public String getDefaultDetailPane(IStructuredSelection selection) {
+ return NumberFormatDetailPane.ID;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.views.variables.IDetailsFactory#getName(java.lang.String)
+ */
+ public String getDetailPaneName(String id) {
+ if (id.equals(NumberFormatDetailPane.ID)){
+ return MessagesForDetailPane.NumberFormatDetailPane_Name;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.views.variables.IDetailsFactory#getDescription(java.lang.String)
+ */
+ public String getDetailPaneDescription(String id) {
+ if (id.equals(NumberFormatDetailPane.ID)){
+ return MessagesForDetailPane.NumberFormatDetailPane_Description;
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/DsfDebugUITools.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/DsfDebugUITools.java
new file mode 100644
index 00000000000..8ff52b7741d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/DsfDebugUITools.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.jface.preference.IPreferenceStore;
+
+/**
+ * @since 1.1
+ */
+public class DsfDebugUITools {
+
+ public static IPreferenceStore getPreferenceStore()
+ {
+ return DsfUIPlugin.getDefault().getPreferenceStore();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/IDsfDebugUIConstants.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/IDsfDebugUIConstants.java
new file mode 100644
index 00000000000..5e51d671a21
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/IDsfDebugUIConstants.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems, Inc. - initial implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui;
+
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * @noimplement This interface is not intended to be implemented by clients.
+ */
+public interface IDsfDebugUIConstants {
+
+ /**
+ * Debug UI plug-in identifier (value <code>"org.eclipse.cdt.dsf.debug.ui"</code>).
+ */
+ public static final String PLUGIN_ID = "org.eclipse.cdt.dsf.debug.ui"; //$NON-NLS-1$;
+
+ /** Loaded shared library symbols image identifier. */
+ public static final String IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED = "icons/library_syms_obj.gif"; //$NON-NLS-1$
+
+ /** Unloaded Shared library symbols image identifier. */
+ public static final String IMG_OBJS_SHARED_LIBRARY_SYMBOLS_UNLOADED = "icons/library_obj.gif"; //$NON-NLS-1$
+
+ /*
+ * The orientation of the detail view in the VariablesView
+ * Note: these constants should be removed from API. See bug 246005.
+ */
+ public static final String VARIABLES_DETAIL_PANE_ORIENTATION = "Variables.detail.orientation"; //$NON-NLS-1$
+ public static final String EXPRESSIONS_DETAIL_PANE_ORIENTATION = "Expressions.detail.orientation"; //$NON-NLS-1$
+ public static final String REGISTERS_DETAIL_PANE_ORIENTATION = "Registers.detail.orientation"; //$NON-NLS-1$
+ public static final String MODULES_DETAIL_PANE_ORIENTATION = "Modules.detail.orientation"; //$NON-NLS-1$
+ public static final String VARIABLES_DETAIL_PANE_RIGHT = "Variables.detail.orientation.right"; //$NON-NLS-1$
+ public static final String VARIABLES_DETAIL_PANE_UNDERNEATH = "Variables.detail.orientation.underneath"; //$NON-NLS-1$
+ public static final String VARIABLES_DETAIL_PANE_HIDDEN = "Variables.detail.orientation.hidden"; //$NON-NLS-1$
+
+ /**
+ * Boolean preference controlling whether the text in the detail panes is
+ * wrapped. When <code>true</code> the text in the detail panes will be
+ * wrapped in new variable view.
+ */
+ public static final String PREF_DETAIL_PANE_WORD_WRAP = PLUGIN_ID + ".detail_pane_word_wrap"; //$NON-NLS-1$
+
+ /**
+ * Maximum number of characters to display in the details area of the variables
+ * view, or 0 if unlimited.
+ */
+ public static final String PREF_MAX_DETAIL_LENGTH = PLUGIN_ID + ".max_detail_length"; //$NON-NLS-1$
+
+ /**
+ * The name of the font to use for detail panes. This font is managed via
+ * the workbench font preference page.
+ */
+ public static final String DETAIL_PANE_FONT= PLUGIN_ID + "DetailPaneFont"; //$NON-NLS-1$
+
+ /**
+ * Integer preference to control the maximum amount of stack frames to
+ * retrieve from the backend. Default value is <code>10</code>.
+ * @see {@link #PREF_STACK_FRAME_LIMIT_ENABLE}
+ *
+ * @since 1.1
+ */
+ public static final String PREF_STACK_FRAME_LIMIT = "stackFrameLimit"; //$NON-NLS-1$
+
+ /**
+ * Boolean preference whether to apply the stack frame limit preference. Default is <code>true</code>.
+ * @see {@link #PREF_STACK_FRAME_LIMIT}
+ *
+ * @since 1.1
+ */
+ public static final String PREF_STACK_FRAME_LIMIT_ENABLE = "stackFrameLimitEnable"; //$NON-NLS-1$
+
+ /**
+ * Boolean preference whether to keep stepping speed in sync with UI updates. Default is <code>false</code>.
+ *
+ * @since 1.1
+ */
+ public static final String PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE = "delaySteppingForViewUpdatesEnable"; //$NON-NLS-1$
+
+ /**
+ * Integer preference to enforce a minimum time interval between steps. Default is <code>100</code>.
+ *
+ * @since 1.1
+ */
+ public static final String PREF_MIN_STEP_INTERVAL= "minStepInterval"; //$NON-NLS-1$
+
+ /**
+ * Help prefixes.
+ */
+ public static final String PREFIX = IDebugUIConstants.PLUGIN_ID + "."; //$NON-NLS-1$
+
+ public static final String DETAIL_PANE = PREFIX + "detail_pane_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_ASSIGN_VALUE_ACTION = PREFIX + "detail_pane_assign_value_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_CONTENT_ASSIST_ACTION = PREFIX + "detail_pane_content_assist_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_CUT_ACTION = PREFIX + "detail_pane_cut_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_COPY_ACTION = PREFIX + "detail_pane_copy_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_PASTE_ACTION = PREFIX + "detail_pane_paste_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_SELECT_ALL_ACTION = PREFIX + "detail_pane_select_all_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_FIND_REPLACE_ACTION = PREFIX + "detail_pane_find_replace_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_WORD_WRAP_ACTION = PREFIX + "detail_pane_word_wrap_action_context"; //$NON-NLS-1$
+ public static final String DETAIL_PANE_MAX_LENGTH_ACTION = PREFIX + "detail_pane_max_length_action_context"; //$NON-NLS-1$
+
+ /**
+ * @since 1.1
+ */
+ public static final String PREFERENCE_PAGE= PREFIX + "preference_page_context"; //$NON-NLS-1$
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/PreferenceInitializer.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/PreferenceInitializer.java
new file mode 100644
index 00000000000..6c111eee564
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/PreferenceInitializer.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 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.cdt.dsf.debug.ui;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.swt.graphics.RGB;
+
+// Note: this class should be removed from public API. See bug 246004
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+ public PreferenceInitializer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ @Override
+ public void initializeDefaultPreferences() {
+
+ IPreferenceStore prefs = DsfUIPlugin.getDefault().getPreferenceStore();
+
+ /*
+ * Common to all views.
+ */
+ PreferenceConverter.setDefault(prefs, IDebugUIConstants.PREF_CHANGED_DEBUG_ELEMENT_COLOR, new RGB(255, 0, 0));
+ prefs.setDefault(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP, false);
+ prefs.setDefault(IDsfDebugUIConstants.PREF_MAX_DETAIL_LENGTH, 10000);
+
+ /*
+ * Variables view
+ */
+ prefs.setDefault(IDsfDebugUIConstants.VARIABLES_DETAIL_PANE_ORIENTATION, IDsfDebugUIConstants.VARIABLES_DETAIL_PANE_UNDERNEATH);
+
+ /*
+ * Registers View
+ */
+ prefs.setDefault(IDsfDebugUIConstants.REGISTERS_DETAIL_PANE_ORIENTATION, IDsfDebugUIConstants.VARIABLES_DETAIL_PANE_UNDERNEATH);
+
+ /*
+ * Expressions View
+ */
+ prefs.setDefault(IDsfDebugUIConstants.EXPRESSIONS_DETAIL_PANE_ORIENTATION, IDsfDebugUIConstants.VARIABLES_DETAIL_PANE_UNDERNEATH);
+
+ /*
+ * Debug View
+ */
+ prefs.setDefault(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, 10);
+ prefs.setDefault(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE, true);
+ prefs.setDefault(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE, false);
+ prefs.setDefault(IDsfDebugUIConstants.PREF_MIN_STEP_INTERVAL, 100);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfCommandRunnable.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfCommandRunnable.java
new file mode 100644
index 00000000000..f4bc09280fa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfCommandRunnable.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IProcesses;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStepQueueManager;
+import org.eclipse.cdt.dsf.debug.service.StepQueueManager;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+
+@Immutable
+public abstract class DsfCommandRunnable extends DsfRunnable {
+ private final IExecutionDMContext fContext;
+ private final DsfServicesTracker fTracker;
+ private final IDebugCommandRequest fRequest;
+
+ public IExecutionDMContext getContext() { return fContext; }
+ public IRunControl getRunControl() {
+ return fTracker.getService(IRunControl.class);
+ }
+ /**
+ * @deprecated Use {@link #getStepQueueManager()} instead.
+ */
+ @Deprecated
+ public StepQueueManager getStepQueueMgr() {
+ return fTracker.getService(StepQueueManager.class);
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IStepQueueManager getStepQueueManager() {
+ // for backwards compatibility
+ IStepQueueManager mgr= getStepQueueMgr();
+ if (mgr != null) {
+ return mgr;
+ }
+ return getSteppingController();
+ }
+
+ /**
+ * @since 1.1
+ */
+ public SteppingController getSteppingController() {
+ if (fContext != null) {
+ return (SteppingController) fContext.getAdapter(SteppingController.class);
+ }
+ return null;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IProcesses getProcessService() {
+ return fTracker.getService(IProcesses.class);
+ }
+
+ public DsfCommandRunnable(DsfServicesTracker servicesTracker, Object element, IDebugCommandRequest request) {
+ fTracker = servicesTracker;
+ if (element instanceof IDMVMContext) {
+ IDMVMContext vmc = (IDMVMContext)element;
+ fContext = DMContexts.getAncestorOfType(vmc.getDMContext(), IExecutionDMContext.class);
+ } else {
+ fContext = null;
+ }
+
+ fRequest = request;
+ }
+
+ public final void run() {
+ if (fRequest.isCanceled()) {
+ fRequest.done();
+ return;
+ }
+ if (getContext() == null) {
+ fRequest.setStatus(makeError("Selected object does not support run control.", null)); //$NON-NLS-1$
+ } else if (getRunControl() == null || getStepQueueManager() == null) {
+ fRequest.setStatus(makeError("Run Control not available", null)); //$NON-NLS-1$
+ } else {
+ doExecute();
+ }
+ fRequest.done();
+ }
+
+ /**
+ * Method to perform the actual work. It should not call monitor.done(), because
+ * it will be called in the super-class.
+ */
+ protected abstract void doExecute();
+
+ protected IStatus makeError(String message, Throwable e) {
+ return new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, -1, message, e);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfResumeCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfResumeCommand.java
new file mode 100644
index 00000000000..d2d7cb77d1c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfResumeCommand.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IResumeHandler;
+
+@Immutable
+public class DsfResumeCommand implements IResumeHandler {
+
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+
+ public DsfResumeCommand(DsfSession session) {
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ public void canExecute(final IEnabledStateRequest request) {
+ if (request.getElements().length != 1) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getRunControl().canResume(
+ getContext(),
+ new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setEnabled(isSuccess() && getData());
+ request.done();
+ }
+ });
+ }
+ });
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ if (request.getElements().length != 1) {
+ request.done();
+ return false;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getRunControl().resume(getContext(), new RequestMonitor(fExecutor, null));
+ }
+ });
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoCommand.java
new file mode 100644
index 00000000000..94375732dc8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepIntoCommand.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+
+@Immutable
+public class DsfStepIntoCommand implements IStepIntoHandler {
+
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+ private final DsfSteppingModeTarget fSteppingMode;
+
+ public DsfStepIntoCommand(DsfSession session, DsfSteppingModeTarget steppingMode) {
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ fSteppingMode = steppingMode;
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ public void canExecute(final IEnabledStateRequest request) {
+ if (request.getElements().length != 1) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ final StepType stepType= getStepType();
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getStepQueueManager().canEnqueueStep(
+ getContext(), stepType,
+ new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setEnabled(isSuccess() && getData());
+ request.done();
+ }
+ });
+ }
+ });
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ if (request.getElements().length != 1) {
+ request.done();
+ return false;
+ }
+
+ final StepType stepType= getStepType();
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getStepQueueManager().enqueueStep(getContext(), stepType);
+ }
+ });
+ return true;
+ }
+
+
+ /**
+ * @return the currently active step type
+ */
+ protected final StepType getStepType() {
+ boolean instructionSteppingEnabled= fSteppingMode != null && fSteppingMode.isInstructionSteppingEnabled();
+ return instructionSteppingEnabled ? StepType.INSTRUCTION_STEP_INTO : StepType.STEP_INTO;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepOverCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepOverCommand.java
new file mode 100644
index 00000000000..00d8c35e7c0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepOverCommand.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+
+@Immutable
+public class DsfStepOverCommand implements IStepOverHandler {
+
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+ private final DsfSteppingModeTarget fSteppingMode;
+
+ public DsfStepOverCommand(DsfSession session, DsfSteppingModeTarget steppingMode) {
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ fSteppingMode = steppingMode;
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ public void canExecute(final IEnabledStateRequest request) {
+ if (request.getElements().length != 1) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ final StepType stepType= getStepType();
+ @Override public void doExecute() {
+ getStepQueueManager().canEnqueueStep(
+ getContext(), stepType,
+ new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setEnabled(isSuccess() && getData());
+ request.done();
+ }
+ });
+ }
+ });
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ if (request.getElements().length != 1) {
+ request.done();
+ return false;
+ }
+
+ final StepType stepType= getStepType();
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getStepQueueManager().enqueueStep(getContext(), stepType);
+ }
+ });
+ return true;
+ }
+
+ /**
+ * @return the currently active step type
+ */
+ protected final StepType getStepType() {
+ boolean instructionSteppingEnabled= fSteppingMode != null && fSteppingMode.isInstructionSteppingEnabled();
+ return instructionSteppingEnabled ? StepType.INSTRUCTION_STEP_OVER : StepType.STEP_OVER;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepReturnCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepReturnCommand.java
new file mode 100644
index 00000000000..7127fe2f0cb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfStepReturnCommand.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+
+@Immutable
+public class DsfStepReturnCommand implements IStepReturnHandler {
+
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+
+ public DsfStepReturnCommand(DsfSession session) {
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ public void canExecute(final IEnabledStateRequest request) {
+ if (request.getElements().length != 1) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getStepQueueManager().canEnqueueStep(
+ getContext(), StepType.STEP_RETURN,
+ new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setEnabled(isSuccess() && getData());
+ request.done();
+ }
+ });
+ }
+ });
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ if (request.getElements().length != 1) {
+ request.done();
+ return false;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getStepQueueManager().enqueueStep(getContext(), StepType.STEP_RETURN);
+ }
+ });
+ return true;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSteppingModeTarget.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSteppingModeTarget.java
new file mode 100644
index 00000000000..aeb4cf64a62
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSteppingModeTarget.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.debug.core.model.ISteppingModeTarget;
+import org.eclipse.cdt.debug.core.model.ITargetProperties;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.Preferences;
+import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ */
+public class DsfSteppingModeTarget implements ISteppingModeTarget, ITargetProperties {
+
+ private static final String ID_DISASSEMBLY_VIEW= "org.eclipse.cdt.dsf.debug.ui.disassembly.view"; //$NON-NLS-1$
+
+ private final Preferences fPreferences;
+
+ public DsfSteppingModeTarget() {
+ fPreferences= new Preferences();
+ fPreferences.setDefault(PREF_INSTRUCTION_STEPPING_MODE, false);
+ }
+
+ /*
+ * @see org.eclipse.cdt.debug.core.model.ISteppingModeTarget#enableInstructionStepping(boolean)
+ */
+ public void enableInstructionStepping(boolean enabled) {
+ fPreferences.setValue(PREF_INSTRUCTION_STEPPING_MODE, enabled);
+ if (enabled) {
+ try {
+ final IWorkbenchWindow activeWorkbenchWindow= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (activeWorkbenchWindow != null && activeWorkbenchWindow.getActivePage() != null) {
+ activeWorkbenchWindow.getActivePage().showView(ID_DISASSEMBLY_VIEW);
+ }
+ } catch (PartInitException exc) {
+ DsfUIPlugin.log(exc);
+ }
+ }
+ }
+
+ /*
+ * @see org.eclipse.cdt.debug.core.model.ISteppingModeTarget#isInstructionSteppingEnabled()
+ */
+ public boolean isInstructionSteppingEnabled() {
+ return fPreferences.getBoolean(PREF_INSTRUCTION_STEPPING_MODE);
+ }
+
+ /*
+ * @see org.eclipse.cdt.debug.core.model.ISteppingModeTarget#supportsInstructionStepping()
+ */
+ public boolean supportsInstructionStepping() {
+ return true;
+ }
+
+ /*
+ * @see org.eclipse.cdt.debug.core.model.ITargetProperties#addPropertyChangeListener(org.eclipse.core.runtime.Preferences.IPropertyChangeListener)
+ */
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ fPreferences.addPropertyChangeListener(listener);
+ }
+
+ /*
+ * @see org.eclipse.cdt.debug.core.model.ITargetProperties#removePropertyChangeListener(org.eclipse.core.runtime.Preferences.IPropertyChangeListener)
+ */
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ fPreferences.removePropertyChangeListener(listener);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSuspendCommand.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSuspendCommand.java
new file mode 100644
index 00000000000..cee40fccf08
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/actions/DsfSuspendCommand.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+
+@Immutable
+public class DsfSuspendCommand implements ISuspendHandler {
+ private final DsfExecutor fExecutor;
+ private final DsfServicesTracker fTracker;
+
+ public DsfSuspendCommand(DsfSession session) {
+ fExecutor = session.getExecutor();
+ fTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ }
+
+ public void dispose() {
+ fTracker.dispose();
+ }
+
+ public void canExecute(final IEnabledStateRequest request) {
+ if (request.getElements().length != 1) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getRunControl().canSuspend(
+ getContext(),
+ new DataRequestMonitor<Boolean>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setEnabled(isSuccess() && getData());
+ request.done();
+ }
+ });
+ }
+ });
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ if (request.getElements().length != 1) {
+ request.done();
+ return false;
+ }
+
+ fExecutor.submit(new DsfCommandRunnable(fTracker, request.getElements()[0], request) {
+ @Override public void doExecute() {
+ getRunControl().suspend(getContext(), new RequestMonitor(fExecutor, null));
+ }
+ });
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java
new file mode 100644
index 00000000000..c8ed34a9fa1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/contexts/DsfSuspendTrigger.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.contexts;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.ui.contexts.ISuspendTrigger;
+import org.eclipse.debug.ui.contexts.ISuspendTriggerListener;
+
+/**
+ * DSF implementation of the ISuspendTrigger interface. The suspend trigger
+ * is used by the IDE to trigger activation of the debug perspective when
+ * the debugger suspends.
+ *
+ * @see ISuspendTrigger
+ */
+@ConfinedToDsfExecutor("fSession.getExecutor()")
+public class DsfSuspendTrigger implements ISuspendTrigger {
+
+ private final DsfSession fSession;
+ private final ILaunch fLaunch;
+ private boolean fDisposed = false;
+ private boolean fEventListenerRegisterd = false;
+
+ @ThreadSafe
+ private final ListenerList fListeners = new ListenerList();
+
+ @ThreadSafe
+ public DsfSuspendTrigger(DsfSession session, ILaunch launch) {
+ fSession = session;
+ fLaunch = launch;
+ try {
+ fSession.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ if (!fDisposed) {
+ fSession.addServiceEventListener(DsfSuspendTrigger.this, null);
+ fEventListenerRegisterd = true;
+ }
+ }
+ });
+ } catch(RejectedExecutionException e) {}
+ }
+
+ @ThreadSafe
+ public void addSuspendTriggerListener(ISuspendTriggerListener listener) {
+ if (fListeners != null) {
+ fListeners.add(listener);
+ }
+ }
+
+ @ThreadSafe
+ public void removeSuspendTriggerListener(ISuspendTriggerListener listener) {
+ if (fListeners != null) {
+ fListeners.remove(listener);
+ }
+ }
+
+ public void dispose() {
+ if (fEventListenerRegisterd) {
+ fSession.removeServiceEventListener(this);
+ }
+ fDisposed = true;
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.ISuspendedDMEvent e) {
+ final Object[] listeners = fListeners.getListeners();
+ if (listeners.length != 0) {
+ new Job("DSF Suspend Trigger Notify") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final MultiStatus status = new MultiStatus(DsfUIPlugin.PLUGIN_ID, 0, "DSF Suspend Trigger Notify Job Status", null); //$NON-NLS-1$
+ for (int i = 0; i < listeners.length; i++) {
+ final ISuspendTriggerListener listener = (ISuspendTriggerListener) listeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ public void run() throws Exception {
+ listener.suspended(fLaunch, null);
+ }
+
+ public void handleException(Throwable exception) {
+ status.add(new Status(
+ IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, "Exception while calling suspend trigger listeners", exception)); //$NON-NLS-1$
+ }
+
+ });
+ }
+ return status;
+ }
+ }.schedule();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/RefreshAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/RefreshAction.java
new file mode 100644
index 00000000000..bb86ca6d561
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/RefreshAction.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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 - Ted Williams - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.ui.memory;
+
+import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockUpdatePolicyProvider;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.internal.ui.views.memory.MemoryView;
+import org.eclipse.debug.ui.memory.IMemoryRendering;
+import org.eclipse.debug.ui.memory.IMemoryRenderingContainer;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+
+@SuppressWarnings("restriction")
+public class RefreshAction implements IViewActionDelegate {
+
+ private IMemoryBlock fMemoryBlock = null;
+
+ private MemoryView fView;
+
+ public void init(IViewPart view) {
+ fView = (MemoryView) view;
+ }
+
+ public void run(IAction action) {
+
+ if(fMemoryBlock instanceof IMemoryBlockUpdatePolicyProvider)
+ {
+ ((IMemoryBlockUpdatePolicyProvider) fMemoryBlock).clearCache();
+ IMemoryRenderingContainer containers[] = fView.getMemoryRenderingContainers();
+ for(int i = 0; i < containers.length; i++)
+ {
+ IMemoryRendering renderings[] = containers[i].getRenderings();
+ for(int j = 0; j < renderings.length; j++)
+ {
+ if (renderings[j].getControl() instanceof IDebugEventSetListener)
+ {
+ ((IDebugEventSetListener) renderings[j].getControl()).handleDebugEvents(
+ new DebugEvent[] { new DebugEvent(fMemoryBlock, DebugEvent.CHANGE) } );
+ }
+ }
+ }
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ fMemoryBlock = null;
+ action.setEnabled(false);
+ if(selection instanceof IStructuredSelection)
+ {
+ if(((IStructuredSelection) selection).getFirstElement() instanceof IMemoryBlock)
+ {
+ fMemoryBlock = (IMemoryBlock) ((IStructuredSelection) selection).getFirstElement();
+ action.setEnabled(true);
+ }
+ else if(((IStructuredSelection) selection).getFirstElement() instanceof IMemoryRendering)
+ {
+ fMemoryBlock = ((IMemoryRendering) ((IStructuredSelection) selection).getFirstElement()).getMemoryBlock();
+ action.setEnabled(true);
+ }
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/SelectUpdatePolicyAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/SelectUpdatePolicyAction.java
new file mode 100644
index 00000000000..026146eb7ba
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/memory/SelectUpdatePolicyAction.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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 - Ted Williams - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.ui.memory;
+
+import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockUpdatePolicyProvider;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.debug.ui.memory.IMemoryRendering;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IMenuCreator;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.events.MenuAdapter;
+import org.eclipse.swt.events.MenuEvent;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+
+/**
+ *
+ */
+public class SelectUpdatePolicyAction implements IMenuCreator, IViewActionDelegate, IDebugContextListener, IActionDelegate2 {
+
+ private IAction fAction = null;
+ private IMemoryBlock fMemoryBlock = null;
+
+ public void dispose() {
+ // do nothing
+
+ }
+
+ public void runWithEvent(IAction action, Event event) {
+ // do nothing
+ }
+
+ class SelectPolicy extends Action {
+
+ String fID;
+ String fDescription;
+
+ public SelectPolicy(String id, String description) {
+ fID = id;
+ fDescription = description;
+ }
+
+ @Override
+ public String getText() {
+ return fDescription;
+ }
+
+ @Override
+ public void run() {
+ ((IMemoryBlockUpdatePolicyProvider) fMemoryBlock).setUpdatePolicy(fID);
+ }
+
+ }
+
+
+ public Menu getMenu(Control parent) {
+ // Never called
+ return null;
+ }
+
+ protected IAction getAction() { return fAction; }
+
+ public void init(IViewPart view) {
+ }
+
+ public void init(IAction action) {
+ fAction = action;
+ action.setMenuCreator(this);
+ }
+
+ public void run(IAction action) {
+ // Do nothing, this is a pull-down menu
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ fMemoryBlock = null;
+ action.setEnabled(false);
+ if(selection instanceof IStructuredSelection)
+ {
+ if(((IStructuredSelection) selection).getFirstElement() instanceof IMemoryBlock)
+ {
+ fMemoryBlock = (IMemoryBlock) ((IStructuredSelection) selection).getFirstElement();
+ action.setMenuCreator(this);
+ action.setEnabled(true);
+ }
+ else if(((IStructuredSelection) selection).getFirstElement() instanceof IMemoryRendering)
+ {
+ fMemoryBlock = ((IMemoryRendering) ((IStructuredSelection) selection).getFirstElement()).getMemoryBlock();
+ action.setMenuCreator(this);
+ action.setEnabled(true);
+ }
+ }
+ }
+
+ public void debugContextChanged(DebugContextEvent event) {
+ }
+
+ public Menu getMenu(Menu parent) {
+ Menu menu = new Menu(parent);
+ menu.addMenuListener(new MenuAdapter() {
+ @Override
+ public void menuShown(MenuEvent e) {
+ Menu m = (Menu)e.widget;
+ MenuItem[] items = m.getItems();
+ for (int i=0; i < items.length; i++) {
+ items[i].dispose();
+ }
+ fillMenu(m);
+ }
+ });
+ return menu;
+ }
+
+ private void fillMenu(Menu menu) {
+ if(fMemoryBlock instanceof IMemoryBlockUpdatePolicyProvider)
+ {
+ IMemoryBlockUpdatePolicyProvider blockPolicy = (IMemoryBlockUpdatePolicyProvider) fMemoryBlock;
+
+ String currentPolicy = blockPolicy.getUpdatePolicy();
+
+ String policies[] = blockPolicy.getUpdatePolicies();
+ for(int i = 0; i < policies.length; i++)
+ {
+ SelectPolicy action = new SelectPolicy(policies[i], blockPolicy.getUpdatePolicyDescription(policies[i]));
+ ActionContributionItem item = new ActionContributionItem(action);
+ action.setChecked(policies[i].equals(currentPolicy));
+
+ item.fill(menu, -1);
+ }
+ }
+ }
+
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/DsfSourceDisplayAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/DsfSourceDisplayAdapter.java
new file mode 100644
index 00000000000..c9140fc99c9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/DsfSourceDisplayAdapter.java
@@ -0,0 +1,855 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.sourcelookup;
+
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.StepQueueManager;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.debug.sourcelookup.DsfSourceLookupParticipant;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.ISteppingControlParticipant;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IFile;
+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.core.runtime.jobs.Job;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+import org.eclipse.debug.core.sourcelookup.containers.LocalFileStorage;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.sourcelookup.CommonSourceNotFoundEditorInput;
+import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.ITextViewerExtension5;
+import org.eclipse.jface.text.Position;
+import org.eclipse.swt.custom.BusyIndicator;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorDescriptor;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.progress.UIJob;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * Source display adapter that performs the source lookup, opens the editor,
+ * and paints the IP for the given object.
+ * <p>
+ * The implementation relies on three types of jobs to perform the operations.<br>
+ * - The first kind, "lookup job" performs the source lookup operation. <br>
+ * - The second "display job" positions and annotates the editor. <br>
+ * - The third clears the old IP annotations when a thread or process has resumed
+ * or exited.
+ * <p>
+ * The the lookup jobs can run in parallel with the display or the clearing job,
+ * but the clearing job and the display job must not run at the same time.
+ * Hence there is some involved logic which ensures that the jobs are run in
+ * proper order. To avoid race conditions, this logic uses the session's
+ * dispatch thread to synchronize access to the state data of the running jobs.
+ */
+@ThreadSafe
+public class DsfSourceDisplayAdapter implements ISourceDisplay, ISteppingControlParticipant
+{
+ private static final class FrameData {
+ IFrameDMContext fDmc;
+ int fLine;
+ int fLevel;
+ String fFile;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ FrameData other = (FrameData) obj;
+ if (!fDmc.equals(other.fDmc))
+ return false;
+ if (fFile == null) {
+ if (other.fFile != null)
+ return false;
+ } else if (!fFile.equals(other.fFile))
+ return false;
+ return true;
+ }
+
+ /**
+ * Test whether the given frame data instance refers to the very same location.
+ *
+ * @param frameData
+ * @return <code>true</code> if the frame data refers to the same location
+ */
+ public boolean isIdentical(FrameData frameData) {
+ return equals(frameData) && fLine == frameData.fLine;
+ }
+ }
+
+ /**
+ * A job to perform source lookup on the given DMC.
+ */
+ class LookupJob extends Job {
+
+ private final IWorkbenchPage fPage;
+ private final FrameData fFrameData;
+ private final boolean fEventTriggered;
+
+ /**
+ * Constructs a new source lookup job.
+ */
+ public LookupJob(FrameData frameData, IWorkbenchPage page, boolean eventTriggered) {
+ super("DSF Source Lookup"); //$NON-NLS-1$
+ setPriority(Job.INTERACTIVE);
+ setSystem(true);
+ fFrameData = frameData;
+ fPage = page;
+ fEventTriggered = eventTriggered;
+ }
+
+ IDMContext getDmc() { return fFrameData.fDmc; }
+
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+
+ final SourceLookupResult result = performLookup();
+ executeFromJob(new DsfRunnable() { public void run() {
+ if (!monitor.isCanceled()) {
+ fPrevResult = result;
+ fPrevFrameData = fFrameData;
+ fRunningLookupJob = null;
+ startDisplayJob(fPrevResult, fFrameData, fPage, fEventTriggered);
+ }
+ }});
+ return Status.OK_STATUS;
+ }
+
+ private SourceLookupResult performLookup() {
+ IDMContext dmc = fFrameData.fDmc;
+ SourceLookupResult result = new SourceLookupResult(dmc , null, null, null);
+ String editorId = null;
+ IEditorInput editorInput = null;
+ Object sourceElement = fSourceLookup.getSourceElement(dmc);
+
+ if (sourceElement == null) {
+ editorInput = new CommonSourceNotFoundEditorInput(dmc);
+ editorId = IDebugUIConstants.ID_COMMON_SOURCE_NOT_FOUND_EDITOR;
+ } else if (sourceElement instanceof IFile) {
+ editorId = getEditorIdForFilename(((IFile)sourceElement).getName());
+ editorInput = new FileEditorInput((IFile)sourceElement);
+ } else if (sourceElement instanceof ITranslationUnit) {
+ try {
+ URI uriLocation = ((ITranslationUnit)sourceElement).getLocationURI();
+ IFileStore fileStore = EFS.getStore(uriLocation);
+ editorInput = new FileStoreEditorInput(fileStore);
+ editorId = getEditorIdForFilename(fileStore.getName());
+ } catch (CoreException e) {
+ editorInput = new CommonSourceNotFoundEditorInput(dmc);
+ editorId = IDebugUIConstants.ID_COMMON_SOURCE_NOT_FOUND_EDITOR;
+ }
+ } else if (sourceElement instanceof LocalFileStorage) {
+ File file = ((LocalFileStorage)sourceElement).getFile();
+ IFileStore fileStore = EFS.getLocalFileSystem().fromLocalFile(file);
+ editorInput = new FileStoreEditorInput(fileStore);
+ editorId = getEditorIdForFilename(file.getName());
+ }
+ result.setEditorInput(editorInput);
+ result.setEditorId(editorId);
+ result.setSourceElement(sourceElement);
+
+ return result;
+ }
+
+ private String getEditorIdForFilename(String filename) {
+ try {
+ IEditorDescriptor descriptor= IDE.getEditorDescriptor(filename);
+ return descriptor.getId();
+ } catch (PartInitException exc) {
+ DsfUIPlugin.log(exc);
+ }
+ return "org.eclipse.ui.DefaultTextEditor"; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Job that positions the editor and paints the IP Annotation for given DMC.
+ */
+ class DisplayJob extends UIJob {
+ private final SourceLookupResult fResult;
+ private final IWorkbenchPage fPage;
+ private final FrameData fFrameData;
+
+ private final DsfRunnable fDisplayJobFinishedRunnable = new DsfRunnable() {
+ public void run() {
+ // If the current display job does not match up with "this", it means that this job got canceled
+ // after it already completed and after this runnable was queued into the dispatch thread.
+ if (fRunningDisplayJob == DisplayJob.this) {
+ fRunningDisplayJob = null;
+ if (fEventTriggered && !fDoneStepping.getAndSet(true)) {
+ doneStepping(fResult.getDmc());
+ }
+ serviceDisplayAndClearingJobs();
+ }
+ }
+ };
+
+ private final AtomicBoolean fDoneStepping = new AtomicBoolean(false);
+ private IRegion fRegion;
+ private ITextViewer fTextViewer;
+ private final boolean fEventTriggered;
+
+ IDMContext getDmc() { return fResult.getDmc(); }
+
+ /**
+ * Constructs a new source display job
+ */
+ public DisplayJob(SourceLookupResult result, FrameData frameData, IWorkbenchPage page, boolean eventTriggered) {
+ super("Debug Source Display"); //$NON-NLS-1$
+ setSystem(true);
+ setPriority(Job.INTERACTIVE);
+ fResult = result;
+ fFrameData = frameData;
+ fPage = page;
+ fEventTriggered = eventTriggered;
+ }
+
+ @Override
+ public IStatus runInUIThread(final IProgressMonitor monitor) {
+
+ if (monitor.isCanceled()) {
+ executeFromJob(fDisplayJobFinishedRunnable);
+ return Status.CANCEL_STATUS;
+ }
+
+ if (fRegion != null && fTextViewer != null) {
+ if (fRunningDisplayJob == this) {
+ if (!shouldCancelSelectionChange()) {
+ enableLineBackgroundPainter();
+ fTextViewer.setSelectedRange(fRegion.getOffset(), 0);
+ }
+ executeFromJob(fDisplayJobFinishedRunnable);
+ }
+ } else {
+ IEditorPart editor = openEditor(fResult, fPage);
+ if (editor == null) {
+ executeFromJob(fDisplayJobFinishedRunnable);
+ return Status.OK_STATUS;
+ }
+
+ ITextEditor textEditor = null;
+ if (editor instanceof ITextEditor) {
+ textEditor = (ITextEditor)editor;
+ } else {
+ textEditor = (ITextEditor) editor.getAdapter(ITextEditor.class);
+ }
+ if (textEditor != null) {
+ if (positionEditor(textEditor, fFrameData)) {
+ return Status.OK_STATUS;
+ }
+ }
+ executeFromJob(fDisplayJobFinishedRunnable);
+ }
+ return Status.OK_STATUS;
+ }
+
+ private boolean shouldCancelSelectionChange() {
+ Query<Boolean> delaySelectionChangeQuery = new Query<Boolean>() {
+ @Override
+ protected void execute(DataRequestMonitor<Boolean> rm) {
+ IExecutionDMContext execCtx = DMContexts.getAncestorOfType(fFrameData.fDmc,
+ IExecutionDMContext.class);
+
+ IRunControl runControl = fServicesTracker.getService(IRunControl.class);
+ rm.setData(runControl != null && execCtx != null &&
+ (fController.getPendingStepCount(execCtx) != 0 || runControl.isStepping(execCtx)));
+ rm.done();
+ }
+ };
+
+ try {
+ fController.getExecutor().execute(delaySelectionChangeQuery);
+ } catch (RejectedExecutionException e) {
+ return false;
+ }
+
+ try {
+ return delaySelectionChangeQuery.get();
+ } catch (InterruptedException e) {
+ return false;
+ } catch (ExecutionException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Opens the editor used to display the source for an element selected in
+ * this view and returns the editor that was opened or <code>null</code> if
+ * no editor could be opened.
+ */
+ private IEditorPart openEditor(SourceLookupResult result, IWorkbenchPage page) {
+ IEditorInput input= result.getEditorInput();
+ String id= result.getEditorId();
+ if (input == null || id == null) {
+ return null;
+ }
+
+ return openEditor(page, input, id);
+ }
+
+ /**
+ * Opens an editor in the workbench and returns the editor that was opened
+ * or <code>null</code> if an error occurred while attempting to open the
+ * editor.
+ */
+ private IEditorPart openEditor(final IWorkbenchPage page, final IEditorInput input, final String id) {
+ final IEditorPart[] editor = new IEditorPart[] {null};
+ Runnable r = new Runnable() {
+ public void run() {
+ if (!page.getWorkbenchWindow().getWorkbench().isClosing()) {
+ try {
+ editor[0] = page.openEditor(input, id, false);
+ } catch (PartInitException e) {}
+ }
+ }
+ };
+ BusyIndicator.showWhile(Display.getDefault(), r);
+ return editor[0];
+ }
+
+ /**
+ * Positions the text editor for the given stack frame
+ */
+ private boolean positionEditor(ITextEditor editor, final FrameData frameData) {
+ // Position and annotate the editor.
+ fRegion= getLineInformation(editor, frameData.fLine);
+ if (fRegion != null) {
+ // add annotation
+ fIPManager.addAnnotation(
+ editor, frameData.fDmc, new Position(fRegion.getOffset(), fRegion.getLength()),
+ frameData.fLevel == 0);
+
+ // this is a dirty trick to get access to the ITextViewer of the editor
+ Object tot = editor.getAdapter(ITextOperationTarget.class);
+ if (tot instanceof ITextViewer) {
+ fTextViewer = (ITextViewer)tot;
+ int widgetLine = frameData.fLine;
+ if (tot instanceof ITextViewerExtension5) {
+ ITextViewerExtension5 ext5 = (ITextViewerExtension5) tot;
+ // expand region if collapsed
+ ext5.exposeModelRange(fRegion);
+ widgetLine = ext5.modelLine2WidgetLine(widgetLine);
+ }
+ revealLine(fTextViewer, widgetLine);
+
+ if (fStepCount > 0 && fSelectionChangeDelay > 0) {
+ disableLineBackgroundPainter();
+ // reschedule for selection change
+ schedule(fSelectionChangeDelay);
+ if (!fDoneStepping.getAndSet(true)) {
+ doneStepping(getDmc());
+ }
+ return true;
+ } else {
+ enableLineBackgroundPainter();
+ fTextViewer.setSelectedRange(fRegion.getOffset(), 0);
+ }
+ } else {
+ editor.selectAndReveal(fRegion.getOffset(), 0);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Scroll the given line into the visible area if it is not yet visible.
+ * @param focusLine
+ * @see org.eclipse.jface.text.TextViewer#revealRange(int, int)
+ */
+ private void revealLine(ITextViewer viewer, int focusLine) {
+ StyledText textWidget = viewer.getTextWidget();
+ int top = textWidget.getTopIndex();
+ if (top > -1) {
+
+ // scroll vertically
+ int lines = getEstimatedVisibleLinesInViewport(textWidget);
+ int bottom = top + lines;
+
+ int bottomBuffer = Math.max(1, lines / 3);
+
+ if (focusLine >= top && focusLine <= bottom - bottomBuffer) {
+ // do not scroll at all as it is already visible
+ } else {
+ if (focusLine > bottom - bottomBuffer && focusLine <= bottom) {
+ // focusLine is already in bottom bufferZone
+ // scroll to top of bottom bufferzone - for smooth down-scrolling
+ int scrollDelta = focusLine - (bottom - bottomBuffer);
+ textWidget.setTopIndex(top + scrollDelta);
+ } else {
+ // scroll to top of visible area minus buffer zone
+ int topBuffer = lines / 3;
+ textWidget.setTopIndex(Math.max(0, focusLine - topBuffer));
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the number of visible lines in the view port assuming a constant
+ * line height.
+ */
+ private int getEstimatedVisibleLinesInViewport(StyledText textWidget) {
+ if (textWidget != null) {
+ Rectangle clArea= textWidget.getClientArea();
+ if (!clArea.isEmpty())
+ return clArea.height / textWidget.getLineHeight();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the line information for the given line in the given editor
+ */
+ private IRegion getLineInformation(ITextEditor editor, int lineNumber) {
+ IDocumentProvider provider= editor.getDocumentProvider();
+ IEditorInput input= editor.getEditorInput();
+ try {
+ provider.connect(input);
+ } catch (CoreException e) {
+ return null;
+ }
+ try {
+ IDocument document= provider.getDocument(input);
+ if (document != null)
+ return document.getLineInformation(lineNumber);
+ } catch (BadLocationException e) {
+ } finally {
+ provider.disconnect(input);
+ }
+ return null;
+ }
+
+ }
+
+ /**
+ * Job that removes the old IP Annotations associated with given execution
+ * context.
+ */
+ class ClearingJob extends UIJob {
+ Set<IRunControl.IExecutionDMContext> fDmcsToClear;
+
+ public ClearingJob(Set<IRunControl.IExecutionDMContext> dmcs) {
+ super("Debug Source Display"); //$NON-NLS-1$
+ setSystem(true);
+ setPriority(Job.INTERACTIVE);
+ fDmcsToClear = dmcs;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ DsfRunnable clearingJobFinishedRunnable = new DsfRunnable() { public void run() {
+ assert fRunningClearingJob == ClearingJob.this;
+ fRunningClearingJob = null;
+ serviceDisplayAndClearingJobs();
+ }};
+
+ enableLineBackgroundPainter();
+
+ if (monitor.isCanceled()) {
+ executeFromJob(clearingJobFinishedRunnable);
+ return Status.CANCEL_STATUS;
+ }
+
+ for (IRunControl.IExecutionDMContext dmc : fDmcsToClear) {
+ fIPManager.removeAnnotations(dmc);
+ }
+
+ executeFromJob(clearingJobFinishedRunnable);
+ return Status.OK_STATUS;
+ }
+ }
+
+ private static final boolean DEBUG = false;
+
+ private DsfSession fSession;
+ private DsfExecutor fExecutor;
+ private DsfServicesTracker fServicesTracker;
+ private FrameData fPrevFrameData;
+ private SourceLookupResult fPrevResult;
+ private ISourceLookupDirector fSourceLookup;
+ private DsfSourceLookupParticipant fSourceLookupParticipant;
+ private InstructionPointerManager fIPManager;
+
+ private LookupJob fRunningLookupJob;
+ private DisplayJob fRunningDisplayJob;
+ private DisplayJob fPendingDisplayJob;
+ private ClearingJob fRunningClearingJob;
+ private Set<IRunControl.IExecutionDMContext> fPendingExecDmcsToClear = new HashSet<IRunControl.IExecutionDMContext>();
+ private SteppingController fController;
+
+ /** Delay (in milliseconds) before the selection is changed to the IP location */
+ private int fSelectionChangeDelay = 150;
+
+ private long fStepStartTime = 0;
+ private long fLastStepTime = 0;
+ private long fStepCount;
+
+ private boolean fEnableLineBackgroundPainter;
+
+ public DsfSourceDisplayAdapter(DsfSession session, ISourceLookupDirector sourceLocator) {
+ this(session, sourceLocator, null);
+ }
+
+ /**
+ * @since 1.1
+ */
+ public DsfSourceDisplayAdapter(DsfSession session, ISourceLookupDirector sourceLocator, SteppingController controller) {
+ fSession = session;
+ fExecutor = session.getExecutor();
+ fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ fSourceLookup = sourceLocator;
+ fSourceLookupParticipant = new DsfSourceLookupParticipant(session);
+ fSourceLookup.addParticipants(new ISourceLookupParticipant[] {fSourceLookupParticipant} );
+
+ fIPManager = new InstructionPointerManager();
+
+ fSession.addServiceEventListener(this, null);
+
+ fController = controller;
+ if (fController != null) {
+ fController.addSteppingControlParticipant(this);
+ }
+ }
+
+ /**
+ * Configure the delay (in milliseconds) before the selection in the editor
+ * is changed to the IP location.
+ *
+ * @param delay the delay in milliseconds, a non-negative integer
+ *
+ * @since 1.1
+ */
+ public void setSelectionChangeDelay(int delay) {
+ fSelectionChangeDelay = delay;
+ }
+
+ public void dispose() {
+ if (fController != null) {
+ fController.removeSteppingControlParticipant(this);
+ fController = null;
+ }
+ fSession.removeServiceEventListener(this);
+ fServicesTracker.dispose();
+ fSourceLookup.removeParticipants(new ISourceLookupParticipant[] {fSourceLookupParticipant});
+
+ // fSourceLookupParticipant is disposed by the source lookup director
+
+ // Need to remove annotations in UI thread.
+ Display display = Display.getDefault();
+ if (!display.isDisposed()) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ enableLineBackgroundPainter();
+ fIPManager.removeAllAnnotations();
+ }});
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.contexts.ISourceDisplayAdapter#displaySource(java.lang.Object, org.eclipse.ui.IWorkbenchPage, boolean)
+ */
+ public void displaySource(Object context, final IWorkbenchPage page, final boolean force) {
+ fStepCount = 0;
+
+ if (!(context instanceof IDMVMContext)) return;
+ final IDMContext dmc = ((IDMVMContext)context).getDMContext();
+
+ // Quick test. DMC is checked again in source lookup participant, but
+ // it's much quicker to test here.
+ if (!(dmc instanceof IFrameDMContext)) return;
+ doDisplaySource((IFrameDMContext) dmc, page, force, false);
+ }
+
+ private void doDisplaySource(final IFrameDMContext context, final IWorkbenchPage page, final boolean force, final boolean eventTriggered) {
+ if (context.getLevel() < 0) {
+ return;
+ }
+ // Re-dispatch to executor thread before accessing job lists.
+ fExecutor.execute(new DsfRunnable() { public void run() {
+ // We need to retrieve the frame level and line number from the service.
+ IStack stackService = fServicesTracker.getService(IStack.class);
+ if (stackService == null) {
+ return;
+ }
+ stackService.getFrameData(
+ context,
+ new DataRequestMonitor<IFrameDMData>(fExecutor, null) {
+ @Override
+ public void handleSuccess() {
+ FrameData frameData = new FrameData();
+ frameData.fDmc = context;
+ frameData.fLevel = context.getLevel();
+ // Document line numbers are 0-based. While debugger line numbers are 1-based.
+ IFrameDMData data = getData();
+ frameData.fLine = data.getLine() - 1;
+ frameData.fFile = data.getFile();
+ if (!force && frameData.equals(fPrevFrameData)) {
+ fPrevResult.updateArtifact(context);
+ startDisplayJob(fPrevResult, frameData, page, eventTriggered);
+ } else {
+ startLookupJob(frameData, page, eventTriggered);
+ }
+ }
+ });
+ }});
+ }
+
+ private void executeFromJob(Runnable runnable) {
+ try {
+ fExecutor.execute(runnable);
+ } catch (RejectedExecutionException e) {
+ // Session disposed, ignore
+ }
+ }
+
+ private void startLookupJob(final FrameData frameData, final IWorkbenchPage page, boolean eventTriggered) {
+ // If there is a previous lookup job running, cancel it.
+ if (fRunningLookupJob != null) {
+ fRunningLookupJob.cancel();
+ }
+
+ fRunningLookupJob = new LookupJob(frameData, page, eventTriggered);
+ fRunningLookupJob.schedule();
+ }
+
+ // To be called only on dispatch thread.
+ private void startDisplayJob(SourceLookupResult lookupResult, FrameData frameData, IWorkbenchPage page, boolean eventTriggered) {
+ DisplayJob nextDisplayJob = new DisplayJob(lookupResult, frameData, page, eventTriggered);
+ if (fRunningDisplayJob != null) {
+ fPendingDisplayJob = null;
+ IExecutionDMContext[] execCtxs = DMContexts.getAllAncestorsOfType(frameData.fDmc, IExecutionDMContext.class);
+ fPendingExecDmcsToClear.removeAll(Arrays.asList(execCtxs));
+
+ if (!eventTriggered && frameData.isIdentical(fRunningDisplayJob.fFrameData)) {
+ // identical location - we are done
+ return;
+ }
+ // cancel running display job
+ fRunningDisplayJob.cancel();
+ }
+ if (fRunningClearingJob != null) {
+ // Wait for the clearing job to finish, instead, set the
+ // display job as pending.
+ fPendingDisplayJob = nextDisplayJob;
+ } else {
+ fRunningDisplayJob = nextDisplayJob;
+ fRunningDisplayJob.schedule();
+ }
+ }
+
+ private void doneStepping(IDMContext context) {
+ if (fController != null) {
+ // indicate completion of step
+ final IExecutionDMContext dmc = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
+ if (dmc != null) {
+ fController.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ fController.doneStepping(dmc, DsfSourceDisplayAdapter.this);
+ };
+ });
+ }
+ }
+ }
+
+ private void serviceDisplayAndClearingJobs() {
+ if (!fPendingExecDmcsToClear.isEmpty()) {
+ // There are annotations to be cleared, run the job first
+ fRunningClearingJob = new ClearingJob(fPendingExecDmcsToClear);
+ fRunningClearingJob.schedule();
+ fPendingExecDmcsToClear = new HashSet<IRunControl.IExecutionDMContext>();
+ } else if (fPendingDisplayJob != null) {
+ fRunningDisplayJob = fPendingDisplayJob;
+ fRunningDisplayJob.schedule();
+ fPendingDisplayJob = null;
+ }
+ }
+
+ private void startAnnotationClearingJob(IRunControl.IExecutionDMContext execDmc) {
+ // Make sure to add the context to the list.
+ fPendingExecDmcsToClear.add(execDmc);
+
+ // If lookup job is running, check it against the execution context,
+ // and cancel it if matches.
+ if (fRunningLookupJob != null) {
+ if (DMContexts.isAncestorOf(fRunningLookupJob.getDmc(), execDmc)) {
+ fRunningLookupJob.cancel();
+ fRunningLookupJob = null;
+ }
+ }
+ // If there is a pending display job, make sure it doesn't get
+ // preempted by this event. If so, just cancel the pending
+ // display job.
+ if (fPendingDisplayJob != null) {
+ if (DMContexts.isAncestorOf(fPendingDisplayJob.getDmc(), execDmc)) {
+ fPendingDisplayJob = null;
+ }
+ }
+
+ // If no display or clearing jobs are running, schedule the clearing job.
+ if (fRunningClearingJob == null && fRunningDisplayJob == null) {
+ fRunningClearingJob = new ClearingJob(fPendingExecDmcsToClear);
+ fRunningClearingJob.schedule();
+ fPendingExecDmcsToClear = new HashSet<IRunControl.IExecutionDMContext>();
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.IResumedDMEvent e) {
+ if (e.getReason() != StateChangeReason.STEP) {
+ startAnnotationClearingJob(e.getDMContext());
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.IExitedDMEvent e) {
+ startAnnotationClearingJob(e.getDMContext());
+ }
+
+ /**
+ * @since 1.1
+ */
+ @DsfServiceEventHandler
+ public void eventDispatched(SteppingTimedOutEvent e) {
+ startAnnotationClearingJob(e.getDMContext());
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(StepQueueManager.ISteppingTimedOutEvent e) {
+ startAnnotationClearingJob(e.getDMContext());
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final IRunControl.ISuspendedDMEvent e) {
+ updateStepTiming();
+ if (e.getReason() == StateChangeReason.STEP || e.getReason() == StateChangeReason.BREAKPOINT) {
+ // trigger source display immediately (should be optional?)
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ Object context = DebugUITools.getDebugContext();
+ if (context instanceof IDMVMContext) {
+ final IDMContext dmc = ((IDMVMContext)context).getDMContext();
+ if (dmc instanceof IFrameDMContext && DMContexts.isAncestorOf(dmc, e.getDMContext())) {
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ doDisplaySource((IFrameDMContext) dmc, page, false, true);
+ }
+ }
+ }});
+ } else {
+ doneStepping(e.getDMContext());
+ }
+ }
+
+ private void updateStepTiming() {
+ long now = System.currentTimeMillis();
+ if (now - fLastStepTime > Math.max(fSelectionChangeDelay, 200)) {
+ fStepCount = 0;
+ fStepStartTime = fLastStepTime = now;
+ return;
+ }
+ fLastStepTime = now;
+ ++fStepCount;
+ if (DEBUG) {
+ long delta = now - fStepStartTime;
+ float meanTime = delta/(float)fStepCount/1000;
+ System.out.println("[DsfSourceDisplayAdapter] step speed = " + 1/meanTime); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Disable editor line background painter if it is enabled.
+ * <p>
+ * <strong>Must be called on display thread.</strong>
+ * </p>
+ */
+ private void disableLineBackgroundPainter() {
+ if (!fEnableLineBackgroundPainter) {
+ fEnableLineBackgroundPainter = EditorsUI.getPreferenceStore().getBoolean(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE);
+ if (fEnableLineBackgroundPainter) {
+ EditorsUI.getPreferenceStore().setValue(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, false);
+ }
+ }
+ }
+
+ /**
+ * Enable the editor line background painter if it was enabled before.
+ * <p>
+ * <strong>Must be called on display thread.</strong>
+ * </p>
+ */
+ private void enableLineBackgroundPainter() {
+ if (fEnableLineBackgroundPainter) {
+ fEnableLineBackgroundPainter = false;
+ EditorsUI.getPreferenceStore().setValue(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, true);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java
new file mode 100644
index 00000000000..7a0d2d2196e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerImageProvider.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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.cdt.dsf.debug.ui.sourcelookup;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.ui.sourcelookup.InstructionPointerManager.IPAnnotation;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.texteditor.IAnnotationImageProvider;
+
+@ThreadSafe
+public class InstructionPointerImageProvider implements IAnnotationImageProvider {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getManagedImage(org.eclipse.jface.text.source.Annotation)
+ */
+ public Image getManagedImage(Annotation annotation) {
+ return ((IPAnnotation)annotation).getImage();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getImageDescriptorId(org.eclipse.jface.text.source.Annotation)
+ */
+ public String getImageDescriptorId(Annotation annotation) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IAnnotationImageProvider#getImageDescriptor(java.lang.String)
+ */
+ public ImageDescriptor getImageDescriptor(String imageDescritporId) {
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerManager.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerManager.java
new file mode 100644
index 00000000000..825ec43daf3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/InstructionPointerManager.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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
+ * Wind River Systems - Adapter to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.sourcelookup;
+
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * This class tracks instruction pointer contexts for a single DSF session.
+ */
+@ThreadSafe
+class InstructionPointerManager {
+
+ /**
+ * Current instruction pointer annotation type.
+ */
+ private static final String ID_CURRENT_IP= "org.eclipse.cdt.dsf.debug.currentIP"; //$NON-NLS-1$
+
+ /**
+ * Secondary instruction pointer annotation type.
+ */
+ private static final String ID_SECONDARY_IP= "org.eclipse.cdt.dsf.debug.secondaryIP"; //$NON-NLS-1$
+
+ /**
+ * Editor annotation object for instruction pointers.
+ */
+ static class IPAnnotation extends Annotation {
+
+ /** The image for this annotation. */
+ private Image fImage;
+
+ /** Frame DMC that this IP is for **/
+ private IStack.IFrameDMContext fFrame;
+
+ /**
+ * Constructs an instruction pointer image.
+ *
+ * @param frame stack frame the instruction pointer is associated with
+ * @param annotationType the type of annotation to display (annotation identifier)
+ * @param text the message to display with the annotation as hover help
+ * @param image the image used to display the annotation
+ */
+ IPAnnotation(IStack.IFrameDMContext frame, String annotationType, String text, Image image) {
+ super(annotationType, false, text);
+ fFrame = frame;
+ fImage = image;
+ }
+
+ /**
+ * Returns this annotation's image.
+ *
+ * @return image
+ */
+ protected Image getImage() {
+ return fImage;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof IPAnnotation) {
+ return fFrame.equals(((IPAnnotation)other).fFrame);
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return fFrame.hashCode();
+ }
+
+ }
+
+ /**
+ * Represents the context for a single instruction pointer. This is a convenience class
+ * used to store the three objects that comprise an instruction pointer 'context' so it
+ * can be stored in collections.
+ */
+ static class AnnotationWrapper {
+
+ /** The text editor for this context. */
+ private ITextEditor fTextEditor;
+
+ /** Stack frame that this annotation is for */
+ private IStack.IFrameDMContext fFrameDmc;
+
+ /** The vertical ruler annotation for this context. */
+ private Annotation fAnnotation;
+
+ AnnotationWrapper(ITextEditor textEditor, Annotation annotation, IStack.IFrameDMContext frameDmc) {
+ fTextEditor = textEditor;
+ fAnnotation = annotation;
+ fFrameDmc = frameDmc;
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof AnnotationWrapper) {
+ AnnotationWrapper otherContext = (AnnotationWrapper) other;
+ return getAnnotation().equals(otherContext.getAnnotation());
+ }
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return getAnnotation().hashCode();
+ }
+
+ ITextEditor getTextEditor() { return fTextEditor; }
+ Annotation getAnnotation() { return fAnnotation; }
+ IStack.IFrameDMContext getFrameDMC() { return fFrameDmc; }
+ }
+
+ /**
+ * Mapping of IDebugTarget objects to (mappings of IThread objects to lists of instruction
+ * pointer contexts).
+ */
+ private List<AnnotationWrapper> fAnnotationWrappers;
+
+ /**
+ * Clients must not instantiate this class.
+ */
+ public InstructionPointerManager() {
+ fAnnotationWrappers = Collections.synchronizedList(new LinkedList<AnnotationWrapper>());
+ }
+
+ /**
+ * Add an instruction pointer annotation in the specified editor for the
+ * specified stack frame.
+ */
+ public void addAnnotation(ITextEditor textEditor, IStack.IFrameDMContext frame, Position position, boolean isTopFrame) {
+
+ IDocumentProvider docProvider = textEditor.getDocumentProvider();
+ IEditorInput editorInput = textEditor.getEditorInput();
+ // If there is no annotation model, there's nothing more to do
+ IAnnotationModel annModel = docProvider.getAnnotationModel(editorInput);
+ if (annModel == null) {
+ return;
+ }
+
+ String id;
+ String text;
+ Image image;
+ if (isTopFrame) {
+ id = ID_CURRENT_IP;
+ text = "Debug Current Instruction Pointer"; //$NON-NLS-1$
+ image = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER_TOP);
+ } else {
+ id = ID_SECONDARY_IP;
+ text = "Debug Call Stack"; //$NON-NLS-1$
+ image = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_INSTRUCTION_POINTER);
+ }
+
+ if (isTopFrame) {
+ // remove other top-frame IP annotation(s) for this execution-context
+ removeAnnotations(DMContexts.getAncestorOfType(frame.getParents()[0], IExecutionDMContext.class));
+ }
+ Annotation annotation = new IPAnnotation(frame, id, text, image);
+
+ // Add the annotation at the position to the editor's annotation model.
+ annModel.removeAnnotation(annotation);
+ annModel.addAnnotation(annotation, position);
+
+ // Add to list of existing wrappers
+ fAnnotationWrappers.add(new AnnotationWrapper(textEditor, annotation, frame));
+ }
+
+ /**
+ * Remove all annotations associated with the specified debug target that this class
+ * is tracking.
+ */
+ public void removeAnnotations(IRunControl.IExecutionDMContext execDmc) {
+ // Retrieve the mapping of threads to context lists
+ synchronized(fAnnotationWrappers) {
+ for (Iterator<AnnotationWrapper> wrapperItr = fAnnotationWrappers.iterator(); wrapperItr.hasNext();) {
+ AnnotationWrapper wrapper = wrapperItr.next();
+ if (DMContexts.isAncestorOf(wrapper.getFrameDMC(), execDmc)) {
+ removeAnnotation(wrapper.getTextEditor(), wrapper.getAnnotation());
+ wrapperItr.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove all top-frame annotations associated with the specified debug target that this class
+ * is tracking.
+ */
+ public void removeTopFrameAnnotations(IRunControl.IExecutionDMContext execDmc) {
+ // Retrieve the mapping of threads to context lists
+ synchronized(fAnnotationWrappers) {
+ for (Iterator<AnnotationWrapper> wrapperItr = fAnnotationWrappers.iterator(); wrapperItr.hasNext();) {
+ AnnotationWrapper wrapper = wrapperItr.next();
+ if (DMContexts.isAncestorOf(wrapper.getFrameDMC(), execDmc)
+ && ID_CURRENT_IP.equals(wrapper.getAnnotation().getType())) {
+ removeAnnotation(wrapper.getTextEditor(), wrapper.getAnnotation());
+ wrapperItr.remove();
+ }
+ }
+ }
+ }
+
+ /** Removes all annotations tracked by this manager */
+ public void removeAllAnnotations() {
+ synchronized(fAnnotationWrappers) {
+ for (AnnotationWrapper wrapper : fAnnotationWrappers) {
+ removeAnnotation(wrapper.getTextEditor(), wrapper.getAnnotation());
+ }
+ fAnnotationWrappers.clear();
+ }
+ }
+
+ /**
+ * Remove the specified annotation from the specified text editor.
+ */
+ private void removeAnnotation(ITextEditor textEditor, Annotation annotation) {
+ IDocumentProvider docProvider = textEditor.getDocumentProvider();
+ if (docProvider != null) {
+ IAnnotationModel annotationModel = docProvider.getAnnotationModel(textEditor.getEditorInput());
+ if (annotationModel != null) {
+ annotationModel.removeAnnotation(annotation);
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/SourceLookupResult.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/SourceLookupResult.java
new file mode 100644
index 00000000000..707d3c4eb3e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/sourcelookup/SourceLookupResult.java
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.sourcelookup;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.ui.IEditorInput;
+
+/**
+ * The result of a source lookup contains the source element, editor id, and
+ * editor input resolved for a debug artifact.
+ *
+ * @since 3.1
+ */
+class SourceLookupResult {
+
+ /**
+ * Element that source was resolved for.
+ */
+ private IDMContext fDmc;
+ /**
+ * Corresponding source element, or <code>null</code>
+ * if unknown.
+ */
+ private Object fSourceElement;
+ /**
+ * Associated editor id, used to display the source element,
+ * or <code>null</code> if unknown.
+ */
+ private String fEditorId;
+ /**
+ * Associatd editor input, used to display the source element,
+ * or <code>null</code> if unknown.
+ */
+ private IEditorInput fEditorInput;
+
+ /**
+ * Creates a source lookup result on the given artifact, source element,
+ * editor id, and editor input.
+ */
+ public SourceLookupResult(IDMContext dmc, Object sourceElement, String editorId, IEditorInput editorInput) {
+ fDmc = dmc;
+ setSourceElement(sourceElement);
+ setEditorId(editorId);
+ setEditorInput(editorInput);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getArtifact()
+ */
+ public IDMContext getDmc() {
+ return fDmc;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getSourceElement()
+ */
+ public Object getSourceElement() {
+ return fSourceElement;
+ }
+
+ /**
+ * Sets the source element resolved for the artifact that source
+ * lookup was performed for, or <code>null</code> if a source element
+ * was not resolved.
+ *
+ * @param element resolved source element or <code>null</code> if unknown
+ */
+ protected void setSourceElement(Object element) {
+ fSourceElement = element;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getEditorId()
+ */
+ public String getEditorId() {
+ return fEditorId;
+ }
+
+ /**
+ * Sets the identifier of the editor used to display this source
+ * lookup result's source element, or <code>null</code> if unknown.
+ *
+ * @param id the identifier of the editor used to display this source
+ * lookup result's source element, or <code>null</code> if unknown
+ */
+ protected void setEditorId(String id) {
+ fEditorId = id;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.sourcelookup.ISourceLookupResult#getEditorInput()
+ */
+ public IEditorInput getEditorInput() {
+ return fEditorInput;
+ }
+
+ /**
+ * Sets the editor input used to display this source lookup
+ * result's source element, or <code>null</code> if unknown.
+ *
+ * @param input the editor input used to display this source lookup
+ * result's source element, or <code>null</code> if unknown
+ */
+ protected void setEditorInput(IEditorInput input) {
+ fEditorInput = input;
+ }
+
+ /**
+ * Updates the artifact to refer to the given artifact
+ * if equal. For example, when a source lookup result is resued
+ * for the same stack frame, we still need to update in case
+ * the stack frame is not identical.
+ *
+ * @param artifact new artifact state
+ */
+ public void updateArtifact(IDMContext dmc) {
+ if (fDmc.equals(dmc)) {
+ fDmc = dmc;
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/AbstractDebugVMAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/AbstractDebugVMAdapter.java
new file mode 100644
index 00000000000..6a6c8e7fc46
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/AbstractDebugVMAdapter.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.ISteppingControlParticipant;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ * Base class for VM adapters used for implementing a debugger integration.
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class AbstractDebugVMAdapter extends AbstractDMVMAdapter
+ implements ISteppingControlParticipant
+{
+
+ public AbstractDebugVMAdapter(DsfSession session, final SteppingController controller) {
+ super(session);
+ fController = controller;
+ try {
+ fController.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ fController.addSteppingControlParticipant(AbstractDebugVMAdapter.this);
+ }
+ });
+ } catch (RejectedExecutionException e) {} // Do nothing if session is shut down.
+ }
+
+ private final SteppingController fController;
+
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ return null;
+ }
+
+ @Override
+ public void doneHandleEvent(Object event) {
+ if (event instanceof IRunControl.ISuspendedDMEvent) {
+ final ISuspendedDMEvent suspendedEvent= (IRunControl.ISuspendedDMEvent) event;
+ fController.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ fController.doneStepping(suspendedEvent.getDMContext(), AbstractDebugVMAdapter.this);
+ };
+ });
+ }
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ fController.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ fController.removeSteppingControlParticipant(AbstractDebugVMAdapter.this);
+ }
+ });
+ } catch (RejectedExecutionException e) {} // Do nothing if session is shut down.
+ super.dispose();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/IDebugVMConstants.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/IDebugVMConstants.java
new file mode 100644
index 00000000000..29647fc5f86
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/IDebugVMConstants.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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 - Ted Williams - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+
+public interface IDebugVMConstants {
+ /**
+ * Standard across the board column IDs.
+ */
+ public static final String ID = DsfUIPlugin.PLUGIN_ID + ".VARIABLES_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+ public static final String COLUMN_ID__NAME = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__NAME"; //$NON-NLS-1$
+ public static final String COLUMN_ID__TYPE = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__TYPE"; //$NON-NLS-1$
+ public static final String COLUMN_ID__VALUE = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__VALUE"; //$NON-NLS-1$
+ public static final String COLUMN_ID__ADDRESS = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__ADDRESS"; //$NON-NLS-1$
+ public static final String COLUMN_ID__DESCRIPTION = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__DESCRIPTION"; //$NON-NLS-1$
+ public static final String COLUMN_ID__EXPRESSION = DsfUIPlugin.PLUGIN_ID + ".COLUMN_ID__EXPRESSION"; //$NON-NLS-1$
+
+ /**
+ * Location of the current format in the IPresentationContext data store.
+ */
+ public final static String CURRENT_FORMAT_STORAGE = "CurrentNumericStyle" ; //$NON-NLS-1$
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/SteppingController.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/SteppingController.java
new file mode 100644
index 00000000000..1f7a2890fe8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/SteppingController.java
@@ -0,0 +1,572 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStepQueueManager;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+/**
+ * This class builds on top of standard run control service to provide
+ * functionality for step queuing and delaying. Step queuing essentially allows
+ * user to press and hold the step key and achieve maximum stepping speed. If
+ * this class is used, other service implementations, such as stack and
+ * expressions, can use it to avoid requesting data from debugger back end if
+ * another step is about to be executed.
+ *
+ * @since 1.1
+ */
+public final class SteppingController implements IStepQueueManager
+{
+ /**
+ * Amount of time in milliseconds, that it takes the SteppingTimedOutEvent
+ * event to be issued after a step is started.
+ * @see SteppingTimedOutEvent
+ */
+ public final static int STEPPING_TIMEOUT = 500;
+
+ /**
+ * The depth of the step queue. In other words, the maximum number of steps
+ * that are queued before the step queue manager is throwing them away.
+ */
+ public final static int STEP_QUEUE_DEPTH = 2;
+
+ /**
+ * The maximum delay (in milliseconds) between steps when synchronized
+ * stepping is enabled. This also serves as a safeguard in the case stepping
+ * control participants fail to indicate completion of event processing.
+ */
+ public final static int MAX_STEP_DELAY= 5000;
+
+ private final static boolean DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/stepping")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Indicates that the given context has been stepping for some time,
+ * and the UI (views and actions) may need to be updated accordingly.
+ */
+ public static final class SteppingTimedOutEvent extends AbstractDMEvent<IExecutionDMContext> {
+ private SteppingTimedOutEvent(IExecutionDMContext execCtx) {
+ super(execCtx);
+ }
+ }
+
+ /**
+ * Interface for clients interested in stepping control. When a stepping
+ * control participant is registered with the stepping controller, it is
+ * expected to call
+ * {@link SteppingController#doneStepping(IExecutionDMContext, ISteppingControlParticipant)
+ * doneStepping} as soon as a "step", i.e. a suspended event has been
+ * processed. If synchronized stepping is enabled, further stepping is
+ * blocked until all stepping control participants have indicated completion
+ * of event processing or the maximum timeout
+ * {@link SteppingController#MAX_STEP_DELAY} has been reached.
+ *
+ * @see SteppingController#addSteppingControlParticipant(ISteppingControlParticipant)
+ * @see SteppingController#removeSteppingControlParticipant(ISteppingControlParticipant)
+ */
+ public interface ISteppingControlParticipant {
+ }
+
+ private static class StepRequest {
+ IExecutionDMContext fContext;
+ StepType fStepType;
+ boolean inProgress = false;
+ StepRequest(IExecutionDMContext execCtx, StepType type) {
+ fContext = execCtx;
+ fStepType = type;
+ }
+ }
+
+ private final DsfSession fSession;
+ private final DsfServicesTracker fServicesTracker;
+
+ private IRunControl fRunControl;
+ private int fQueueDepth = STEP_QUEUE_DEPTH;
+
+ private final Map<IExecutionDMContext,List<StepRequest>> fStepQueues = new HashMap<IExecutionDMContext,List<StepRequest>>();
+ private final Map<IExecutionDMContext,Boolean> fTimedOutFlags = new HashMap<IExecutionDMContext,Boolean>();
+ private final Map<IExecutionDMContext,ScheduledFuture<?>> fTimedOutFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
+
+ /**
+ * Records the time of the last step for an execution context.
+ */
+ private final Map<IExecutionDMContext, Long> fLastStepTimes= new HashMap<IExecutionDMContext, Long>();
+
+ /**
+ * Minimum step interval in milliseconds.
+ */
+ private int fMinStepInterval= 0;
+
+ /**
+ * Map of execution contexts for which a step is in progress.
+ */
+ private final Map<IExecutionDMContext, List<ISteppingControlParticipant>> fStepInProgress = new HashMap<IExecutionDMContext, List<ISteppingControlParticipant>>();
+
+ /**
+ * List of registered stepping control participants.
+ */
+ private final List<ISteppingControlParticipant> fParticipants = Collections.synchronizedList(new ArrayList<ISteppingControlParticipant>());
+
+ /**
+ * Property change listener. It updates the stepping control settings.
+ */
+ private IPropertyChangeListener fPreferencesListener;
+
+ public SteppingController(DsfSession session) {
+ fSession = session;
+ fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+
+ final IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore();
+
+ fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ handlePropertyChanged(store, event);
+ }};
+ store.addPropertyChangeListener(fPreferencesListener);
+
+ setMinimumStepInterval(store.getInt(IDsfDebugUIConstants.PREF_MIN_STEP_INTERVAL));
+ }
+
+ public void dispose() {
+ if (fRunControl != null) {
+ getSession().removeServiceEventListener(this);
+ }
+
+ IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore();
+ store.removePropertyChangeListener(fPreferencesListener);
+
+ fServicesTracker.dispose();
+ }
+
+ /**
+ * Configure the minimum time (in milliseconds) to wait between steps.
+ *
+ * @param interval
+ */
+ public void setMinimumStepInterval(int interval) {
+ fMinStepInterval = interval;
+ }
+
+ /**
+ * Register given stepping control participant.
+ * <p>
+ * Participants are obliged to call
+ * {@link #doneStepping(IExecutionDMContext, ISteppingControlParticipant)}
+ * when they have received and completed processing an
+ * {@link ISuspendedDMEvent}. If synchronized stepping is enabled, further
+ * stepping is disabled until all participants have indicated completion of
+ * processing the event.
+ * </p>
+ *
+ * @param participant
+ */
+ public void addSteppingControlParticipant(ISteppingControlParticipant participant) {
+ fParticipants.add(participant);
+ }
+
+ /**
+ * Unregister given stepping control participant.
+ *
+ * @param participant
+ */
+ public void removeSteppingControlParticipant(final ISteppingControlParticipant participant) {
+ fParticipants.remove(participant);
+ }
+
+ /**
+ * Indicate that participant has completed processing of the last step.
+ *
+ * @param execCtx
+ */
+ public void doneStepping(final IExecutionDMContext execCtx, final ISteppingControlParticipant participant) {
+ if (DEBUG) System.out.println("[SteppingController] doneStepping participant=" + participant.getClass().getSimpleName()); //$NON-NLS-1$
+ List<ISteppingControlParticipant> participants = fStepInProgress.get(execCtx);
+ if (participants != null) {
+ participants.remove(participant);
+ if (participants.isEmpty()) {
+ doneStepping(execCtx);
+ }
+ } else {
+ for (IExecutionDMContext disabledCtx : fStepInProgress.keySet()) {
+ if (DMContexts.isAncestorOf(disabledCtx, execCtx)) {
+ participants = fStepInProgress.get(disabledCtx);
+ if (participants != null) {
+ participants.remove(participant);
+ if (participants.isEmpty()) {
+ doneStepping(disabledCtx);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public DsfSession getSession() {
+ return fSession;
+ }
+
+ /**
+ * All access to this class should happen through this executor.
+ * @return the executor this class is confined to
+ */
+ public DsfExecutor getExecutor() {
+ return getSession().getExecutor();
+ }
+
+ private DsfServicesTracker getServicesTracker() {
+ return fServicesTracker;
+ }
+
+ private IRunControl getRunControl() {
+ if (fRunControl == null) {
+ fRunControl = getServicesTracker().getService(IRunControl.class);
+ getSession().addServiceEventListener(this, null);
+ }
+ return fRunControl;
+ }
+
+ /**
+ * Checks whether a step command can be queued up for given context.
+ */
+ public void canEnqueueStep(IExecutionDMContext execCtx, StepType stepType, DataRequestMonitor<Boolean> rm) {
+ if (doCanEnqueueStep(execCtx, stepType)) {
+ rm.setData(true);
+ rm.done();
+ } else {
+ getRunControl().canStep(execCtx, stepType, rm);
+ }
+ }
+
+ private boolean doCanEnqueueStep(IExecutionDMContext execCtx, StepType stepType) {
+ return getRunControl().isStepping(execCtx) && !isSteppingTimedOut(execCtx);
+ }
+
+ /**
+ * Check whether the next step on the given execution context should be delayed
+ * based on the configured step delay.
+ *
+ * @param execCtx
+ * @return <code>true</code> if the step should be delayed
+ */
+ private boolean shouldDelayStep(IExecutionDMContext execCtx) {
+ final int stepDelay= getStepDelay(execCtx);
+ if (DEBUG) System.out.println("[SteppingController] shouldDelayStep delay=" + stepDelay); //$NON-NLS-1$
+ return stepDelay > 0;
+ }
+
+ /**
+ * Compute the delay in milliseconds before the next step for the given context may be executed.
+ *
+ * @param execCtx
+ * @return the number of milliseconds before the next possible step
+ */
+ private int getStepDelay(IExecutionDMContext execCtx) {
+ if (fMinStepInterval > 0) {
+ for (IExecutionDMContext lastStepCtx : fLastStepTimes.keySet()) {
+ if (execCtx.equals(lastStepCtx) || DMContexts.isAncestorOf(execCtx, lastStepCtx)) {
+ long now = System.currentTimeMillis();
+ int delay= (int) (fLastStepTimes.get(lastStepCtx) + fMinStepInterval - now);
+ return Math.max(delay, 0);
+ }
+ }
+ }
+ return 0;
+ }
+
+ private void updateLastStepTime(IExecutionDMContext execCtx) {
+ long now = System.currentTimeMillis();
+ fLastStepTimes.put(execCtx, now);
+ for (IExecutionDMContext lastStepCtx : fLastStepTimes.keySet()) {
+ if (!execCtx.equals(lastStepCtx) && DMContexts.isAncestorOf(execCtx, lastStepCtx)) {
+ fLastStepTimes.put(lastStepCtx, now);
+ }
+ }
+ }
+
+ private long getLastStepTime(IExecutionDMContext execCtx) {
+ if (fLastStepTimes.containsKey(execCtx)) {
+ return fLastStepTimes.get(execCtx);
+ }
+ for (IExecutionDMContext lastStepCtx : fLastStepTimes.keySet()) {
+ if (DMContexts.isAncestorOf(execCtx, lastStepCtx)) {
+ return fLastStepTimes.get(lastStepCtx);
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the number of step commands that are queued for given execution
+ * context.
+ */
+ public int getPendingStepCount(IExecutionDMContext execCtx) {
+ List<StepRequest> stepQueue = getStepQueue(execCtx);
+ if (stepQueue == null) return 0;
+ return stepQueue.size();
+ }
+
+ /**
+ * Adds a step command to the execution queue for given context.
+ * @param execCtx Execution context that should perform the step.
+ * @param stepType Type of step to execute.
+ */
+ public void enqueueStep(final IExecutionDMContext execCtx, final StepType stepType) {
+ if (DEBUG) System.out.println("[SteppingController] enqueueStep ctx=" + execCtx); //$NON-NLS-1$
+ if (!shouldDelayStep(execCtx) || doCanEnqueueStep(execCtx, stepType)) {
+ doEnqueueStep(execCtx, stepType);
+ processStepQueue(execCtx);
+ }
+ }
+
+ private void doStep(final IExecutionDMContext execCtx, final StepType stepType) {
+ if (DEBUG) System.out.println("[SteppingController] doStep ctx="+execCtx); //$NON-NLS-1$
+ disableStepping(execCtx);
+ updateLastStepTime(execCtx);
+
+ getRunControl().step(execCtx, stepType, new RequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleFailure() {
+ if (getStatus().getCode() == IDsfStatusConstants.INVALID_STATE) {
+ // Ignore errors. During fast stepping there can be expected race
+ // conditions leading to stepping errors.
+ return;
+ }
+ super.handleFailure();
+ }
+ });
+ }
+
+ /**
+ * Enqueue the given step for later execution.
+ *
+ * @param execCtx
+ * @param stepType
+ */
+ private void doEnqueueStep(final IExecutionDMContext execCtx, final StepType stepType) {
+ List<StepRequest> stepQueue = fStepQueues.get(execCtx);
+ if (stepQueue == null) {
+ stepQueue = new LinkedList<StepRequest>();
+ fStepQueues.put(execCtx, stepQueue);
+ }
+ if (stepQueue.size() < fQueueDepth) {
+ stepQueue.add(new StepRequest(execCtx, stepType));
+ }
+ }
+
+ /**
+ * Returns whether the step instruction for the given context has timed out.
+ */
+ public boolean isSteppingTimedOut(IExecutionDMContext execCtx) {
+ for (IExecutionDMContext timedOutCtx : fTimedOutFlags.keySet()) {
+ if (execCtx.equals(timedOutCtx) || DMContexts.isAncestorOf(execCtx, timedOutCtx)) {
+ return fTimedOutFlags.get(timedOutCtx);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Process next step on queue if any.
+ * @param execCtx
+ */
+ private void processStepQueue(final IExecutionDMContext execCtx) {
+ final List<StepRequest> queue = getStepQueue(execCtx);
+ if (queue != null) {
+ final int stepDelay = getStepDelay(execCtx);
+ if (stepDelay > 0) {
+ getExecutor().schedule(new DsfRunnable() {
+ public void run() {
+ processStepQueue(execCtx);
+ }
+ }, stepDelay, TimeUnit.MILLISECONDS);
+ return;
+ }
+ final StepRequest request = queue.get(0);
+ if (DEBUG) System.out.println("[SteppingController] processStepQueue request-in-progress="+request.inProgress); //$NON-NLS-1$
+ if (!request.inProgress) {
+ if (isSteppingDisabled(request.fContext)) {
+ return;
+ }
+ request.inProgress = true;
+ getRunControl().canStep(
+ request.fContext, request.fStepType,
+ new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess() && getData()) {
+ queue.remove(0);
+ if (queue.isEmpty()) fStepQueues.remove(request.fContext);
+ doStep(request.fContext, request.fStepType);
+ } else {
+ // For whatever reason we can't step anymore, so clear out
+ // the step queue.
+ fStepQueues.remove(request.fContext);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private List<StepRequest> getStepQueue(IExecutionDMContext execCtx) {
+ List<StepRequest> queue = fStepQueues.get(execCtx);
+ if (queue == null) {
+ for (IExecutionDMContext stepCtx : fStepQueues.keySet()) {
+ if (DMContexts.isAncestorOf(stepCtx, execCtx)) {
+ queue = fStepQueues.get(stepCtx);
+ break;
+ }
+ }
+ }
+ return queue;
+ }
+
+ /**
+ * Disable stepping for the given execution context.
+ *
+ * @param execCtx
+ */
+ private void disableStepping(IExecutionDMContext execCtx) {
+ fStepInProgress.put(execCtx, new ArrayList<ISteppingControlParticipant>(fParticipants));
+ }
+
+ /**
+ * Indicate that processing of the last step has completed and
+ * the next step can be issued.
+ *
+ * @param execCtx
+ */
+ private void doneStepping(final IExecutionDMContext execCtx) {
+ if (DEBUG) System.out.println("[SteppingController] doneStepping ctx=" + execCtx); //$NON-NLS-1$
+ enableStepping(execCtx);
+ processStepQueue(execCtx);
+ }
+
+ /**
+ * Enable stepping for the given execution context.
+ *
+ * @param execCtx
+ */
+ private void enableStepping(final IExecutionDMContext execCtx) {
+ fStepInProgress.remove(execCtx);
+ for (IExecutionDMContext disabledCtx : fStepInProgress.keySet()) {
+ if (DMContexts.isAncestorOf(disabledCtx, execCtx)) {
+ fStepInProgress.remove(disabledCtx);
+ }
+ }
+ }
+
+ private boolean isSteppingDisabled(IExecutionDMContext execCtx) {
+ boolean disabled= fStepInProgress.containsKey(execCtx);
+ if (!disabled) {
+ for (IExecutionDMContext disabledCtx : fStepInProgress.keySet()) {
+ if (DMContexts.isAncestorOf(execCtx, disabledCtx)) {
+ disabled = true;
+ break;
+ }
+ }
+ }
+ if (disabled) {
+ long now = System.currentTimeMillis();
+ long lastStepTime = getLastStepTime(execCtx);
+ if (now - lastStepTime > MAX_STEP_DELAY) {
+ if (DEBUG) System.out.println("[SteppingController] stepping control participant(s) timed out"); //$NON-NLS-1$
+ enableStepping(execCtx);
+ disabled = false;
+ }
+ }
+ return disabled;
+ }
+
+ protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (IDsfDebugUIConstants.PREF_MIN_STEP_INTERVAL.equals(property)) {
+ setMinimumStepInterval(store.getInt(property));
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final ISuspendedDMEvent e) {
+ // Take care of the stepping time out
+ fTimedOutFlags.remove(e.getDMContext());
+ ScheduledFuture<?> future = fTimedOutFutures.remove(e.getDMContext());
+ if (future != null) future.cancel(false);
+
+ // Check if there's a step pending, if so execute it
+ processStepQueue(e.getDMContext());
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final IResumedDMEvent e) {
+ if (e.getReason().equals(StateChangeReason.STEP)) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.FALSE);
+ // We shouldn't have a stepping timeout running unless we get two
+ // stepping events in a row without a suspended, which would be a
+ // protocol error.
+ assert !fTimedOutFutures.containsKey(e.getDMContext());
+ fTimedOutFutures.put(
+ e.getDMContext(),
+ getExecutor().schedule(
+ new DsfRunnable() { public void run() {
+ fTimedOutFutures.remove(e.getDMContext());
+
+ if (getSession().isActive()) {
+ // Issue the stepping time-out event.
+ getSession().dispatchEvent(
+ new SteppingTimedOutEvent(e.getDMContext()),
+ null);
+ }
+ }},
+ STEPPING_TIMEOUT, TimeUnit.MILLISECONDS)
+ );
+
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(SteppingTimedOutEvent e) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.TRUE);
+ enableStepping(e.getDMContext());
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/AbstractVMProviderActionDelegate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/AbstractVMProviderActionDelegate.java
new file mode 100644
index 00000000000..8bbd0226f4d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/AbstractVMProviderActionDelegate.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Ted R Williams (Wind River Systems, Inc.) - initial implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.ui.AbstractDebugView;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.debug.ui.contexts.IDebugContextListener;
+import org.eclipse.debug.ui.contexts.IDebugContextService;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+abstract public class AbstractVMProviderActionDelegate implements IViewActionDelegate, IDebugContextListener, IActionDelegate2 {
+
+ private IViewPart fView = null;
+ private IAction fAction = null;
+ private ISelection fDebugContext;
+
+ public void init(IViewPart view) {
+ fView = view;
+
+ // Get the current selection from the DebugView so we can determine if we want this menu action to be live or not.
+ IDebugContextService debugContextService = DebugUITools.getDebugContextManager().getContextService(view.getSite().getWorkbenchWindow());
+ debugContextService.addPostDebugContextListener(this);
+ fDebugContext = debugContextService.getActiveContext();
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ if (fAction != action) {
+ fAction = action;
+ }
+ }
+
+ public void runWithEvent(IAction action, Event event) {
+ run(action);
+ }
+
+ public void init(IAction action) {
+ fAction = action;
+ }
+
+ public void dispose() {
+ DebugUITools.getDebugContextManager().getContextService(getView().getSite().getWorkbenchWindow()).removePostDebugContextListener(this);
+ }
+
+ public void debugContextChanged(DebugContextEvent event) {
+ fDebugContext = event.getContext();
+ }
+
+ protected IViewPart getView() { return fView; }
+
+ protected IAction getAction() { return fAction; }
+
+ protected Object getViewerInput() {
+ if (fDebugContext instanceof IStructuredSelection) {
+ return ((IStructuredSelection)fDebugContext).getFirstElement();
+ }
+ return null;
+ }
+
+ protected IVMProvider getVMProvider() {
+ Object viewerInput = getViewerInput();
+ IPresentationContext presentationContext = getPresentationContext();
+
+ if (viewerInput instanceof IAdaptable && presentationContext != null) {
+ IVMAdapter adapter = (IVMAdapter) ((IAdaptable)viewerInput).getAdapter(IVMAdapter.class);
+
+ if ( adapter != null ) {
+ return adapter.getVMProvider(presentationContext);
+ }
+ }
+
+ return null;
+ }
+
+ protected IPresentationContext getPresentationContext() {
+ if (fView instanceof AbstractDebugView &&
+ ((AbstractDebugView) fView).getViewer() instanceof TreeModelViewer)
+ {
+ return ((TreeModelViewer) ((AbstractDebugView) fView).getViewer()).getPresentationContext();
+ }
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/DefaultRefreshAllTarget.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/DefaultRefreshAllTarget.java
new file mode 100644
index 00000000000..95bae0930de
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/DefaultRefreshAllTarget.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMAdapterExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ICachingVMProvider;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+/**
+ * The default implementation of the refresh all debug target which
+ * calls the active VM providers, to ask them to refresh.
+ *
+ * @since 1.1
+ */
+public class DefaultRefreshAllTarget implements IRefreshAllTarget {
+
+ public void refresh(ISelection debugContext) throws CoreException {
+ IVMAdapterExtension adapter = getActiveVMAdapter( debugContext );
+
+ if (adapter != null) {
+ for (IVMProvider provider : adapter.getActiveProviders()) {
+ if (provider instanceof ICachingVMProvider) {
+ ((ICachingVMProvider)provider).refresh();
+ }
+ }
+ }
+ }
+
+ protected IVMAdapterExtension getActiveVMAdapter(ISelection debugContext) {
+
+ if (debugContext instanceof IStructuredSelection) {
+ Object activeElement = ((IStructuredSelection)debugContext).getFirstElement();
+ if (activeElement instanceof IAdaptable) {
+ return (IVMAdapterExtension)((IAdaptable)activeElement).getAdapter(IVMAdapterExtension.class);
+ }
+ }
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/IRefreshAllTarget.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/IRefreshAllTarget.java
new file mode 100644
index 00000000000..cf1f50ec876
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/IRefreshAllTarget.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.actions;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.viewers.ISelection;
+
+/**
+ * A retargetable action target which allows a debugger to refresh all of its
+ * active views with fresh data from the debug target.
+ *
+ * @since 1.1
+ */
+public interface IRefreshAllTarget {
+
+ /**
+ * Refreshes the debugger data of the given debug context.
+ * @param debugContext The active window debug context.
+ *
+ * @throws CoreException
+ */
+ public void refresh(ISelection debugContext) throws CoreException;
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/VMHandlerUtils.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/VMHandlerUtils.java
new file mode 100644
index 00000000000..594c89290ce
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/actions/VMHandlerUtils.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.actions;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.debug.ui.contexts.IDebugContextService;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.IPartService;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.handlers.HandlerUtil;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Static utility methods for use with View Model related
+ * commands and handlers.
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class VMHandlerUtils {
+
+ /**
+ * Retrieves the active VM provider based on the currently active
+ * selection and part.
+ * @param serviceLocator Service locator for access to active selection
+ * and part.
+ *
+ * @return The active VM provder.
+ */
+ static public IVMProvider getActiveVMProvider(IServiceLocator serviceLocator) {
+ ISelection selection = null;
+
+ ISelectionService selectionService =
+ (ISelectionService)serviceLocator.getService(ISelectionService.class);
+ if (selectionService != null) {
+ selection = selectionService.getSelection();
+ }
+
+ if (selection != null && !selection.isEmpty()) {
+ return getVMProviderForSelection(selection);
+ }
+ else {
+ IWorkbenchPart part = null;
+ IPartService partService = (IPartService)serviceLocator.getService(IPartService.class);
+ if (partService != null) {
+ part = partService.getActivePart();
+ }
+ return getVMProviderForPart(part);
+ }
+ }
+
+ /**
+ * Retrieves the active VM provider based on the given execution event.
+ * @param event The execution event which is usually given as an argument
+ * to the command handler execution call.
+ *
+ * @return The active VM provder.
+ */
+ static public IVMProvider getActiveVMProvider(ExecutionEvent event) {
+ ISelection selection = HandlerUtil.getCurrentSelection(event);
+ if (selection != null && !selection.isEmpty()) {
+ return getVMProviderForSelection(selection);
+ }
+ else {
+ IWorkbenchPart part = HandlerUtil.getActivePart(event);
+ return getVMProviderForPart(part);
+ }
+ }
+
+ public static IVMProvider getVMProviderForPart(IWorkbenchPart part) {
+ IDebugContextService contextService =
+ DebugUITools.getDebugContextManager().getContextService(part.getSite().getWorkbenchWindow());
+
+ ISelection debugContext = contextService.getActiveContext(getPartId(part));
+ if (debugContext == null) {
+ debugContext = contextService.getActiveContext();
+ }
+
+ Object input = null;
+ if (debugContext instanceof IStructuredSelection) {
+ input = ((IStructuredSelection)debugContext).getFirstElement();
+ }
+
+ if (part instanceof IDebugView) {
+ Viewer viewer = ((IDebugView)part).getViewer();
+ if (input instanceof IAdaptable && viewer instanceof TreeModelViewer) {
+ IPresentationContext presContext = ((TreeModelViewer)viewer).getPresentationContext();
+ IVMAdapter vmAdapter = (IVMAdapter)((IAdaptable)input).getAdapter(IVMAdapter.class);
+ if (vmAdapter != null) {
+ return vmAdapter.getVMProvider(presContext);
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String getPartId(IWorkbenchPart part) {
+ if (part instanceof IViewPart) {
+ IViewSite site = (IViewSite)part.getSite();
+ return site.getId() + (site.getSecondaryId() != null ? (":" + site.getSecondaryId()) : ""); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ return part.getSite().getId();
+ }
+ }
+
+ public static IVMProvider getVMProviderForSelection(ISelection selection) {
+ if (selection instanceof IStructuredSelection) {
+ Object element = ((IStructuredSelection)selection).getFirstElement();
+ if (element instanceof IVMContext) {
+ return ((IVMContext)element).getVMNode().getVMProvider();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/AbstractExpressionVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/AbstractExpressionVMNode.java
new file mode 100644
index 00000000000..6e2a34f3e4c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/AbstractExpressionVMNode.java
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+
+/**
+ * Base class for VM Nodes which can be used in the expressions view.
+ * <p>
+ * This base class uses the methods {@link #canParseExpression(IExpression)} and
+ * {@link #update(IChildrenUpdate[])} to implement the
+ * {@link IExpressionVMNode#update(IExpressionUpdate)}
+ * method. Two additional abstract protected methods need to be implemented
+ * by the sub-class as well.
+ * </p>
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractExpressionVMNode extends AbstractDMVMNode
+ implements IExpressionVMNode
+{
+ public AbstractExpressionVMNode(AbstractDMVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
+ super(provider, session, dmcClassType);
+ }
+
+ public void update(final IExpressionUpdate update) {
+ if (!canParseExpression(update.getExpression())) {
+ // This method should not be called if canParseExpression() returns false.
+ // Return an internal error status.
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Cannot parse expression", null)); //$NON-NLS-1$
+ update.done();
+ return;
+ }
+
+ // Retrieve the list of all elements from the sub-class. Then compare
+ // each returned element to the expression in the update, using
+ // testElementForExpression(). The element that matches the expression
+ // is returned to the client.
+ // If no matching element is found, the createInvalidExpressionVMContext()
+ // method is called to a special context.
+ update(new IChildrenUpdate[] { new VMChildrenUpdate(
+ update, -1, -1,
+ new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ if (getData().size() == 0) {
+ update.setExpressionElement(createInvalidExpressionVMContext(update.getExpression()));
+ update.done();
+ } else {
+ final List<Object> elements = getData();
+
+ final MultiRequestMonitor<DataRequestMonitor<Boolean>> multiRm = new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ boolean foundMatchingContext = false;
+ for (int i = 0; i < getRequestMonitors().size(); i++) {
+ if (getRequestMonitors().get(i).getData()) {
+ Object element = elements.get(i);
+ associateExpression(element, update.getExpression());
+ update.setExpressionElement(element);
+ foundMatchingContext = true;
+ break;
+ }
+ }
+ if (!foundMatchingContext) {
+ update.setExpressionElement(createInvalidExpressionVMContext(update.getExpression()));
+ }
+ } else {
+ update.setStatus(getStatus());
+ }
+ update.done();
+ }
+ };
+
+ for (Object element : elements) {
+ testElementForExpression(
+ element, update.getExpression(),
+ multiRm.add(
+ new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ multiRm.requestMonitorDone(this);
+ }
+ }));
+ }
+ }
+ }
+
+ @Override
+ protected void handleFailure() {
+ update.setStatus(getStatus());
+ update.done();
+ }
+ })}
+ );
+
+ }
+
+
+ /**
+ * Tests whether the given element matches the given expression.
+ *
+ * @param element Element to test against the given expression.
+ * @param expression Expression to use to check if the element is matching.
+ * @param rm The request monitor for the result.
+ */
+ @ConfinedToDsfExecutor("#getSession#getExecutor")
+ protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
+ rm.setData(false);
+ rm.done();
+ }
+
+ /**
+ * Sets the given expression as the expression belonging to the given
+ * element.
+ * <p>
+ * This base class creates VM context elements using the extending class's
+ * {@link #update(IChildrenUpdate[])} method. The element matching the
+ * expression is found using {@link #testElementForExpression(Object, IExpression, DataRequestMonitor)}.
+ * Once the matching element is found it needs to be linked to the expression
+ * so that it can be distinguished from other contexts created for identical
+ * but distinct expressions. This method accomplishes this task. Elements
+ * which are associated with expressions should use the expression object
+ * for implementation of {@link #equals(Object)} and {@link #hashCode()}
+ * methods.
+ * </p>
+ *
+ * @param element
+ * @param expression
+ */
+ protected void associateExpression(Object element, IExpression expression) {
+ }
+
+ /**
+ * Create a place holder for an invalid expression. If for a given expression,
+ * this VM node returns true from {@link #canParseExpression(IExpression)}, which
+ * indicates that the expression matches the node's expected format, but the node
+ * then is not able to find the element represented by the expression, then an
+ * "invalid" expression context needs to be created.
+ * <p>
+ * This method can be overriden to provide a node-specific invalid expression
+ * context.
+ * </p>
+ *
+ * @param expression Expression to create the context for.
+ * @return Returns a VM context object representing an invalid expression with
+ *
+ * @since 1.1
+ */
+ protected IVMContext createInvalidExpressionVMContext(IExpression expression) {
+ return new InvalidExpressionVMContext(this, expression);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionColumnPresentation.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionColumnPresentation.java
new file mode 100644
index 00000000000..8c5b437d712
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionColumnPresentation.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class ExpressionColumnPresentation implements IColumnPresentation {
+
+ public static final String ID = DsfUIPlugin.PLUGIN_ID + ".EXPRESSION_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+
+ public void init(IPresentationContext context) {
+ }
+
+ public void dispose() {
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getAvailableColumns()
+ public String[] getAvailableColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__EXPRESSION, IDebugVMConstants.COLUMN_ID__NAME, IDebugVMConstants.COLUMN_ID__TYPE, IDebugVMConstants.COLUMN_ID__VALUE, IDebugVMConstants.COLUMN_ID__DESCRIPTION, IDebugVMConstants.COLUMN_ID__ADDRESS };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getHeader(java.lang.String)
+ public String getHeader(String id) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_expression;
+ } else if (IDebugVMConstants.COLUMN_ID__NAME.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_name;
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_type;
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_value;
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_description;
+ } else if (IDebugVMConstants.COLUMN_ID__ADDRESS.equals(id)) {
+ return MessagesForExpressionVM.ExpressionColumnPresentation_address;
+ }
+ return null;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getId()
+ public String getId() {
+ return ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getInitialColumns()
+ public String[] getInitialColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__EXPRESSION, IDebugVMConstants.COLUMN_ID__TYPE, IDebugVMConstants.COLUMN_ID__VALUE };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#isOptional()
+ public boolean isOptional() {
+ return true;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionManagerVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionManagerVMNode.java
new file mode 100644
index 00000000000..ae679c01bbb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionManagerVMNode.java
@@ -0,0 +1,307 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerCountingRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IExpressionManager;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * This is the top-level view model node in the expressions view. Its job is to:
+ * <li>
+ * <ol> retrieve the {@link IExpression} objects from the global {@link IExpressionManager},</ol>
+ * <ol> retrieve the expression string from the <code>IExpression</code> object,</ol>
+ * <ol> then to call the configured expression nodes to parse the expression string.</ol>
+ * </li>
+ * <p>
+ * This node is not intended to have any standard child nodes, therefore
+ * the implementation of {@link #setChildNodes(IVMNode[])} throws an exception.
+ * Instead users should call {@link #setExpressionNodes(IExpressionVMNode[])}
+ * to configure the nodes that this node will delegate to when processing expressions.
+ * </p>
+ */
+@SuppressWarnings("restriction")
+public class ExpressionManagerVMNode extends AbstractVMNode
+ implements IElementLabelProvider, IElementEditor
+{
+ /**
+ * VMC for a new expression object to be added. When user clicks on this node to
+ * edit it, he will create a new expression.
+ */
+ class NewExpressionVMC extends AbstractVMContext {
+ public NewExpressionVMC() {
+ super(ExpressionManagerVMNode.this);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ return super.getAdapter(adapter);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof NewExpressionVMC;
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().hashCode();
+ }
+ }
+
+ /** Local reference to the global expression manager */
+ private IExpressionManager fManager = DebugPlugin.getDefault().getExpressionManager();
+
+ /** Cached reference to a cell modifier for editing expression strings of invalid expressions */
+ private WatchExpressionCellModifier fWatchExpressionCellModifier = new WatchExpressionCellModifier();
+
+ public ExpressionManagerVMNode(ExpressionVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public String toString() {
+ return "ExpressionManagerVMNode"; //$NON-NLS-1$
+ }
+
+ private ExpressionVMProvider getExpressionVMProvider() {
+ return (ExpressionVMProvider)getVMProvider();
+ }
+
+ public void update(IHasChildrenUpdate[] updates) {
+ // Test availability of children based on whether there are any expressions
+ // in the manager. We assume that the getExpressions() will just read
+ // local state data, so we don't bother using a job to perform this
+ // operation.
+ for (int i = 0; i < updates.length; i++) {
+ updates[i].setHasChilren(fManager.getExpressions().length != 0);
+ updates[i].done();
+ }
+ }
+
+ public void update(IChildrenCountUpdate[] updates) {
+ for (IChildrenCountUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+
+ // We assume that the getExpressions() will just read local state data,
+ // so we don't bother using a job to perform this operation.
+ update.setChildCount(fManager.getExpressions().length + 1);
+ update.done();
+ }
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ for (IChildrenUpdate update : updates) {
+ doUpdateChildren(update);
+ }
+ }
+
+ public void doUpdateChildren(final IChildrenUpdate update) {
+ final IExpression[] expressions = fManager.getExpressions();
+
+ // For each (expression) element in update, find the layout node that can
+ // parse it. And for each expression that has a corresponding layout node,
+ // call IExpressionLayoutNode#getElementForExpression to generate a VMC.
+ // Since the last is an async call, we need to create a multi-RM to wait
+ // for all the calls to complete.
+ final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getVMProvider().getExecutor(), update);
+ int multiRmCount = 0;
+
+ int lowOffset= update.getOffset();
+ if (lowOffset < 0) {
+ lowOffset = 0;
+ }
+ int length= update.getLength();
+ if (length <= 0) {
+ length = expressions.length;
+ }
+ final int highOffset= lowOffset + length;
+ for (int i = lowOffset; i < highOffset && i < expressions.length + 1; i++) {
+ if (i < expressions.length) {
+ multiRmCount++;
+ final int childIndex = i;
+ final IExpression expression = expressions[i];
+ // getElementForExpression() accepts a IElementsUpdate as an argument.
+ // Construct an instance of VMElementsUpdate which will call a
+ // the request monitor when it is finished. The request monitor
+ // will in turn set the element in the update argument in this method.
+ ((ExpressionVMProvider)getVMProvider()).update(
+ new VMExpressionUpdate(
+ update, expression,
+ new DataRequestMonitor<Object>(getVMProvider().getExecutor(), multiRm) {
+ @Override
+ protected void handleSuccess() {
+ update.setChild(getData(), childIndex);
+ multiRm.done();
+ }
+
+ @Override
+ protected void handleError() {
+ update.setChild(new InvalidExpressionVMContext(ExpressionManagerVMNode.this, expression), childIndex);
+ multiRm.done();
+ }
+ })
+ );
+ } else {
+ // Last element in the list of expressions is the "add new expression"
+ // dummy entry.
+ update.setChild(new NewExpressionVMC(), i);
+ }
+ }
+
+ // If no expressions were parsed, we're finished.
+ // Set the count to the counting RM.
+ multiRm.setDoneCount(multiRmCount);
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ // The label update handler only handles labels for the invalid expression VMCs.
+ // The expression layout nodes are responsible for supplying label providers
+ // for their VMCs.
+ for (ILabelUpdate update : updates) {
+ if (update.getElement() instanceof NewExpressionVMC) {
+ updateNewExpressionVMCLabel(update, (NewExpressionVMC) update.getElement());
+ } else {
+ update.done();
+ }
+ }
+ }
+
+ /**
+ * Updates the label for the NewExpressionVMC.
+ */
+ private void updateNewExpressionVMCLabel(ILabelUpdate update, NewExpressionVMC vmc) {
+ String[] columnIds = update.getColumnIds() != null ?
+ update.getColumnIds() : new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int i = 0; i < columnIds.length; i++) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnIds[i])) {
+ update.setLabel(MessagesForExpressionVM.ExpressionManagerLayoutNode__newExpression_label, i);
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], i);
+ } else {
+ update.setLabel("", i); //$NON-NLS-1$
+ }
+ }
+
+
+ update.done();
+ }
+
+ public int getDeltaFlags(Object event) {
+ int retVal = 0;
+
+ // Add a flag if the list of expressions in the global expression manager has changed.
+ if (event instanceof ExpressionsChangedEvent) {
+ retVal |= IModelDelta.ADDED | IModelDelta.REMOVED | IModelDelta.INSERTED | IModelDelta.CONTENT ;
+ }
+
+ for (IExpression expression : fManager.getExpressions()) {
+ retVal |= getExpressionVMProvider().getDeltaFlagsForExpression(expression, event);
+ }
+
+ return retVal;
+ }
+
+ public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ if (event instanceof ExpressionsChangedEvent) {
+ buildDeltaForExpressionsChangedEvent((ExpressionsChangedEvent)event, parentDelta, nodeOffset, requestMonitor);
+ } else {
+
+ // For each expression, find its corresponding node and ask that
+ // layout node for its delta flags for given event. If there are delta flags to be
+ // generated, call the asynchronous method to do so.
+ CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor);
+
+ int buildDeltaForExpressionCallCount = 0;
+
+ IExpression[] expressions = fManager.getExpressions();
+ for (int i = 0; i < expressions.length; i++ ) {
+ int flags = getExpressionVMProvider().getDeltaFlagsForExpression(expressions[i], event);
+ // If the given expression has no delta flags, skip it.
+ if (flags == IModelDelta.NO_CHANGE) continue;
+
+ int elementOffset = nodeOffset >= 0 ? nodeOffset + i : -1;
+ getExpressionVMProvider().buildDeltaForExpression(
+ expressions[i], elementOffset, event, parentDelta, getTreePathFromDelta(parentDelta),
+ new RequestMonitor(getExecutor(), multiRm));
+ buildDeltaForExpressionCallCount++;
+ }
+
+ multiRm.setDoneCount(buildDeltaForExpressionCallCount);
+ }
+ }
+
+ private void buildDeltaForExpressionsChangedEvent(ExpressionsChangedEvent event, VMDelta parentDelta,
+ int nodeOffset, RequestMonitor requestMonitor)
+ {
+ CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), requestMonitor);
+ for (int i = 0; i < event.getExpressions().length; i++) {
+ int expIndex = event.getIndex() != -1
+ ? nodeOffset + event.getIndex() + i
+ : -1;
+ getExpressionVMProvider().buildDeltaForExpression(
+ event.getExpressions()[i], expIndex, event, parentDelta, getTreePathFromDelta(parentDelta),
+ new RequestMonitor(getExecutor(), multiRm));
+ }
+ multiRm.setDoneCount(event.getExpressions().length);
+ }
+
+ private TreePath getTreePathFromDelta(IModelDelta delta) {
+ List<Object> elementList = new LinkedList<Object>();
+ IModelDelta listDelta = delta;
+ elementList.add(0, listDelta.getElement());
+ while (listDelta.getParentDelta() != null) {
+ elementList.add(0, listDelta.getElement());
+ listDelta = listDelta.getParentDelta();
+ }
+ return new TreePath(elementList.toArray());
+ }
+
+
+ public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ return null;
+ }
+
+ public ICellModifier getCellModifier(IPresentationContext context, Object element) {
+ return fWatchExpressionCellModifier;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java
new file mode 100644
index 00000000000..3f608a9dc0a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProvider.java
@@ -0,0 +1,379 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.DsfDebugUITools;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterBitFieldVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterGroupVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.SyncRegisterDataAccess;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.SyncVariableDataAccess;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMNode;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.DefaultVMContentProviderStrategy;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.core.IExpressionsListener2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * The expression provider is used to populate the contents of the expressions
+ * view. The node hierarchy in this view is a little different than in a typical
+ * provider: the expression manager node should be registered as the single child
+ * of the root node and no nodes should be registered as children of expression node.
+ * Instead the top level expression nodes should be registered with a call to
+ * {@link #setExpressionNodes(IExpressionVMNode[])}. And each expression node can
+ * have its own sub-hierarchy of elements as needed. However all nodes configured
+ * with this provider (with the exception of the root and the expression manager)
+ * should implement {@link IExpressionVMNode}.
+ */
+@SuppressWarnings("restriction")
+public class ExpressionVMProvider extends AbstractDMVMProvider
+ implements IExpressionsListener2
+{
+ private IExpressionVMNode[] fExpressionNodes;
+
+ private IPropertyChangeListener fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (property.equals(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE)) {
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ setDelayEventHandleForViewUpdate(store.getBoolean(property));
+ }
+ }
+ };
+
+ private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ handleEvent(event);
+ }
+ };
+
+ public ExpressionVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
+ super(adapter, context, session);
+
+ context.addPropertyChangeListener(fPresentationContextListener);
+
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ store.addPropertyChangeListener(fPreferencesListener);
+ setDelayEventHandleForViewUpdate(store.getBoolean(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE));
+
+ // The VM provider has to handle all events that result in model deltas.
+ // Add the provider as listener to expression changes events.
+ DebugPlugin.getDefault().getExpressionManager().addExpressionListener(this);
+
+ configureLayout();
+ }
+
+ @Override
+ protected DefaultVMContentProviderStrategy createContentStrategy() {
+ return new ExpressionVMProviderContentStragegy(this);
+ }
+
+ @Override
+ protected IVMModelProxy createModelProxyStrategy(Object rootElement) {
+ return new ExpressionVMProviderModelProxyStrategy(this, rootElement);
+ }
+
+ /**
+ * Updates the given expression element. This method is used by the
+ * expression manager node to obtain a view model element based on the
+ * {@link IExpression} retrieved from the expression manager. The
+ * implementation of this method (which is in the content strategy),
+ * checks the configured expression nodes to see which one can
+ * process the given expression, when it finds it it delegates
+ * to that expression node's {@link IExpressionVMNode#update(IExpressionUpdate)}
+ * method.
+ * @param update Expression update to process.
+ */
+ public void update(IExpressionUpdate update) {
+ ((ExpressionVMProviderContentStragegy)getContentStrategy()).update(update);
+ }
+
+ /**
+ * Retrieves the delta flags that can be generated for the given expression
+ * and the given event. This method is used by the
+ * expression manager node to obtain the delta flags based on the
+ * {@link IExpression} retrieved from the expression manager. The
+ * implementation of this method (which is in the model proxy strategy),
+ * checks the configured expression nodes to see which one can
+ * process the given expression, when it finds it it delegates
+ * to that expression node's {@link IExpressionVMNode#getDeltaFlagsForExpression(IExpression, Object)}
+ * method.
+ */
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ // Workaround: find the first active proxy and use it.
+ if (!getActiveModelProxies().isEmpty()) {
+ return ((ExpressionVMProviderModelProxyStrategy)getActiveModelProxies().get(0)).getDeltaFlagsForExpression(expression, event);
+ }
+ return 0;
+ }
+
+ /**
+ * Builds the model delta based on the given expression
+ * and the given event. This method is used by the
+ * expression manager to build the delta based on the
+ * {@link IExpression} retrieved from the expression manager. The
+ * implementation of this method (which is in the model proxy strategy),
+ * checks the configured expression nodes to see which one can
+ * process the given expression, when it finds it it delegates
+ * to that expression node's {@link IExpressionVMNode#buildDeltaForExpression(IExpression, int, Object, ModelDelta, TreePath, RequestMonitor)}
+ * and {@link IExpressionVMNode#buildDeltaForExpressionElement(Object, int, Object, ModelDelta, RequestMonitor)
+ * methods.
+ */
+ public void buildDeltaForExpression(final IExpression expression, final int expressionElementIdx, final Object event,
+ final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
+ {
+ // Workaround: find the first active proxy and use it.
+ if (!getActiveModelProxies().isEmpty()) {
+ ((ExpressionVMProviderModelProxyStrategy)getActiveModelProxies().get(0)).buildDeltaForExpression(
+ expression, expressionElementIdx, event, parentDelta, path, rm);
+ } else {
+ rm.done();
+ }
+ }
+
+ /**
+ * Configures the given nodes as the top-level expression nodes.
+ */
+ protected void setExpressionNodes(IExpressionVMNode[] nodes) {
+ fExpressionNodes = nodes;
+
+ // Call the base class to make sure that the nodes are also
+ // returned by the getAllNodes method.
+ for (IExpressionVMNode node : nodes) {
+ addNode(node);
+ }
+ }
+
+ /**
+ * Returns the list of configured top-level expression nodes.
+ * @return
+ */
+ public IExpressionVMNode[] getExpressionNodes() {
+ return fExpressionNodes;
+ }
+
+ /**
+ * Configures the nodes of this provider. This method may be over-ridden by
+ * sub classes to create an alternate configuration in this provider.
+ */
+ protected void configureLayout() {
+
+ IFormattedValuePreferenceStore prefStore = FormattedValuePreferenceStore.getDefault();
+
+ /*
+ * Allocate the synchronous data providers.
+ */
+ SyncRegisterDataAccess syncRegDataAccess = new SyncRegisterDataAccess(getSession());
+ SyncVariableDataAccess syncvarDataAccess = new SyncVariableDataAccess(getSession()) ;
+
+ /*
+ * Create the top level node which provides the anchor starting point.
+ */
+ IRootVMNode rootNode = new RootDMVMNode(this);
+
+ /*
+ * Now the Over-arching management node.
+ */
+ ExpressionManagerVMNode expressionManagerNode = new ExpressionManagerVMNode(this);
+ addChildNodes(rootNode, new IVMNode[] {expressionManagerNode});
+
+ /*
+ * The expression view wants to support fully all of the components of the register view.
+ */
+ IExpressionVMNode registerGroupNode = new RegisterGroupVMNode(this, getSession(), syncRegDataAccess);
+
+ IExpressionVMNode registerNode = new RegisterVMNode(prefStore, this, getSession(), syncRegDataAccess);
+ addChildNodes(registerGroupNode, new IExpressionVMNode[] {registerNode});
+
+ /*
+ * Create the next level which is the bit-field level.
+ */
+ IVMNode bitFieldNode = new RegisterBitFieldVMNode(prefStore, this, getSession(), syncRegDataAccess);
+ addChildNodes(registerNode, new IVMNode[] { bitFieldNode });
+
+ /*
+ * Create the support for the SubExpressions. Anything which is brought into the expressions
+ * view comes in as a fully qualified expression so we go directly to the SubExpression layout
+ * node.
+ */
+ IExpressionVMNode variableNode = new VariableVMNode(prefStore, this, getSession(), syncvarDataAccess);
+ addChildNodes(variableNode, new IExpressionVMNode[] {variableNode});
+
+ /*
+ * Tell the expression node which sub-nodes it will directly support. It is very important
+ * that the variables node be the last in this chain. The model assumes that there is some
+ * form of metalanguage expression syntax which each of the nodes evaluates and decides if
+ * they are dealing with it or not. The variables node assumes that the expression is fully
+ * qualified and there is no analysis or subdivision of the expression it will parse. So it
+ * it currently the case that the location of the nodes within the array being passed in is
+ * the order of search/evaluation. Thus variables wants to be last. Otherwise it would just
+ * assume what it was passed was for it and the real node which wants to handle it would be
+ * left out in the cold.
+ */
+ setExpressionNodes(new IExpressionVMNode[] {registerGroupNode, variableNode});
+
+ /*
+ * Let the work know which is the top level node.
+ */
+ setRootNode(rootNode);
+ }
+
+ /**
+ * Finds the expression node which can parse the given expression. This
+ * method is used by the expression content and model proxy strategies.
+ *
+ * @param parentNode The parent of the nodes to search. If <code>null</code>,
+ * then the top level expressions will be searched.
+ * @param expression The expression object.
+ * @return The matching expression node.
+ */
+ public IExpressionVMNode findNodeToParseExpression(IExpressionVMNode parentNode, IExpression expression) {
+ IVMNode[] childNOdes;
+ if (parentNode == null) {
+ childNOdes = getExpressionNodes();
+ } else {
+ childNOdes = getChildVMNodes(parentNode);
+ }
+ for (IVMNode childNode : childNOdes) {
+ if (childNode instanceof IExpressionVMNode) {
+ IExpressionVMNode childExpressionNode = (IExpressionVMNode)childNode;
+ if (childExpressionNode.canParseExpression(expression)) {
+ return childExpressionNode;
+ } else if (!childExpressionNode.equals(parentNode)) {
+ // The above check is to make sure that child isn't the same as
+ // parent to avoid recursive loops.
+ IExpressionVMNode matchingNode =
+ findNodeToParseExpression(childExpressionNode, expression);
+ if (matchingNode != null) {
+ return matchingNode;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ @Override
+ public void dispose() {
+ DebugPlugin.getDefault().getExpressionManager().removeExpressionListener(this);
+ DsfDebugUITools.getPreferenceStore().removePropertyChangeListener(fPreferencesListener);
+ getPresentationContext().removePropertyChangeListener(fPresentationContextListener);
+ super.dispose();
+ }
+
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return new ExpressionColumnPresentation();
+ }
+
+ @Override
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return ExpressionColumnPresentation.ID;
+ }
+
+ @Override
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ExpressionsManualUpdatePolicy(),
+ new ExpressionsBreakpointHitUpdatePolicy() };
+ }
+
+ public void expressionsAdded(IExpression[] expressions) {
+ expressionsListChanged(ExpressionsChangedEvent.Type.ADDED, expressions, -1);
+ }
+
+ public void expressionsRemoved(IExpression[] expressions) {
+ expressionsListChanged(ExpressionsChangedEvent.Type.REMOVED, expressions, -1);
+ }
+
+ public void expressionsInserted(IExpression[] expressions, int index) {
+ expressionsListChanged(ExpressionsChangedEvent.Type.INSERTED, expressions, index);
+ }
+
+ public void expressionsMoved(IExpression[] expressions, int index) {
+ expressionsListChanged(ExpressionsChangedEvent.Type.MOVED, expressions, index);
+ }
+
+ public void expressionsChanged(IExpression[] expressions) {
+ expressionsListChanged(ExpressionsChangedEvent.Type.CHANGED, expressions, -1);
+ }
+
+ private void expressionsListChanged(ExpressionsChangedEvent.Type type, IExpression[] expressions, int index) {
+ Set<Object> rootElements = new HashSet<Object>();
+ for (IVMModelProxy proxy : getActiveModelProxies()) {
+ rootElements.add(proxy.getRootElement());
+ }
+ handleEvent(new ExpressionsChangedEvent(type, rootElements, expressions, index));
+ }
+
+ @Override
+ protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+ // To optimize the performance of the view when stepping rapidly, skip all
+ // other events when a suspended event is received, including older suspended
+ // events.
+ return newEvent instanceof ISuspendedDMEvent;
+ }
+
+ @Override
+ public void refresh() {
+ super.refresh();
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), getSession().getId());
+ IExpressions expressionsService = tracker.getService(IExpressions.class);
+ if (expressionsService instanceof ICachingService) {
+ ((ICachingService)expressionsService).flushCache(null);
+ }
+ IRegisters registerService = tracker.getService(IRegisters.class);
+ if (registerService instanceof ICachingService) {
+ ((ICachingService)registerService).flushCache(null);
+ }
+ tracker.dispose();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session disposed, ignore.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderContentStragegy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderContentStragegy.java
new file mode 100644
index 00000000000..55535acc67c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderContentStragegy.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.DefaultVMContentProviderStrategy;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * The IElementContentProvider implementation to be used with an expression
+ * view model provider.
+ *
+ * @see ExpressionVMProvider
+ */
+@SuppressWarnings("restriction")
+public class ExpressionVMProviderContentStragegy extends DefaultVMContentProviderStrategy {
+ public ExpressionVMProviderContentStragegy(ExpressionVMProvider provider) {
+ super(provider);
+ }
+
+ private ExpressionVMProvider getExpressionVMProvider() {
+ return (ExpressionVMProvider)getVMProvider();
+ }
+
+ public void update(final IExpressionUpdate update) {
+ final IExpressionVMNode matchingNode =
+ getExpressionVMProvider().findNodeToParseExpression(null, update.getExpression());
+
+ if (matchingNode != null) {
+ updateExpressionWithNode(matchingNode, update);
+ } else {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Cannot parse expression", null)); //$NON-NLS-1$
+ update.done();
+ }
+ }
+
+ private void updateExpressionWithNode(final IExpressionVMNode node, final IExpressionUpdate update) {
+ // Call the expression node to parse the expression and fill in the value.
+ node.update(
+ new VMExpressionUpdate(
+ update, update.getExpression(),
+ new ViewerDataRequestMonitor<Object>(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ // Check if the evaluated node has child expression nodes.
+ // If it does, check if any of those nodes can evaluate the given
+ // expression further. If they can, call the child node to further
+ // process the expression. Otherwise we found our element and
+ // we're done.
+ final IExpressionVMNode matchingNode = getExpressionVMProvider().
+ findNodeToParseExpression(node, update.getExpression());
+
+ if (matchingNode != null && !matchingNode.equals(node)) {
+ updateExpressionWithNode(
+ matchingNode,
+ new VMExpressionUpdate(
+ update.getElementPath().createChildPath(getData()), update.getViewerInput(),
+ update.getPresentationContext(), update.getExpression(),
+ new ViewerDataRequestMonitor<Object>(getVMProvider().getExecutor(), update) {
+
+ @Override
+ protected void handleSuccess() {
+ update.setExpressionElement(getData());
+ update.done();
+ }
+ })
+ );
+ } else {
+ update.setExpressionElement(getData());
+ update.done();
+ }
+ }
+ })
+ );
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderModelProxyStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderModelProxyStrategy.java
new file mode 100644
index 00000000000..fb59a74e02e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionVMProviderModelProxyStrategy.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.DefaultVMModelProxyStrategy;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * The IModelProxy implementation to be used with an expression
+ * view model provider.
+ *
+ * @see ExpressionVMProvider
+ */
+@SuppressWarnings("restriction")
+public class ExpressionVMProviderModelProxyStrategy extends DefaultVMModelProxyStrategy {
+
+ public ExpressionVMProviderModelProxyStrategy(ExpressionVMProvider provider, Object rootElement) {
+ super(provider, rootElement);
+ }
+
+ private ExpressionVMProvider getExpressionVMProvider() {
+ return (ExpressionVMProvider)getVMProvider();
+ }
+
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ final IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(null, expression);
+
+ if (matchingNode != null) {
+ return getNodeDeltaFlagsForExpression(matchingNode, expression, event);
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ private int getNodeDeltaFlagsForExpression(IExpressionVMNode node, IExpression expression, Object event) {
+ int flags = node.getDeltaFlagsForExpression(expression, event);
+
+ IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(node, expression);
+ if (matchingNode != null && !matchingNode.equals(node)) {
+ flags = flags | getNodeDeltaFlagsForExpression(matchingNode, expression, event);
+ } else {
+ // Check the child nodes of this expression node for additional
+ // delta flags.
+ for (IVMNode childNode : getVMProvider().getChildVMNodes(node)) {
+ if (!childNode.equals(node)) {
+ int childNodeDeltaFlags = getDeltaFlags(childNode, null, event);
+ if ((childNodeDeltaFlags & IModelDelta.CONTENT) != 0) {
+ childNodeDeltaFlags &= ~IModelDelta.CONTENT;
+ childNodeDeltaFlags |= IModelDelta.STATE;
+ }
+ flags |= childNodeDeltaFlags;
+ }
+ }
+ }
+ return flags;
+ }
+
+ public void buildDeltaForExpression(IExpression expression, int expressionElementIdx, Object event,
+ VMDelta parentDelta, TreePath path, RequestMonitor rm)
+ {
+ final IExpressionVMNode matchingNode = getExpressionVMProvider().findNodeToParseExpression(null, expression);
+
+ if (matchingNode != null) {
+ buildNodeDeltaForExpression(matchingNode, expression, expressionElementIdx, event,
+ parentDelta, path, rm);
+ } else {
+ rm.done();
+ }
+ }
+
+ private void buildNodeDeltaForExpression(final IExpressionVMNode node, final IExpression expression,
+ final int expressionElementIdx, final Object event, final VMDelta parentDelta, final TreePath path,
+ final RequestMonitor rm)
+ {
+ node.buildDeltaForExpression(
+ expression, expressionElementIdx, event, parentDelta, path,
+ new RequestMonitor(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ final IExpressionVMNode matchingNode =
+ getExpressionVMProvider().findNodeToParseExpression(node, expression);
+ if (matchingNode != null && !matchingNode.equals(node)) {
+ buildNodeDeltaForExpression(
+ matchingNode, expression, expressionElementIdx, event, parentDelta, path, rm);
+ } else {
+ getExpressionVMProvider().update(new VMExpressionUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), expression,
+ new DataRequestMonitor<Object>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ buildDeltaForExpressionElement(
+ node, expression, getData(), expressionElementIdx, event, parentDelta, path, rm);
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ // Avoid propagating the error to avoid processing the delta by
+ // all nodes.
+ rm.done();
+ }
+ }));
+ }
+ }
+ });
+ }
+
+
+ private void buildDeltaForExpressionElement(IExpressionVMNode node, IExpression expression, Object expressionElement,
+ int expressionElementIdx, Object event, VMDelta parentDelta, TreePath path, RequestMonitor rm)
+ {
+ CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), rm);
+ int multiRmCount = 0;
+
+ node.buildDeltaForExpressionElement(expressionElement, expressionElementIdx, event, parentDelta, multiRm);
+ multiRmCount++;
+
+ // Find the child nodes that have deltas for the given event.
+ Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event);
+
+ // If no child layout nodes have deltas we can stop here.
+ if (childNodesWithDeltaFlags.size() != 0) {
+ callChildNodesToBuildDelta(
+ node, childNodesWithDeltaFlags,
+ parentDelta.addNode(expressionElement, expressionElementIdx, IModelDelta.NO_CHANGE),
+ event, multiRm);
+ multiRmCount++;
+ }
+
+ if (event instanceof ExpressionsChangedEvent) {
+ buildDeltaForExpressionsChangedEvent(expressionElement, expressionElementIdx,
+ (ExpressionsChangedEvent)event, parentDelta, multiRm);
+ multiRmCount++;
+ }
+
+ multiRm.setDoneCount(multiRmCount);
+ }
+
+ private void buildDeltaForExpressionsChangedEvent(Object element, int elementIdx, ExpressionsChangedEvent event,
+ VMDelta parentDelta, final RequestMonitor rm)
+ {
+ switch (event.getType()) {
+ case ADDED:
+ parentDelta.addNode(element, -1, IModelDelta.ADDED);
+ break;
+ case CHANGED:
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ break;
+ case MOVED:
+ parentDelta.addNode(element, -1, IModelDelta.REMOVED);
+ parentDelta.addNode(element, elementIdx, IModelDelta.INSERTED);
+ break;
+ case REMOVED:
+ parentDelta.addNode(element, -1, IModelDelta.REMOVED);
+ break;
+ case INSERTED:
+ parentDelta.addNode(element, elementIdx, IModelDelta.INSERTED);
+ break;
+ default:
+ break;
+ }
+ rm.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsBreakpointHitUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsBreakpointHitUpdatePolicy.java
new file mode 100644
index 00000000000..63bdc7f58bc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsBreakpointHitUpdatePolicy.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
+
+/**
+ * Manual update policy which selectively clears the cache when the expressions
+ * in the expression manager are modified.
+ */
+public class ExpressionsBreakpointHitUpdatePolicy extends BreakpointHitUpdatePolicy {
+
+ @Override
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ if (event instanceof ExpressionsChangedEvent) {
+ return new ExpressionsChangedUpdateTester((ExpressionsChangedEvent)event);
+ }
+ return super.getElementUpdateTester(event);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedEvent.java
new file mode 100644
index 00000000000..058a6f39e2a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedEvent.java
@@ -0,0 +1,38 @@
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.expression;
+
+import java.util.Arrays;
+import java.util.Set;
+
+import org.eclipse.debug.core.model.IExpression;
+
+/**
+ * Object representing a change in configured expressions. This event is
+ * object is used when generating a model delta.
+ */
+public class ExpressionsChangedEvent {
+ enum Type {ADDED, CHANGED, REMOVED, MOVED, INSERTED}
+
+ private final Set<Object> fExpressionManagerElements;
+ private final ExpressionsChangedEvent.Type fType;
+ private final IExpression[] fExpressions;
+ private final int fIndex;
+
+ public ExpressionsChangedEvent(ExpressionsChangedEvent.Type type, Set<Object> expressionManagerElements,
+ IExpression[] expressions, int index)
+ {
+ fExpressionManagerElements = expressionManagerElements;
+ fType = type;
+ fExpressions = expressions;
+ fIndex = index;
+ }
+
+ public Set<Object> getExpressionManagerElements() { return fExpressionManagerElements; }
+ public ExpressionsChangedEvent.Type getType() { return fType; }
+ public IExpression[] getExpressions() { return fExpressions; }
+ public int getIndex() { return fIndex; }
+
+ @Override
+ public String toString() {
+ return Arrays.asList(fExpressions).toString() + " " + fType + "@" + fIndex; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedUpdateTester.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedUpdateTester.java
new file mode 100644
index 00000000000..9f29b3c466a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsChangedUpdateTester.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.jface.viewers.TreePath;
+
+class ExpressionsChangedUpdateTester implements IElementUpdateTester {
+
+ private final ExpressionsChangedEvent fEvent;
+
+ public ExpressionsChangedUpdateTester(ExpressionsChangedEvent event) {
+ fEvent = event;
+ }
+
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ // Check whether the element in the cache matches the expression manager element.
+ Object element = path.getSegmentCount() == 0 ? viewerInput : path.getLastSegment();
+ if (fEvent.getExpressionManagerElements().contains(element)) {
+ return ExpressionsManualUpdatePolicy.FLUSH;
+ }
+
+ // If the expressions were modified, flush the entries which are under the
+ // given expression. To do that, check whether the element path contains one
+ // of the changed expressions.
+ if (fEvent.getType().equals(ExpressionsChangedEvent.Type.CHANGED)) {
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ if (eventContainsElement(path.getSegment(i))) {
+ return ExpressionsManualUpdatePolicy.FLUSH;
+ }
+ }
+ }
+ return 0;
+ }
+
+ private boolean eventContainsElement(Object element) {
+ if (element instanceof IAdaptable) {
+ IExpression expression = (IExpression)((IAdaptable)element).getAdapter(IExpression.class);
+ if (expression != null) {
+ for (int i = 0; i < fEvent.getExpressions().length; i++) {
+ if (expression.equals(fEvent.getExpressions()[i])) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ return tester instanceof ExpressionsChangedUpdateTester;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + fEvent + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsManualUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsManualUpdatePolicy.java
new file mode 100644
index 00000000000..8ca367468a6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/ExpressionsManualUpdatePolicy.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+
+/**
+ * Manual update policy which selectively clears the cache when the expressions
+ * in the expression manager are modified.
+ */
+public class ExpressionsManualUpdatePolicy extends ManualUpdatePolicy {
+
+ @Override
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ if (event instanceof ExpressionsChangedEvent) {
+ return new ExpressionsChangedUpdateTester((ExpressionsChangedEvent)event);
+ }
+ return super.getElementUpdateTester(event);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionUpdate.java
new file mode 100644
index 00000000000..e3fd41fc4a7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionUpdate.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * An update for an element based on the given expression. The provider processing
+ * this update needs to create an expression element based on the tree path and the
+ * expression object in this update.
+ */
+@SuppressWarnings("restriction")
+public interface IExpressionUpdate extends IViewerUpdate {
+
+ /**
+ * Returns the expression object for this update.
+ */
+ public IExpression getExpression();
+
+ /**
+ * Sets the element to the update. The element is to be calculated by the provider
+ * handling the update.
+ */
+ public void setExpressionElement(Object element);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionVMNode.java
new file mode 100644
index 00000000000..1403d73d25e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/IExpressionVMNode.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Interface for view model nodes that can be used within the expression view.
+ * The methods of this interface allow the {@link ExpressionManagerVMNode}
+ * to use this node to delegate expression parsing to this node, and to
+ * generate deltas for expressions that are owned by this node.
+ */
+public interface IExpressionVMNode extends IVMNode {
+
+ /**
+ * Returns whether the given expression node recognizes and can parse the given
+ * expression.
+ * @param expression Expression that needs to be parsed.
+ * @return true if expression can be parsed
+ */
+ public boolean canParseExpression(IExpression expression);
+
+ /**
+ * Asynchronously fills in the given expression update.
+ * @param update Update to complete.
+ */
+ public void update(IExpressionUpdate update);
+
+ /**
+ * Returns the flags that this node can generate for the given expression and
+ * event.
+ */
+ public int getDeltaFlagsForExpression(IExpression expression, Object event);
+
+ /**
+ * Adds delta flags to the given parent delta based on the expression
+ * object given. The nodes add flags to the expression view's root
+ * delta using this method, regardless of whether the node is directly
+ * below the expression manager or not.
+ *
+ */
+ public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
+ TreePath path, RequestMonitor rm);
+
+ /**
+ * Adds delta to the given parent delta based on the given element that
+ * was created base on an expression parsed by this node. The VM nodes can
+ * add a new delta node to the parentDela by implementing this method.
+ */
+ public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/InvalidExpressionVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/InvalidExpressionVMContext.java
new file mode 100644
index 00000000000..9731351bb98
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/InvalidExpressionVMContext.java
@@ -0,0 +1,88 @@
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.resource.JFaceResources;
+
+/**
+ * VMC of an expression object that failed to get parsed by any of the
+ * configured expression layout nodes. It is only used to display an
+ * error message in the view, and to allow the user to edit the
+ * expression.
+ * <p>
+ * Note: VM Nodes using this invalid expression VM context should
+ * provide a cell modifier to edit the expressions. The cell modifier
+ * should subclass {@link WatchExpressionCellModifier}.
+ * </p>
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class InvalidExpressionVMContext extends AbstractVMContext implements IElementLabelProvider {
+
+ final private IExpression fExpression;
+
+ public InvalidExpressionVMContext(IVMNode node, IExpression expression) {
+ super(node);
+ fExpression = expression;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (adapter.isAssignableFrom(fExpression.getClass())) {
+ return fExpression;
+ } else {
+ return super.getAdapter(adapter);
+ }
+ }
+
+ public IExpression getExpression() {
+ return fExpression;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof InvalidExpressionVMContext && ((InvalidExpressionVMContext)obj).fExpression.equals(fExpression);
+ }
+
+ @Override
+ public int hashCode() {
+ return fExpression.hashCode();
+ }
+
+ /**
+ * Updates the label for the InvalidExpressionVMC.
+ */
+ public void update(ILabelUpdate[] updates) {
+ for (ILabelUpdate update : updates) {
+ String[] columnIds = update.getColumnIds() != null ?
+ update.getColumnIds() : new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int i = 0; i < columnIds.length; i++) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnIds[i])) {
+ update.setLabel(getExpression().getExpressionText(), i);
+ update.setImageDescriptor(DebugUITools.getImageDescriptor( IDebugUIConstants.IMG_OBJS_EXPRESSION ), i);
+ } else if (IDebugVMConstants.COLUMN_ID__NAME.equals(columnIds[i])) {
+ update.setLabel(getExpression().getExpressionText(), i);
+ update.setImageDescriptor(DebugUITools.getImageDescriptor( IDebugUIConstants.IMG_OBJS_EXPRESSION ), i);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnIds[i])) {
+ update.setLabel(MessagesForExpressionVM.ExpressionManagerLayoutNode__invalidExpression_valueColumn_label, i);
+ } else {
+ update.setLabel("", i); //$NON-NLS-1$
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], i);
+ }
+
+ update.done();
+ }
+ }
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/MessagesForExpressionVM.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/MessagesForExpressionVM.java
new file mode 100644
index 00000000000..02014605b57
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/MessagesForExpressionVM.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForExpressionVM extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.messages"; //$NON-NLS-1$
+
+ public static String ExpressionColumnPresentation_expression;
+ public static String ExpressionColumnPresentation_name;
+ public static String ExpressionColumnPresentation_type;
+ public static String ExpressionColumnPresentation_value;
+ public static String ExpressionColumnPresentation_address;
+ public static String ExpressionColumnPresentation_description;
+
+ public static String ExpressionManagerLayoutNode__invalidExpression_nameColumn_label;
+ public static String ExpressionManagerLayoutNode__invalidExpression_valueColumn_label;
+
+ public static String ExpressionManagerLayoutNode__newExpression_label;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForExpressionVM.class);
+ }
+
+ private MessagesForExpressionVM() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/VMExpressionUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/VMExpressionUpdate.java
new file mode 100644
index 00000000000..8f64c623b28
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/VMExpressionUpdate.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMViewerUpdate;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+class VMExpressionUpdate extends VMViewerUpdate implements IExpressionUpdate {
+
+ private final IExpression fExpression;
+ private Object fExpressionElement;
+
+ public VMExpressionUpdate(IViewerUpdate clientUpdate, IExpression expression, DataRequestMonitor<Object> rm)
+ {
+ super(clientUpdate, rm);
+ fExpression = expression;
+ }
+
+ public VMExpressionUpdate(IModelDelta delta, IPresentationContext presentationContext, IExpression expression, DataRequestMonitor<Object> rm)
+ {
+ super(delta, presentationContext, rm);
+ fExpression = expression;
+ }
+
+ public VMExpressionUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, IExpression expression, DataRequestMonitor<Object> rm)
+ {
+ super(elementPath, viewerInput, presentationContext, rm);
+ fExpression = expression;
+ }
+
+
+ public IExpression getExpression() {
+ return fExpression;
+ }
+
+
+ public void setExpressionElement(Object element) {
+ fExpressionElement = element;
+ }
+
+ @Override
+ public String toString() {
+ return "VMExpressionUpdate for elements under parent = " + getElement() + ", in for expression " + getExpression().getExpressionText(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public void done() {
+ @SuppressWarnings("unchecked")
+
+ DataRequestMonitor<Object> rm = (DataRequestMonitor<Object>)getRequestMonitor();
+ if (fExpressionElement != null) {
+ rm.setData(fExpressionElement);
+ } else if (rm.isSuccess()) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Incomplete elements of updates", null)); //$NON-NLS-1$
+ }
+ super.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionCellModifier.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionCellModifier.java
new file mode 100644
index 00000000000..8f4413bab8a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionCellModifier.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionManagerVMNode.NewExpressionVMC;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IExpressionManager;
+import org.eclipse.debug.core.model.IWatchExpression;
+import org.eclipse.jface.viewers.ICellModifier;
+
+/**
+ *
+ */
+@ThreadSafeAndProhibitedFromDsfExecutor("")
+public class WatchExpressionCellModifier implements ICellModifier {
+
+ /**
+ * Constructor for the modifier requires a valid DSF session in order to
+ * initialize the service tracker.
+ * @param session DSF session this modifier will use.
+ */
+ public WatchExpressionCellModifier() {
+ }
+
+ public boolean canModify(Object element, String property) {
+ return IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(property) &&
+ (getWatchExpression(element) != null || element instanceof NewExpressionVMC);
+ }
+
+ public Object getValue(Object element, String property) {
+ if (!IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(property)) return ""; //$NON-NLS-1$
+
+ IWatchExpression expression = getWatchExpression(element);
+
+ if (expression != null) {
+ return expression.getExpressionText();
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ public void modify(Object element, String property, Object value) {
+ if (!IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(property)) return;
+ if (!(value instanceof String)) return;
+
+ String origStrValue = (String) value;
+ String strValue = origStrValue.trim();
+ IWatchExpression expression = getWatchExpression(element);
+ IExpressionManager expressionManager = DebugPlugin.getDefault().getExpressionManager();
+ if (expression != null) {
+ if (strValue.length() != 0) {
+ expression.setExpressionText(origStrValue);
+ } else {
+ // (bug 233111) If user entered a blank string, remove the expression.
+ expressionManager.removeExpression(expression);
+ }
+ } else if (element instanceof NewExpressionVMC && strValue.length() != 0) {
+ IWatchExpression watchExpression = expressionManager.newWatchExpression(origStrValue);
+ expressionManager.addExpression(watchExpression);
+ }
+ }
+
+ private IWatchExpression getWatchExpression(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IWatchExpression)((IAdaptable)element).getAdapter(IWatchExpression.class);
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionDelegate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionDelegate.java
new file mode 100644
index 00000000000..91fa6f1492c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/WatchExpressionDelegate.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.expression;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.core.model.IWatchExpressionDelegate;
+import org.eclipse.debug.core.model.IWatchExpressionListener;
+import org.eclipse.debug.core.model.IWatchExpressionResult;
+
+/**
+ *
+ */
+public class WatchExpressionDelegate implements IWatchExpressionDelegate {
+ public void evaluateExpression(final String expression, IDebugElement context, IWatchExpressionListener listener) {
+ listener.watchEvaluationFinished(new IWatchExpressionResult() {
+ public String[] getErrorMessages() { return new String[0]; }
+ public DebugException getException() { return null; }
+ public String getExpressionText() { return expression; }
+ public IValue getValue() { return null; }
+ public boolean hasErrors() { return false; }
+ });
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/messages.properties
new file mode 100644
index 00000000000..9102d757a58
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/expression/messages.properties
@@ -0,0 +1,21 @@
+###############################################################################
+# Copyright (c) 2008 Wind River Systems 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
+# Wind River Systems - added Address
+###############################################################################
+
+ExpressionColumnPresentation_expression=Expression
+ExpressionColumnPresentation_name=Name
+ExpressionColumnPresentation_type=Type
+ExpressionColumnPresentation_value=Value
+ExpressionColumnPresentation_address=Address
+ExpressionColumnPresentation_description=Description
+ExpressionManagerLayoutNode__invalidExpression_nameColumn_label=Invalid expression
+ExpressionManagerLayoutNode__invalidExpression_valueColumn_label=Invalid expression
+ExpressionManagerLayoutNode__newExpression_label=Add new expression
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java
new file mode 100644
index 00000000000..26cfc2d5468
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractContainerVMNode.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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:
+ * Anton Leherbauer (Wind River Systems) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ * Abstract implementation of a container view model node.
+ * Clients need to implement {@link #updateLabelInSessionThread(ILabelUpdate[])}.
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider {
+
+ public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, IRunControl.IContainerDMContext.class);
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ for (final ILabelUpdate update : updates) {
+ updateLabelInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ /**
+ * Perform the given label updates in the session executor thread.
+ *
+ * @param updates the pending label updates
+ * @see {@link #update(ILabelUpdate[])
+ */
+ protected abstract void updateLabelInSessionThread(ILabelUpdate update);
+
+ @Override
+ public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) {
+ super.getContextsForEvent(parentDelta, e, rm);
+ }
+
+ public int getDeltaFlags(Object e) {
+ IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+ if (e instanceof IContainerResumedDMEvent) {
+ if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
+ {
+ return IModelDelta.CONTENT;
+ }
+ } else if (e instanceof IContainerSuspendedDMEvent) {
+ return IModelDelta.NO_CHANGE;
+ } else if (e instanceof FullStackRefreshEvent) {
+ if (dmc instanceof IContainerDMContext) {
+ return IModelDelta.CONTENT;
+ }
+ } else if (e instanceof SteppingTimedOutEvent) {
+ if (dmc instanceof IContainerDMContext)
+ {
+ return IModelDelta.CONTENT;
+ }
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ if (dmc instanceof IContainerDMContext)
+ {
+ return IModelDelta.CONTENT;
+ }
+ } else if (e instanceof IExitedDMEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof IStartedDMEvent) {
+ if (dmc instanceof IContainerDMContext) {
+ return IModelDelta.EXPAND | IModelDelta.SELECT;
+ } else {
+ return IModelDelta.CONTENT;
+ }
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+ if(e instanceof IContainerResumedDMEvent) {
+ // Container resumed:
+ // - If not stepping, update the container and the execution
+ // contexts under it.
+ // - If stepping, do nothing to avoid too many updates. If a
+ // time-out is reached before the step completes, the
+ // ISteppingTimedOutEvent will trigger a full refresh.
+ if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
+ {
+ parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
+ }
+ } else if (e instanceof IContainerSuspendedDMEvent) {
+ // Container suspended. Do nothing here to give the stack the
+ // priority in updating. The container and threads will update as
+ // a result of FullStackRefreshEvent.
+ } else if (e instanceof FullStackRefreshEvent) {
+ // Full-stack refresh event is generated following a suspended event
+ // and a fixed delay. If the suspended event was generated for the
+ // container refresh the whole container.
+ if (dmc instanceof IContainerDMContext) {
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ }
+ } else if (e instanceof SteppingTimedOutEvent) {
+ // Stepping time-out indicates that a step operation is taking
+ // a long time, and the view needs to be refreshed to show
+ // the user that the program is running.
+ // If the step was issued for the whole container refresh
+ // the whole container.
+ if (dmc instanceof IContainerDMContext) {
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ }
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ // Stepping time-out indicates that a step operation is taking
+ // a long time, and the view needs to be refreshed to show
+ // the user that the program is running.
+ // If the step was issued for the whole container refresh
+ // the whole container.
+ if (dmc instanceof IContainerDMContext) {
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ }
+ } else if (e instanceof IExitedDMEvent) {
+ // An exited event could either be for a thread within a container
+ // or for the container itself.
+ // If a container exited, refresh the parent element so that the
+ // container may be removed.
+ // If a thread exited within a container, refresh that container.
+ if (dmc instanceof IContainerDMContext) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ } else {
+ IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
+ if (containerCtx != null) {
+ parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
+ }
+ }
+ } else if (e instanceof IStartedDMEvent) {
+ // A started event could either be for a thread within a container
+ // or for the container itself.
+ // If a container started, issue an expand and select event to
+ // show the threads in the new container.
+ // Note: the EXPAND flag implies refreshing the parent element.
+ if (dmc instanceof IContainerDMContext) {
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.EXPAND | IModelDelta.SELECT);
+ } else {
+ IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
+ if (containerCtx != null) {
+ parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
+ }
+ }
+ }
+
+ requestMonitor.done();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java
new file mode 100644
index 00000000000..28de36ba1d8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractLaunchVMProvider.java
@@ -0,0 +1,294 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Modified for new functionality
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode.IncompleteStackVMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+
+/**
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class AbstractLaunchVMProvider extends AbstractDMVMProvider
+ implements IDebugEventSetListener, ILaunchesListener2
+{
+ /**
+ * Delay (in milliseconds) before a full stack trace will be requested.
+ */
+ private static final int FRAME_UPDATE_DELAY= 200;
+
+ private final Map<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
+
+ private IPropertyChangeListener fPreferencesListener;
+
+ @ThreadSafe
+ public AbstractLaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)
+ {
+ super(adapter, presentationContext, session);
+
+ final IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore();
+ if (store.getBoolean(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE)) {
+ getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, store.getInt(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT));
+ }
+
+ fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(final PropertyChangeEvent event) {
+ handlePropertyChanged(store, event);
+ }};
+ store.addPropertyChangeListener(fPreferencesListener);
+ }
+
+ @Override
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] {
+ new DelayedStackRefreshUpdatePolicy(new AutomaticUpdatePolicy()),
+ new DelayedStackRefreshUpdatePolicy(new ManualUpdatePolicy())
+ };
+ }
+
+ public void handleDebugEvents(final DebugEvent[] events) {
+ if (isDisposed()) return;
+
+ // We're in session's executor thread. Re-dispach to VM Adapter
+ // executor thread and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+
+ for (final DebugEvent event : events) {
+ handleEvent(event);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+
+ @Override
+ public void handleEvent(Object event, final RequestMonitor rm) {
+ if (event instanceof DoubleClickEvent && !isDisposed()) {
+ final ISelection selection= ((DoubleClickEvent) event).getSelection();
+ if (selection instanceof IStructuredSelection) {
+ Object element= ((IStructuredSelection) selection).getFirstElement();
+ if (element instanceof IncompleteStackVMContext) {
+ IncompleteStackVMContext incStackVmc = ((IncompleteStackVMContext) element);
+ IVMNode node = incStackVmc.getVMNode();
+ if (node instanceof StackFramesVMNode && node.getVMProvider() == this) {
+ IExecutionDMContext exeCtx= incStackVmc.getExecutionDMContext();
+ ((StackFramesVMNode) node).incrementStackFrameLimit(exeCtx);
+ // replace double click event with expand stack event
+ final ExpandStackEvent expandStackEvent = new ExpandStackEvent(exeCtx);
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(expandStackEvent, null);
+ }
+ });
+ }
+ }
+ }
+ if (rm != null) {
+ rm.done();
+ }
+ return;
+ }
+ super.handleEvent(event, rm);
+ }
+
+ @Override
+ protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
+ super.handleEvent(proxyStrategy, event, rm);
+
+ if (event instanceof IRunControl.ISuspendedDMEvent) {
+ final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext();
+ ScheduledFuture<?> refreshStackFramesFuture = getRefreshFuture(exeContext);
+ // trigger delayed full stack frame update
+ if (refreshStackFramesFuture != null) {
+ // cancel previously scheduled frame update
+ refreshStackFramesFuture.cancel(false);
+ }
+
+ refreshStackFramesFuture = getSession().getExecutor().schedule(
+ new DsfRunnable() {
+ public void run() {
+ if (getSession().isActive()) {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ // trigger full stack frame update
+ ScheduledFuture<?> future= fRefreshStackFramesFutures.get(exeContext);
+ if (future != null && !isDisposed()) {
+ fRefreshStackFramesFutures.remove(exeContext);
+ handleEvent(new FullStackRefreshEvent(exeContext), null);
+ }
+ }});
+ }
+ }
+ },
+ FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+ fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture);
+ } else if (event instanceof IRunControl.IResumedDMEvent) {
+ IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext();
+ ScheduledFuture<?> refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext);
+ if (refreshStackFramesFuture != null) {
+ // cancel previously scheduled frame update
+ refreshStackFramesFuture.cancel(false);
+ fRefreshStackFramesFutures.remove(exeContext);
+ }
+ }
+
+ }
+
+ /**
+ * Returns the future for the given execution context or for any child of the
+ * given execution context.
+ */
+ private ScheduledFuture<?> getRefreshFuture(IExecutionDMContext execCtx) {
+ for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) {
+ if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) {
+ return fRefreshStackFramesFutures.remove(refreshCtx);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void dispose() {
+ DebugPlugin.getDefault().removeDebugEventListener(this);
+ DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
+
+ final IPreferenceStore store= DsfUIPlugin.getDefault().getPreferenceStore();
+ store.removePropertyChangeListener(fPreferencesListener);
+
+ super.dispose();
+ }
+
+ public void launchesAdded(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED));
+ }
+
+ public void launchesRemoved(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED));
+ }
+
+ public void launchesChanged(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED));
+ }
+
+ public void launchesTerminated(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED));
+ }
+
+ private void handleLaunchesEvent(final LaunchesEvent event) {
+ if (isDisposed()) return;
+
+ // We're in session's executor thread. Re-dispach to VM Adapter
+ // executor thread and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+
+ IRootVMNode rootLayoutNode = getRootVMNode();
+ if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
+ handleEvent(event);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+
+ @Override
+ protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+ // To optimize view performance when stepping rapidly, skip events that came
+ // before the last suspended events. However, the debug view can get suspended
+ // events for different threads, so make sure to skip only the events if they
+ // were in the same hierarchy as the last suspended event.
+ // Note: Avoid skipping thread started/exited events which require a larger
+ // scope refresh than some suspended events.
+ if (newEvent instanceof IStartedDMEvent || newEvent instanceof IExitedDMEvent) {
+ return false;
+ }
+
+ if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent<?>) {
+ IDMContext newEventDmc = ((IDMEvent<?>)newEvent).getDMContext();
+ IDMContext eventToSkipDmc = ((IDMEvent<?>)eventToSkip).getDMContext();
+
+ if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected void handlePropertyChanged(final IPreferenceStore store, final PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property)
+ || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property)) {
+ if (store.getBoolean(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE)) {
+ getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, store.getInt(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT));
+ } else {
+ getPresentationContext().setProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT, null);
+ }
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ handleEvent(event);
+ }
+ });
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java
new file mode 100644
index 00000000000..51f28dc57f9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/AbstractThreadVMNode.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Modified for multi threaded functionality
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch;
+
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.ModelProxyInstalledEvent;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+
+/**
+ * Abstract implementation of a thread view model node.
+ * Clients need to implement {@link #updateLabelInSessionThread(ILabelUpdate[])}.
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractThreadVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider
+{
+ public AbstractThreadVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, IExecutionDMContext.class);
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ IRunControl runControl = getServicesTracker().getService(IRunControl.class);
+ final IContainerDMContext contDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IContainerDMContext.class);
+ if (runControl == null || contDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ runControl.getExecutionContexts(contDmc,
+ new ViewerDataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), update){
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }
+ });
+ }
+
+
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @Override
+ public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) {
+ if(e instanceof IContainerResumedDMEvent) {
+ IExecutionDMContext[] triggerContexts = ((IContainerResumedDMEvent)e).getTriggeringContexts();
+ if (triggerContexts.length != 0) {
+ rm.setData(new IVMContext[] { createVMContext(triggerContexts[0]) });
+ rm.done();
+ return;
+ }
+ } else if(e instanceof IContainerSuspendedDMEvent) {
+ IExecutionDMContext[] triggerContexts = ((IContainerSuspendedDMEvent)e).getTriggeringContexts();
+ if (triggerContexts.length != 0) {
+ rm.setData(new IVMContext[] { createVMContext(triggerContexts[0]) });
+ rm.done();
+ return;
+ }
+ } else if (e instanceof SteppingTimedOutEvent &&
+ ((SteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext)
+ {
+ // The timed out event occured on a container and not on a thread. Do not
+ // return a context for this event, which will force the view model to generate
+ // a delta for all the threads.
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ } else if (e instanceof ISteppingTimedOutEvent &&
+ ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext)
+ {
+ // The timed out event occured on a container and not on a thread. Do not
+ // return a context for this event, which will force the view model to generate
+ // a delta for all the threads.
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ } else if (e instanceof FullStackRefreshEvent &&
+ ((FullStackRefreshEvent)e).getDMContext() instanceof IContainerDMContext)
+ {
+ // The step sequence end event occured on a container and not on a thread. Do not
+ // return a context for this event, which will force the view model to generate
+ // a delta for all the threads.
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ } else if (e instanceof ModelProxyInstalledEvent) {
+ getThreadVMCForModelProxyInstallEvent(
+ parentDelta,
+ new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ rm.setData(new IVMContext[] { getData().fVMContext });
+ } else {
+ rm.setData(new IVMContext[0]);
+ }
+ rm.done();
+ }
+ });
+ return;
+ }
+ super.getContextsForEvent(parentDelta, e, rm);
+ }
+
+ private static class VMContextInfo {
+ final IVMContext fVMContext;
+ final int fIndex;
+ final boolean fIsSuspended;
+ VMContextInfo(IVMContext vmContext, int index, boolean isSuspended) {
+ fVMContext = vmContext;
+ fIndex = index;
+ fIsSuspended = isSuspended;
+ }
+ }
+
+ private void getThreadVMCForModelProxyInstallEvent(VMDelta parentDelta, final DataRequestMonitor<VMContextInfo> rm) {
+ getVMProvider().updateNode(this, new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), -1, -1,
+ new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRunControl runControl = getServicesTracker().getService(IRunControl.class);
+ if (runControl != null) {
+ int vmcIdx = -1;
+ int suspendedVmcIdx = -1;
+
+ for (int i = 0; i < getData().size(); i++) {
+ if (getData().get(i) instanceof IDMVMContext) {
+ IDMVMContext vmc = (IDMVMContext)getData().get(i);
+ IExecutionDMContext execDmc = DMContexts.getAncestorOfType(
+ vmc.getDMContext(), IExecutionDMContext.class);
+ if (execDmc != null) {
+ vmcIdx = vmcIdx < 0 ? i : vmcIdx;
+ if (runControl.isSuspended(execDmc)) {
+ suspendedVmcIdx = suspendedVmcIdx < 0 ? i : suspendedVmcIdx;
+ }
+ }
+ }
+ }
+ if (suspendedVmcIdx >= 0) {
+ rm.setData(new VMContextInfo(
+ (IVMContext)getData().get(suspendedVmcIdx), suspendedVmcIdx, true));
+ } else if (vmcIdx >= 0) {
+ rm.setData(new VMContextInfo((IVMContext)getData().get(vmcIdx), vmcIdx, false));
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$
+ }
+ rm.done();
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "No threads available", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ }));
+ }
+
+ /**
+ * Perform the given label updates in the session executor thread.
+ *
+ * @param updates the pending label updates
+ * @see {@link #update(ILabelUpdate[])
+ */
+ protected abstract void updateLabelInSessionThread(ILabelUpdate[] updates);
+
+
+ public int getDeltaFlags(Object e) {
+ IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+ if (dmc instanceof IContainerDMContext) {
+ return IModelDelta.NO_CHANGE;
+ } else if (e instanceof IResumedDMEvent &&
+ ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP)
+ {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof ISuspendedDMEvent) {
+ return IModelDelta.NO_CHANGE;
+ } else if (e instanceof FullStackRefreshEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof SteppingTimedOutEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof ModelProxyInstalledEvent) {
+ return IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+ if(dmc instanceof IContainerDMContext) {
+ // The IContainerDMContext sub-classes IExecutionDMContext.
+ // Also IContainerResumedDMEvent sub-classes IResumedDMEvent and
+ // IContainerSuspendedDMEvnet sub-classes ISuspendedEvent.
+ // Because of this relationship, the thread VM node can be called
+ // with data-model evnets for the containers. This statement
+ // filters out those event.
+ rm.done();
+ } else if(e instanceof IResumedDMEvent) {
+ // Resumed:
+ // - If not stepping, update the thread and its content (its stack).
+ // - If stepping, do nothing to avoid too many updates. If a
+ // time-out is reached before the step completes, the
+ // ISteppingTimedOutEvent will trigger a refresh.
+ if (((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) {
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ }
+ rm.done();
+ } else if (e instanceof ISuspendedDMEvent) {
+ // Container suspended. Do nothing here to give the stack the
+ // priority in updating. The thread will update as a result of
+ // FullStackRefreshEvent.
+ rm.done();
+ } else if (e instanceof FullStackRefreshEvent) {
+ // Full-stack refresh event is generated following a suspended event
+ // and a fixed delay. Refresh the whole thread upon this event.
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ rm.done();
+ } else if (e instanceof SteppingTimedOutEvent) {
+ // Stepping time-out indicates that a step operation is taking
+ // a long time, and the view needs to be refreshed to show
+ // the user that the program is running.
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ rm.done();
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ // Stepping time-out indicates that a step operation is taking
+ // a long time, and the view needs to be refreshed to show
+ // the user that the program is running.
+ parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+ rm.done();
+ } else if (e instanceof ModelProxyInstalledEvent) {
+ // Model Proxy install event is generated when the model is first
+ // populated into the view. This happens when a new debug session
+ // is started or when the view is first opened.
+ // In both cases, if there are already threads in the debug model,
+ // the desired user behavior is to show the threads and to select
+ // the first thread.
+ // If the thread is suspended, do not select the thread, instead,
+ // its top stack frame will be selected.
+ getThreadVMCForModelProxyInstallEvent(
+ parentDelta,
+ new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ parentDelta.addNode(
+ getData().fVMContext, nodeOffset + getData().fIndex,
+ IModelDelta.EXPAND | (getData().fIsSuspended ? 0 : IModelDelta.SELECT));
+ }
+ rm.done();
+ }
+ });
+ } else {
+
+ rm.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java
new file mode 100644
index 00000000000..7a05904d4a4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfModelSelectionPolicyFactory.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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:
+ * Anton Leherbauer (Wind River Systems) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+/**
+ * Default model selection policy factory for DSF.
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class DefaultDsfModelSelectionPolicyFactory implements IModelSelectionPolicyFactory {
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory#createModelSelectionPolicyAdapter(java.lang.Object, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext)
+ */
+ public IModelSelectionPolicy createModelSelectionPolicyAdapter(Object element, IPresentationContext context) {
+ if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) {
+ if (element instanceof IDMVMContext) {
+ IDMVMContext dmvmContext= (IDMVMContext) element;
+ IDMContext dmContext= dmvmContext.getDMContext();
+ if (dmContext != null) {
+ return new DefaultDsfSelectionPolicy(dmContext);
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java
new file mode 100644
index 00000000000..cb1e8faffbc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DefaultDsfSelectionPolicy.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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:
+ * Anton Leherbauer (Wind River Systems) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeSelection;
+
+/**
+ * Default DSF selection policy implementation modelled after platform version
+ * (<code>DefaultSelectionPolicy</code>).
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class DefaultDsfSelectionPolicy implements IModelSelectionPolicy {
+
+ private IDMContext fDMContext;
+
+ /**
+ * Create selection policy instance for the given data model context.
+ *
+ * @param dmContext
+ */
+ public DefaultDsfSelectionPolicy(IDMContext dmContext) {
+ fDMContext= dmContext;
+ }
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#contains(org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext)
+ */
+ public boolean contains(ISelection selection, IPresentationContext context) {
+ if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) {
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss= (IStructuredSelection) selection;
+ Object element= ss.getFirstElement();
+ if (element instanceof IDMVMContext) {
+ IDMVMContext dmvmContext= (IDMVMContext) element;
+ IDMContext dmContext= dmvmContext.getDMContext();
+ if (dmContext != null) {
+ return fDMContext.getSessionId().equals(dmContext.getSessionId());
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#isSticky(org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext)
+ */
+ public boolean isSticky(ISelection selection, IPresentationContext context) {
+ if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) {
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss= (IStructuredSelection) selection;
+ Object element= ss.getFirstElement();
+ return isSticky(element);
+ }
+ }
+ return false;
+ }
+
+ protected boolean isSticky(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMVMContext dmvmContext= (IDMVMContext) element;
+ IDMContext dmContext= dmvmContext.getDMContext();
+ if (dmContext instanceof IFrameDMContext) {
+ IExecutionDMContext execContext= DMContexts.getAncestorOfType(dmContext, IExecutionDMContext.class);
+ if (execContext != null) {
+ DsfServicesTracker servicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), dmContext.getSessionId());
+ try {
+ IRunControl runControl= servicesTracker.getService(IRunControl.class);
+ if (runControl != null) {
+ if (runControl.isSuspended(execContext)) {
+ return true;
+ }
+ }
+ } finally {
+ servicesTracker.dispose();
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#overrides(org.eclipse.jface.viewers.ISelection, org.eclipse.jface.viewers.ISelection, org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext)
+ */
+ public boolean overrides(ISelection existing, ISelection candidate, IPresentationContext context) {
+ if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId())) {
+ if (existing instanceof IStructuredSelection && candidate instanceof IStructuredSelection) {
+ IStructuredSelection ssExisting = (IStructuredSelection) existing;
+ IStructuredSelection ssCandidate = (IStructuredSelection) candidate;
+ return overrides(ssExisting.getFirstElement(), ssCandidate.getFirstElement());
+ }
+ }
+ return true;
+ }
+
+
+ protected boolean overrides(Object existing, Object candidate) {
+ if (existing == null || existing.equals(candidate)) {
+ return true;
+ }
+ if (existing instanceof IDMVMContext && candidate instanceof IDMVMContext) {
+ IDMContext curr = ((IDMVMContext) existing).getDMContext();
+ IDMContext cand = ((IDMVMContext) candidate).getDMContext();
+ if (curr instanceof IFrameDMContext && cand instanceof IFrameDMContext) {
+ IExecutionDMContext currExecContext= DMContexts.getAncestorOfType(curr, IExecutionDMContext.class);
+ if (currExecContext != null) {
+ IExecutionDMContext candExecContext= DMContexts.getAncestorOfType(cand, IExecutionDMContext.class);
+ return currExecContext.equals(candExecContext) || !isSticky(existing);
+ }
+ }
+ }
+ return !isSticky(existing);
+ }
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy#replaceInvalidSelection(org.eclipse.jface.viewers.ISelection, org.eclipse.jface.viewers.ISelection)
+ */
+ public ISelection replaceInvalidSelection(ISelection invalidSelection, ISelection newSelection) {
+ if (invalidSelection instanceof ITreeSelection) {
+ ITreeSelection treeSelection = (ITreeSelection)invalidSelection;
+ if (treeSelection.getPaths().length == 1) {
+ TreePath path = treeSelection.getPaths()[0];
+ return new TreeSelection(path.getParentPath());
+ }
+ }
+ return newSelection;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java
new file mode 100644
index 00000000000..8cdfc04d8d7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/DelayedStackRefreshUpdatePolicy.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.UpdatePolicyDecorator;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * An update strategy decorator specialized for delayed stack frame refresh. The
+ * strategy flushes only the cached top stack frame in case of an normal {@link ISuspendedDMEvent},
+ * while in in case of a special {@link FullStackRefreshEvent} everything is invalidated.
+ *
+ * <p>
+ * The underlying base update policy is considered for container contexts only.
+ * In other cases the cache data is always flushed.
+ * </p>
+ *
+ * @since 1.1
+ */
+public class DelayedStackRefreshUpdatePolicy extends UpdatePolicyDecorator {
+
+ private static final class DelayedStackRefreshUpdateTester implements IElementUpdateTester {
+
+ private final IElementUpdateTester fBaseTester;
+
+ /** Indicates whether only the top stack frame should be updated */
+ private final boolean fLazyStackFrameMode;
+
+ DelayedStackRefreshUpdateTester(IElementUpdateTester baseTester, boolean lazyStackFrameMode) {
+ fBaseTester = baseTester;
+ fLazyStackFrameMode = lazyStackFrameMode;
+ }
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput;
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ if (fLazyStackFrameMode) {
+ if (dmc instanceof IFrameDMContext) {
+ if (((IFrameDMContext) dmc).getLevel() == 0) {
+ return FLUSH;
+ }
+ } else if (dmc instanceof IExecutionDMContext) {
+ return fBaseTester.getUpdateFlags(viewerInput, path);
+ }
+ return DIRTY;
+ } else if (dmc instanceof IContainerDMContext) {
+ return fBaseTester.getUpdateFlags(viewerInput, path);
+ }
+ }
+ return FLUSH;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ // A non-lazy tester includes a lazy tester, but not vice versa.
+ // This allows entries that were marked as dirty by a flush with
+ // the lazy mode to be superseded by a non-lazy update which
+ // actually clears the entries that were marked as dirty.
+ if (tester instanceof DelayedStackRefreshUpdateTester) {
+ DelayedStackRefreshUpdateTester sfTester = (DelayedStackRefreshUpdateTester)tester;
+ if (fLazyStackFrameMode) {
+ if (sfTester.fLazyStackFrameMode) {
+ return fBaseTester.includes(sfTester.fBaseTester);
+ }
+ } else {
+ if (!sfTester.fLazyStackFrameMode) {
+ return fBaseTester.includes(sfTester.fBaseTester);
+ }
+ // non-lazy includes lazy
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "Delayed stack refresh (lazy = " + fLazyStackFrameMode + ", base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ }
+
+ private static final class ThreadsUpdateTester implements IElementUpdateTester {
+
+ private final IElementUpdateTester fBaseTester;
+
+ private final boolean fRefreshAll;
+
+ ThreadsUpdateTester(IElementUpdateTester baseTester, boolean refreshAll) {
+ fBaseTester = baseTester;
+ fRefreshAll = refreshAll;
+ }
+
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ Object element = path.getSegmentCount() != 0 ? path.getLastSegment() : viewerInput;
+
+ if (!fRefreshAll && element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ if (dmc instanceof IContainerDMContext) {
+ return fBaseTester.getUpdateFlags(viewerInput, path);
+ }
+ }
+
+ // If the element is not a container or if the flush all flag is set,
+ // always flush it.
+ return FLUSH;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ // A refresh-all tester includes a non-refresh-all tester, but not
+ // vice versa. This allows entries that were marked as dirty by
+ // a flush with
+ // the non-refresh-all to be superseded by a refresh-all update which
+ // actually clears the entries that were marked as dirty.
+ if (tester instanceof ThreadsUpdateTester) {
+ ThreadsUpdateTester threadsTester = (ThreadsUpdateTester)tester;
+ if (fRefreshAll) {
+ if (threadsTester.fRefreshAll) {
+ return fBaseTester.includes(threadsTester.fBaseTester);
+ }
+ // refresh-all includes the non-refresh-all
+ return true;
+ } else {
+ if (!threadsTester.fRefreshAll) {
+ return fBaseTester.includes(threadsTester.fBaseTester);
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "Threads update tester (base = " + fBaseTester + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+
+ public DelayedStackRefreshUpdatePolicy(IVMUpdatePolicy base) {
+ super(base);
+ }
+
+ @Override
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ if (event instanceof ISuspendedDMEvent) {
+ return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), true);
+ } else if (event instanceof FullStackRefreshEvent) {
+ return new DelayedStackRefreshUpdateTester(getBaseUpdatePolicy().getElementUpdateTester(event), false);
+ } else if (event instanceof IExitedDMEvent &&
+ ((IExitedDMEvent)event).getDMContext() instanceof IContainerDMContext)
+ {
+ // container exit should always trigger a refresh
+ return new ThreadsUpdateTester(super.getElementUpdateTester(event), true);
+ } else {
+ return new ThreadsUpdateTester(super.getElementUpdateTester(event), false);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java
new file mode 100644
index 00000000000..bed23000bb8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/ExpandStackEvent.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+/**
+ * Event to increase the stack frame limit for an execution context.
+ *
+ * @since 1.1
+ */
+public class ExpandStackEvent extends AbstractDMEvent<IExecutionDMContext> {
+
+ public ExpandStackEvent(IExecutionDMContext execCtx) {
+ super(execCtx);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java
new file mode 100644
index 00000000000..ecca6de8eb6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/FullStackRefreshEvent.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+/**
+ * Indicates the end of a sequence of steps. Should be handled like a suspended
+ * event to trigger a full refresh of stack frames.
+ *
+ * @since 1.1
+ */
+public class FullStackRefreshEvent extends AbstractDMEvent<IExecutionDMContext> {
+
+ public FullStackRefreshEvent(IExecutionDMContext execCtx) {
+ super(execCtx);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java
new file mode 100644
index 00000000000..faed099a305
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchRootVMNode.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.RootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IDebugElement;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ * Layout node for the standard ILaunch object. This node can only be used at
+ * the root of a hierarchy. It does not implement the label provider
+ * functionality, so the default adapters should be used to retrieve the label.
+ */
+@SuppressWarnings("restriction")
+public class LaunchRootVMNode extends RootVMNode
+ implements IRootVMNode
+{
+ public static class LaunchesEvent {
+ public enum Type { ADDED, REMOVED, CHANGED, TERMINATED }
+ public final ILaunch[] fLaunches;
+ public final Type fType;
+
+ public LaunchesEvent(ILaunch[] launches, Type type) {
+ fLaunches = launches;
+ fType = type;
+ }
+ }
+
+
+ public LaunchRootVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public String toString() {
+ return "LaunchRootVMNode"; //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean isDeltaEvent(Object rootObject, Object e) {
+ if (e instanceof DebugEvent) {
+ DebugEvent de = (DebugEvent)e;
+ if (de.getSource() instanceof IProcess &&
+ !((IProcess)de.getSource()).getLaunch().equals(rootObject) )
+ {
+ return false;
+ }
+ else if (de.getSource() instanceof IDebugElement &&
+ !rootObject.equals(((IDebugElement)de.getSource()).getLaunch()))
+ {
+ return false;
+ }
+ }
+ return super.isDeltaEvent(rootObject, e);
+ }
+
+ @Override
+ public int getDeltaFlags(Object e) {
+ int flags = 0;
+ if (e instanceof LaunchesEvent) {
+ LaunchesEvent le = (LaunchesEvent)e;
+ if (le.fType == LaunchesEvent.Type.CHANGED || le.fType == LaunchesEvent.Type.TERMINATED) {
+ flags = IModelDelta.STATE | IModelDelta.CONTENT;
+ }
+ }
+
+ return flags;
+ }
+
+ @Override
+ public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<VMDelta> rm) {
+ if (!(rootObject instanceof ILaunch)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Invalid root element configured with launch root node.", null)); //$NON-NLS-1$
+ return;
+ }
+
+ ILaunch rootLaunch = (ILaunch)rootObject;
+
+ /*
+ * Create the root of the delta. Since the launch object is not at the
+ * root of the view, create the delta with the path to the launch.
+ */
+ ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
+ List<ILaunch> launchList = Arrays.asList(manager.getLaunches());
+ final VMDelta viewRootDelta = new VMDelta(manager, 0, IModelDelta.NO_CHANGE, launchList.size());
+ final VMDelta rootDelta = viewRootDelta.addNode(rootLaunch, launchList.indexOf(rootLaunch), IModelDelta.NO_CHANGE);
+
+ // Generate delta for launch node.
+ if (event instanceof LaunchesEvent) {
+ LaunchesEvent le = (LaunchesEvent)event;
+ for (ILaunch launch : le.fLaunches) {
+ if (rootLaunch == launch) {
+ if (le.fType == LaunchesEvent.Type.CHANGED) {
+ rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT);
+ } else if (le.fType == LaunchesEvent.Type.TERMINATED) {
+ rootDelta.setFlags(rootDelta.getFlags() | IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+ }
+ }
+ }
+
+ rm.setData(rootDelta);
+ rm.done();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java
new file mode 100644
index 00000000000..0a5db99385e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/LaunchVMUpdateMessages.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * @since 1.1
+ */
+public class LaunchVMUpdateMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.LaunchVMUpdateMessages";//$NON-NLS-1$
+
+ public static String ThreadsAutomaticUpdatePolicy_name;
+ public static String ThreadsManualUpdatePolicy_name;
+
+ static {
+ // load message values from bundle file
+ NLS.initializeMessages(BUNDLE_NAME, LaunchVMUpdateMessages.class);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java
new file mode 100644
index 00000000000..957f25598f1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StackFramesVMNode.java
@@ -0,0 +1,724 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack2;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController.SteppingTimedOutEvent;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.ModelProxyInstalledEvent;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.ui.IMemento;
+
+@SuppressWarnings("restriction")
+public class StackFramesVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider, IElementMementoProvider
+{
+
+ /**
+ * View model context representing the end of an incomplete stack.
+ *
+ * @since 1.1
+ */
+ public class IncompleteStackVMContext extends AbstractVMContext {
+ private final int fLevel;
+ private final IExecutionDMContext fDmc;
+
+ public IncompleteStackVMContext(IExecutionDMContext dmc, int level) {
+ super(StackFramesVMNode.this);
+ fDmc = dmc;
+ fLevel = level;
+ }
+ public int getLevel() {
+ return fLevel;
+ }
+ public IExecutionDMContext getExecutionDMContext() {
+ return fDmc;
+ }
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof IncompleteStackVMContext &&
+ ((IncompleteStackVMContext)obj).fDmc.equals(fDmc);
+ }
+
+ @Override
+ public int hashCode() {
+ return fDmc.hashCode();
+ }
+ }
+
+ /**
+ * Temporary stack frame limit to allow incremental stack updates.
+ */
+ private Map<IExecutionDMContext, Integer> fTemporaryLimits = new HashMap<IExecutionDMContext, Integer>();
+
+ public StackFramesVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, IStack.IFrameDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "StackFramesVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateHasElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate)
+ */
+ @Override
+ protected void updateHasElementsInSessionThread(IHasChildrenUpdate update) {
+ IRunControl runControl = getServicesTracker().getService(IRunControl.class);
+ IExecutionDMContext execCtx = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
+ if (runControl == null || execCtx == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ update.setHasChilren(runControl.isSuspended(execCtx) || runControl.isStepping(execCtx));
+ update.done();
+ }
+
+ @Override
+ protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
+ IStack stackService = getServicesTracker().getService(IStack.class);
+ final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
+ if (stackService == null || execDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ final int stackFrameLimit= getStackFrameLimit(execDmc);
+ stackService.getStackDepth(
+ execDmc, stackFrameLimit == Integer.MAX_VALUE ? 0 : stackFrameLimit + 1,
+ new ViewerDataRequestMonitor<Integer>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ int stackDepth= getData();
+ if (stackFrameLimit < stackDepth) {
+ stackDepth = stackFrameLimit + 1;
+ }
+ update.setChildCount(stackDepth);
+ update.done();
+ }
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
+ */
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ IStack stackService = getServicesTracker().getService(IStack.class);
+ final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
+ if (stackService == null || execDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ final int stackFrameLimit= getStackFrameLimit(execDmc);
+ final int startIndex= update.getOffset();
+
+ if (startIndex == 0 && update.getLength() == 1) {
+ // Requesting top stack frame only
+ stackService.getTopFrame(
+ execDmc,
+ new ViewerDataRequestMonitor<IFrameDMContext>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ update.setChild(createVMContext(getData()), 0);
+ update.done();
+ }
+ });
+
+ } else {
+ if (startIndex >= 0 && update.getLength() > 0 && stackService instanceof IStack2) {
+ // partial stack dump
+ IStack2 stackService2= (IStack2) stackService;
+ int endIndex= startIndex + update.getLength() - 1;
+ if (startIndex < stackFrameLimit && endIndex >= stackFrameLimit) {
+ endIndex = stackFrameLimit - 1;
+ }
+ stackService2.getFrames(
+ execDmc,
+ startIndex,
+ endIndex,
+ new ViewerDataRequestMonitor<IFrameDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ IFrameDMContext[] frames = getData();
+ fillUpdateWithVMCs(update, frames, startIndex);
+ if (startIndex + update.getLength() > stackFrameLimit) {
+ update.setChild(new IncompleteStackVMContext(execDmc, stackFrameLimit), stackFrameLimit);
+ }
+ update.done();
+ }
+ });
+ } else {
+ // full stack dump
+ stackService.getFrames(
+ execDmc,
+ new ViewerDataRequestMonitor<IFrameDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ IFrameDMContext[] frames = getData();
+ if (frames.length > stackFrameLimit) {
+ IFrameDMContext[] tmpFrames = new IFrameDMContext[stackFrameLimit];
+ System.arraycopy(frames, 0, tmpFrames, 0, stackFrameLimit);
+ frames = tmpFrames;
+ update.setChild(new IncompleteStackVMContext(execDmc, stackFrameLimit), stackFrameLimit);
+ }
+ fillUpdateWithVMCs(update, frames);
+ update.done();
+ }
+ });
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
+ */
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+ IStack stackService = getServicesTracker().getService(IStack.class);
+
+ if (stackService == null) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ if (update.getElement() instanceof IncompleteStackVMContext) {
+ update.setLabel("<...more frames...>", 0); //$NON-NLS-1$
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(IDebugUIConstants.IMG_OBJS_STACKFRAME), 0);
+ update.done();
+ continue;
+ }
+
+ final IFrameDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
+ if (dmc == null) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ getDMVMProvider().getModelData(
+ this, update,
+ getServicesTracker().getService(IStack.class, null),
+ dmc,
+ new ViewerDataRequestMonitor<IFrameDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * Check that the request was evaluated and data is still
+ * valid. The request could fail if the state of the
+ * service changed during the request, but the view model
+ * has not been updated yet.
+ */
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+ handleFailedUpdate(update);
+ return;
+ }
+
+ /*
+ * If columns are configured, call the protected methods to
+ * fill in column values.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null) localColumns = new String[] { null };
+
+ for (int i = 0; i < localColumns.length; i++) {
+ fillColumnLabel(dmc, getData(), localColumns[i], i, update);
+ }
+ update.done();
+ }
+ },
+ getExecutor());
+ }
+ }
+
+ protected void fillColumnLabel(IFrameDMContext dmContext, IFrameDMData dmData, String columnId, int idx, ILabelUpdate update)
+ {
+ if (idx != 0) return;
+
+ final IExecutionDMContext execDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExecutionDMContext.class);
+ if (execDmc == null) {
+ return;
+ }
+ IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
+ SteppingController stepQueueMgr = (SteppingController) execDmc.getAdapter(SteppingController.class);
+ if (runControlService == null || stepQueueMgr == null) return;
+
+ String imageKey = null;
+ if (runControlService.isSuspended(execDmc) ||
+ (runControlService.isStepping(execDmc) && !stepQueueMgr.isSteppingTimedOut(execDmc)))
+ {
+ imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME;
+ } else {
+ imageKey = IDebugUIConstants.IMG_OBJS_STACKFRAME_RUNNING;
+ }
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+ //
+ // Finally, if all goes well, set the label.
+ //
+ StringBuilder label = new StringBuilder();
+
+ // Add the function name
+ if (dmData.getFunction() != null && dmData.getFunction().length() != 0) {
+ label.append(" "); //$NON-NLS-1$
+ label.append(dmData.getFunction());
+ label.append("()"); //$NON-NLS-1$
+ }
+
+ // Add full file name
+ if (dmData.getFile() != null && dmData.getFile().length() != 0) {
+ label.append(" at "); //$NON-NLS-1$
+ label.append(dmData.getFile());
+ }
+
+ // Add line number
+ if (dmData.getLine() >= 0) {
+ label.append(":"); //$NON-NLS-1$
+ label.append(dmData.getLine());
+ label.append(" "); //$NON-NLS-1$
+ }
+
+ // Add the address
+ if (dmData.getAddress() != null) {
+ label.append("- 0x" + dmData.getAddress().toString(16)); //$NON-NLS-1$
+ }
+
+ // Set the label to the result listener
+ update.setLabel(label.toString(), 0);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#getContextsForEvent(org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, java.lang.Object, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ @Override
+ public void getContextsForEvent(final VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) {
+ if (e instanceof ModelProxyInstalledEvent) {
+ // Retrieve the list of stack frames, and mark the top frame to be selected.
+ getVMProvider().updateNode(
+ this,
+ new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), 0, 1,
+ new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+ if (isSuccess() && getData().size() != 0) {
+ rm.setData(new IVMContext[] { (IVMContext)getData().get(0) });
+ } else {
+ // In case of errors, return an empty set of frames.
+ rm.setData(new IVMContext[0]);
+ }
+ rm.done();
+ }
+ })
+ );
+ return;
+ }
+ super.getContextsForEvent(parentDelta, e, rm);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
+ */
+ public int getDeltaFlags(Object e) {
+ // This node generates delta if the timers have changed, or if the
+ // label has changed.
+ if (e instanceof ISuspendedDMEvent) {
+ return IModelDelta.CONTENT | IModelDelta.EXPAND | IModelDelta.SELECT;
+ } else if (e instanceof FullStackRefreshEvent) {
+ return IModelDelta.CONTENT | IModelDelta.EXPAND;
+ } else if (e instanceof SteppingTimedOutEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof ModelProxyInstalledEvent) {
+ return IModelDelta.SELECT | IModelDelta.EXPAND;
+ } else if (e instanceof ExpandStackEvent) {
+ return IModelDelta.CONTENT;
+ } else if (e instanceof IExitedDMEvent) {
+ // Do not generate a delta for this event, but do clear the
+ // internal stack frame limit to avoid a memory leak.
+ clearStackFrameLimit( ((IExitedDMEvent)e).getDMContext() );
+ return IModelDelta.NO_CHANGE;
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property)
+ || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property))
+ {
+ return IModelDelta.CONTENT;
+ }
+ } else {
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, int, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDelta(final Object e, final VMDelta parent, final int nodeOffset, final RequestMonitor rm) {
+ if (e instanceof IContainerSuspendedDMEvent) {
+ // Clear the limit on the stack frames for all stack frames under a given container.
+ clearStackFrameLimit( ((IContainerSuspendedDMEvent)e).getDMContext() );
+
+ IContainerSuspendedDMEvent csEvent = (IContainerSuspendedDMEvent)e;
+
+ IExecutionDMContext triggeringCtx = csEvent.getTriggeringContexts().length != 0
+ ? csEvent.getTriggeringContexts()[0] : null;
+
+ if (parent.getElement() instanceof IDMVMContext) {
+ IExecutionDMContext threadDmc = null;
+ threadDmc = DMContexts.getAncestorOfType( ((IDMVMContext)parent.getElement()).getDMContext(), IExecutionDMContext.class);
+ buildDeltaForSuspendedEvent(threadDmc, triggeringCtx, parent, nodeOffset, rm);
+ } else {
+ rm.done();
+ }
+ } else if (e instanceof FullStackRefreshEvent) {
+ IExecutionDMContext execDmc = ((FullStackRefreshEvent)e).getDMContext();
+ buildDeltaForFullStackRefreshEvent(execDmc, execDmc, parent, nodeOffset, rm);
+ } else if (e instanceof ISuspendedDMEvent) {
+ clearStackFrameLimit( ((ISuspendedDMEvent)e).getDMContext() );
+ IExecutionDMContext execDmc = ((ISuspendedDMEvent)e).getDMContext();
+ buildDeltaForSuspendedEvent(execDmc, execDmc, parent, nodeOffset, rm);
+ } else if (e instanceof SteppingTimedOutEvent) {
+ buildDeltaForSteppingTimedOutEvent((SteppingTimedOutEvent)e, parent, nodeOffset, rm);
+ } else if (e instanceof ISteppingTimedOutEvent) {
+ buildDeltaForSteppingTimedOutEvent((ISteppingTimedOutEvent)e, parent, nodeOffset, rm);
+ } else if (e instanceof ModelProxyInstalledEvent) {
+ buildDeltaForModelProxyInstalledEvent(parent, nodeOffset, rm);
+ } else if (e instanceof ExpandStackEvent) {
+ IExecutionDMContext execDmc = ((ExpandStackEvent)e).getDMContext();
+ buildDeltaForExpandStackEvent(execDmc, parent, rm);
+ } else if (e instanceof PropertyChangeEvent) {
+ String property = ((PropertyChangeEvent)e).getProperty();
+ if (IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT_ENABLE.equals(property)
+ || IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT.equals(property))
+ {
+ buildDeltaForStackFrameLimitPreferenceChangedEvent(parent, rm);
+ } else {
+ rm.done();
+ }
+ } else {
+ rm.done();
+ }
+ }
+
+ private void buildDeltaForSuspendedEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
+ IStack stackService = getServicesTracker().getService(IStack.class);
+ if (stackService == null || runControlService == null) {
+ // Required services have not initialized yet. Ignore the event.
+ rm.done();
+ return;
+ }
+
+ // Check if we are building a delta for the thread that triggered the event.
+ // Only then expand the stack frames and select the top one.
+ if (executionCtx.equals(triggeringCtx)) {
+ // Always expand the thread node to show the stack frames.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
+
+ // Retrieve the list of stack frames, and mark the top frame to be selected.
+ getVMProvider().updateNode(
+ this,
+ new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), 0, 2,
+ new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+ final List<Object> data= getData();
+ if (data != null && data.size() != 0) {
+ parentDelta.addNode(data.get(0), 0, IModelDelta.SELECT | IModelDelta.STATE);
+
+ // Refresh the whole list of stack frames unless the target is already stepping the next command. In
+ // which case, the refresh will occur when the stepping sequence slows down or stops. Trying to
+ // refresh the whole stack trace with every step would slow down stepping too much.
+ IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
+ if (runControlService != null &&
+ triggeringCtx != null && runControlService.isStepping(triggeringCtx) &&
+ data.size() >= 2)
+ {
+ parentDelta.addNode( data.get(1), 1, IModelDelta.STATE);
+ }
+ }
+ // Even in case of errors, complete the request monitor.
+ rm.done();
+ }
+ })
+ );
+ } else {
+ rm.done();
+ }
+ }
+
+ private void buildDeltaForFullStackRefreshEvent(final IExecutionDMContext executionCtx, final IExecutionDMContext triggeringCtx, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ IRunControl runControlService = getServicesTracker().getService(IRunControl.class);
+ IStack stackService = getServicesTracker().getService(IStack.class);
+ if (stackService == null || runControlService == null) {
+ // Required services have not initialized yet. Ignore the event.
+ rm.done();
+ return;
+ }
+
+ // Refresh the whole list of stack frames unless the target is already stepping the next command. In
+ // which case, the refresh will occur when the stepping sequence slows down or stops. Trying to
+ // refresh the whole stack trace with every step would slow down stepping too much.
+ if (triggeringCtx == null || !runControlService.isStepping(triggeringCtx)) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+
+ private void buildDeltaForSteppingTimedOutEvent(final SteppingTimedOutEvent e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ // Repaint the stack frame images to have the running symbol.
+ //parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ rm.done();
+ }
+
+ private void buildDeltaForSteppingTimedOutEvent(final ISteppingTimedOutEvent e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ // Repaint the stack frame images to have the running symbol.
+ //parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ rm.done();
+ }
+
+ private void buildDeltaForModelProxyInstalledEvent(final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+ // Retrieve the list of stack frames, and mark the top frame to be selected.
+ getVMProvider().updateNode(
+ this,
+ new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), -1, -1,
+ new DataRequestMonitor<List<Object>>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+ if (isSuccess() && getData().size() != 0) {
+ parentDelta.addNode( getData().get(0), 0, IModelDelta.SELECT | IModelDelta.EXPAND);
+ }
+ rm.done();
+ }
+ })
+ );
+ }
+
+ private void buildDeltaForExpandStackEvent(IExecutionDMContext execDmc, final VMDelta parentDelta, final RequestMonitor rm) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ rm.done();
+ }
+
+
+ private void buildDeltaForStackFrameLimitPreferenceChangedEvent(final VMDelta parentDelta, final RequestMonitor rm) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ rm.done();
+ }
+
+ private String produceFrameElementName( String viewName , IFrameDMContext frame ) {
+ /*
+ * We are addressing Bugzilla 211490 which wants the Register View to keep the same expanded
+ * state for registers for stack frames within the same thread. Different threads could have
+ * different register sets ( e.g. one thread may have floating point & another may not ). But
+ * within a thread we are enforcing the assumption that the register sets will be the same.
+ * So we make a more convenient work flow by keeping the same expansion when selecting amount
+ * stack frames within the same thread. We accomplish this by only differentiating by adding
+ * the level for the Expression/Variables view. Otherwise we do not delineate based on which
+ * view and this captures the Register View in its filter.
+ */
+ if ( viewName.startsWith(IDebugUIConstants.ID_VARIABLE_VIEW) ||
+ viewName.startsWith(IDebugUIConstants.ID_EXPRESSION_VIEW) )
+ {
+ return "Frame." + frame.getLevel() + "." + frame.getSessionId(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ else {
+ return "Frame" + frame.getSessionId(); //$NON-NLS-1$
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ public void compareElements(IElementCompareRequest[] requests) {
+
+ for ( IElementCompareRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ String mementoName = memento.getString("STACK_FRAME_MEMENTO_NAME"); //$NON-NLS-1$
+
+ if (mementoName != null) {
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof IFrameDMContext) {
+
+ String elementName = produceFrameElementName( request.getPresentationContext().getId(), (IFrameDMContext) dmc );
+ request.setEqual( elementName.equals( mementoName ) );
+ }
+ }
+ }
+ request.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+
+ for ( IElementMementoRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof IFrameDMContext) {
+
+ String elementName = produceFrameElementName( request.getPresentationContext().getId(), (IFrameDMContext) dmc );
+ memento.putString("STACK_FRAME_MEMENTO_NAME", elementName); //$NON-NLS-1$
+ }
+ }
+ request.done();
+ }
+ }
+
+ /**
+ * Get the current active stack frame limit. If no limit is applicable {@link Integer.MAX_VALUE} is returned.
+ *
+ * @return the current stack frame limit
+ *
+ * @since 1.1
+ */
+ public int getStackFrameLimit(IExecutionDMContext execCtx) {
+ if (fTemporaryLimits.containsKey(execCtx)) {
+ return fTemporaryLimits.get(execCtx);
+ }
+ Object stackDepthLimit= getVMProvider().getPresentationContext().getProperty(IDsfDebugUIConstants.PREF_STACK_FRAME_LIMIT);
+ if (stackDepthLimit instanceof Integer) {
+ return (Integer)stackDepthLimit;
+ }
+ return Integer.MAX_VALUE;
+ }
+
+ private void clearStackFrameLimit(IExecutionDMContext execCtx) {
+ if (execCtx instanceof IContainerDMContext) {
+ for (Iterator<IExecutionDMContext> itr = fTemporaryLimits.keySet().iterator(); itr.hasNext();) {
+ IExecutionDMContext limitCtx = itr.next();
+ if (limitCtx.equals(execCtx) || DMContexts.isAncestorOf(limitCtx, execCtx)) {
+ itr.remove();
+ }
+ }
+ } else {
+ fTemporaryLimits.remove(execCtx);
+ }
+ }
+
+
+ /**
+ * Increment the stack frame limit by the default increment.
+ * This implementation doubles the current limit.
+ *
+ * @since 1.1
+ */
+ public void incrementStackFrameLimit(IExecutionDMContext execCtx) {
+ final int stackFrameLimit= getStackFrameLimit(execCtx);
+ if (stackFrameLimit < Integer.MAX_VALUE / 2) {
+ fTemporaryLimits.put(execCtx, stackFrameLimit * 2);
+ } else {
+ fTemporaryLimits.put(execCtx, Integer.MAX_VALUE);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java
new file mode 100644
index 00000000000..5e0e7212e23
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/StandardProcessVMNode.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.IStreamsProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Layout node for the standard platform debug model IProcess object. This
+ * node requires that an ILaunch object be found as an ancestor of this node.
+ * It does not implement the label provider functionality, so the default
+ * adapters should be used to retrieve the label.
+ */
+@SuppressWarnings("restriction")
+public class StandardProcessVMNode extends AbstractVMNode {
+
+ /**
+ * VMC element implementation, it is a proxy for the IProcess class, to
+ * allow the standard label adapter to be used with this object.
+ */
+ private class VMC extends AbstractVMContext
+ implements IProcess
+ {
+ private final IProcess fProcess;
+
+ VMC(IProcess process) {
+ super(StandardProcessVMNode.this);
+ fProcess = process;
+ }
+
+ @Override
+ public IVMNode getVMNode() { return StandardProcessVMNode.this; }
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ Object vmcAdapter = super.getAdapter(adapter);
+ if (vmcAdapter != null) {
+ return vmcAdapter;
+ }
+ return fProcess.getAdapter(adapter);
+ }
+ @Override
+ public String toString() { return "IProcess " + fProcess.toString(); } //$NON-NLS-1$
+
+ public String getAttribute(String key) { return fProcess.getAttribute(key); }
+ public int getExitValue() throws DebugException { return fProcess.getExitValue(); }
+ public String getLabel() { return fProcess.getLabel(); }
+ public ILaunch getLaunch() { return fProcess.getLaunch(); }
+ public IStreamsProxy getStreamsProxy() { return fProcess.getStreamsProxy(); }
+ public void setAttribute(String key, String value) { fProcess.setAttribute(key, value); }
+ public boolean canTerminate() { return fProcess.canTerminate(); }
+ public boolean isTerminated() { return fProcess.isTerminated(); }
+ public void terminate() throws DebugException { fProcess.terminate(); }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof VMC && fProcess.equals(((VMC)other).fProcess);
+ }
+ @Override
+ public int hashCode() { return fProcess.hashCode(); }
+ }
+
+ public StandardProcessVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public String toString() {
+ return "StandardProcessVMNode"; //$NON-NLS-1$
+ }
+
+ public void update(IChildrenUpdate[] updates) {
+ for (IChildrenUpdate update : updates) {
+ ILaunch launch = findLaunch(update.getElementPath());
+ if (launch == null) {
+ // There is no launch in the parent of this node. This means that the
+ // layout is misconfigured.
+ assert false;
+ update.done();
+ continue;
+ }
+
+ /*
+ * Assume that the process objects are stored within the launch, and
+ * retrieve them on dispatch thread.
+ */
+ IProcess[] processes = launch.getProcesses();
+ for (int i = 0; i < processes.length; i++) {
+ update.setChild(new VMC(processes[i]), i);
+ }
+ update.done();
+ }
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ for (IChildrenCountUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ ILaunch launch = findLaunch(update.getElementPath());
+ if (launch == null) {
+ assert false;
+ update.setChildCount(0);
+ update.done();
+ return;
+ }
+
+ update.setChildCount(launch.getProcesses().length);
+ update.done();
+ }
+ }
+
+ // @see org.eclipse.cdt.dsf.ui.viewmodel.IViewModelLayoutNode#hasElements(org.eclipse.cdt.dsf.ui.viewmodel.IVMContext, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ public void update(IHasChildrenUpdate[] updates) {
+ for (IHasChildrenUpdate update : updates) {
+ ILaunch launch = findLaunch(update.getElementPath());
+ if (launch == null) {
+ assert false;
+ update.setHasChilren(false);
+ update.done();
+ return;
+ }
+
+ update.setHasChilren(launch.getProcesses().length != 0);
+ update.done();
+ }
+ }
+
+ // @see org.eclipse.cdt.dsf.ui.viewmodel.IViewModelLayoutNode#retrieveLabel(org.eclipse.cdt.dsf.ui.viewmodel.IVMContext, org.eclipse.debug.internal.ui.viewers.provisional.ILabelRequestMonitor)
+ public void updateLabel(IVMContext vmc, ILabelRequestMonitor result, String[] columns) {
+
+ /*
+ * The implementation of IAdapterFactory that uses this node should not
+ * register a label adapter for IProcess. This will cause the default
+ * label provider to be used instead, and this method should then never
+ * be called.
+ */
+ assert false;
+ result.done();
+ }
+
+ /**
+ * Recursively searches the VMC for Launch VMC, and returns its ILaunch.
+ * Returns null if an ILaunch is not found.
+ */
+ private ILaunch findLaunch(TreePath path) {
+ for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
+ if (path.getSegment(i) instanceof ILaunch) {
+ return (ILaunch)path.getSegment(i);
+ }
+ }
+ return null;
+ }
+
+ public int getDeltaFlags(Object e) {
+ int myFlags = 0;
+ if (e instanceof DebugEvent) {
+ DebugEvent de = (DebugEvent)e;
+ if ( de.getSource() instanceof IProcess &&
+ (de.getKind() == DebugEvent.CHANGE ||
+ de.getKind() == DebugEvent.CREATE ||
+ de.getKind() == DebugEvent.TERMINATE) )
+ {
+ myFlags = IModelDelta.STATE;
+ }
+ }
+ return myFlags;
+ }
+
+ public void buildDelta(Object e, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor) {
+ if (e instanceof DebugEvent && ((DebugEvent)e).getSource() instanceof IProcess) {
+ DebugEvent de = (DebugEvent)e;
+ if (de.getKind() == DebugEvent.CHANGE) {
+ handleChange(de, parent);
+ } else if (de.getKind() == DebugEvent.CREATE) {
+ handleCreate(de, parent);
+ } else if (de.getKind() == DebugEvent.TERMINATE) {
+ handleTerminate(de, parent);
+ }
+ /*
+ * No other node should need to process events related to process.
+ * Therefore, just invoke the request monitor without calling super.buildDelta().
+ */
+ }
+ requestMonitor.done();
+ }
+
+ protected void handleChange(DebugEvent event, ModelDelta parent) {
+ parent.addNode(new VMC((IProcess)event.getSource()), IModelDelta.STATE);
+ }
+
+ protected void handleCreate(DebugEvent event, ModelDelta parent) {
+ parent.setFlags(parent.getFlags() | IModelDelta.CONTENT);
+ }
+
+ protected void handleTerminate(DebugEvent event, ModelDelta parent) {
+ handleChange(event, parent);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java
new file mode 100644
index 00000000000..665d6e9f109
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/launch/actions/ExpandStackAction.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.ui.viewmodel.launch.actions;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.AbstractVMProviderActionDelegate;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.AbstractLaunchVMProvider;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.ExpandStackEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode.IncompleteStackVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.debug.ui.contexts.DebugContextEvent;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Increment the (temporary) stack limit for the selected stack.
+ */
+public class ExpandStackAction extends AbstractVMProviderActionDelegate implements IObjectActionDelegate {
+
+ /*
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ Object element = getViewerInput();
+ if (element instanceof IncompleteStackVMContext) {
+ IncompleteStackVMContext incStackVmc = ((IncompleteStackVMContext) element);
+ IVMNode node = incStackVmc.getVMNode();
+ if (incStackVmc.getVMNode() instanceof StackFramesVMNode) {
+ final IExecutionDMContext exeCtx= incStackVmc.getExecutionDMContext();
+ ((StackFramesVMNode) node).incrementStackFrameLimit(exeCtx);
+ final ExpandStackEvent event = new ExpandStackEvent(exeCtx);
+ final AbstractLaunchVMProvider vmProvider = (AbstractLaunchVMProvider) getVMProvider();
+ vmProvider.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ vmProvider.handleEvent(event);
+ }
+ });
+ }
+ }
+ }
+
+ @Override
+ public void init(IViewPart view) {
+ super.init(view);
+ updateEnablement();
+ }
+
+ @Override
+ public void debugContextChanged(DebugContextEvent event) {
+ super.debugContextChanged(event);
+ updateEnablement();
+ }
+
+ @Override
+ public void selectionChanged(IAction action, ISelection selection) {
+ super.selectionChanged(action, selection);
+ updateEnablement();
+ }
+
+ private void updateEnablement() {
+ boolean enabled = false;
+ if (getVMProvider() instanceof AbstractLaunchVMProvider) {
+ Object element = getViewerInput();
+ enabled = element instanceof IncompleteStackVMContext;
+ }
+ getAction().setEnabled(enabled);
+ }
+
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ if (targetPart instanceof IViewPart) {
+ init((IViewPart) targetPart);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMNode.java
new file mode 100644
index 00000000000..83c9bbe2e4c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMNode.java
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson AB - Modules view for DSF implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMData;
+import org.eclipse.cdt.dsf.debug.service.IModules.ISymbolDMContext;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+@SuppressWarnings("restriction")
+public class ModulesVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider
+{
+ /**
+ * Marker type for the modules VM context. It allows action enablement
+ * expressions to check for module context type.
+ */
+ public class ModuleVMContext extends DMVMContext {
+ protected ModuleVMContext(IDMContext dmc) {
+ super(dmc);
+ }
+ }
+
+
+ public ModulesVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, IModuleDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "ModulesVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ IModules modulesService = getServicesTracker().getService(IModules.class);
+ final ISymbolDMContext symDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), ISymbolDMContext.class) ;
+
+ if (modulesService == null || symDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ modulesService.getModules(
+ symDmc,
+ new ViewerDataRequestMonitor<IModuleDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ update.done();
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }});
+ }
+
+ @Override
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new ModuleVMContext(dmc);
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+ IModules modulesService = getServicesTracker().getService(IModules.class);
+ final IModuleDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IModuleDMContext.class);
+ // If either update or service are not valid, fail the update and exit.
+ if ( modulesService == null || dmc == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ // Use different image for loaded and unloaded symbols when event to report loading of symbols is implemented.
+ update.setImageDescriptor(DsfUIPlugin.getImageDescriptor(IDsfDebugUIConstants.IMG_OBJS_SHARED_LIBRARY_SYMBOLS_LOADED), 0);
+
+ modulesService.getModuleData(
+ dmc,
+ new ViewerDataRequestMonitor<IModuleDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * The request could fail if the state of the service
+ * changed during the request, but the view model
+ * has not been updated yet.
+ */
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+ handleFailedUpdate(update);
+ return;
+ }
+
+ /*
+ * If columns are configured, call the protected methods to
+ * fill in column values.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null) localColumns = new String[] { null };
+
+ for (int i = 0; i < localColumns.length; i++) {
+ fillColumnLabel(dmc, getData(), localColumns[i], i, update);
+ }
+ update.done();
+ }
+ });
+ }
+ }
+
+ protected void fillColumnLabel(IModuleDMContext dmContext, IModuleDMData dmData,
+ String columnId, int idx, ILabelUpdate update)
+ {
+ if ( columnId == null ) {
+ /*
+ * If the Column ID comes in as "null" then this is the case where the user has decided
+ * to not have any columns. So we need a default action which makes the most sense and
+ * is doable. In this case we elect to simply display the name.
+ */
+ update.setLabel(dmData.getName(), idx);
+ }
+ }
+
+ public int getDeltaFlags(Object e) {
+ if (e instanceof IRunControl.ISuspendedDMEvent) {
+ return IModelDelta.CONTENT;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
+ if (e instanceof IRunControl.ISuspendedDMEvent) {
+ // Create a delta that indicates all groups have changed
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMProvider.java
new file mode 100644
index 00000000000..fc713683cdc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/ModulesVMProvider.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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
+ * Ericsson AB - Modules view for DSF implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class ModulesVMProvider extends AbstractDMVMProvider {
+ /*
+ * Current default for register formatting.
+ */
+ public ModulesVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
+ super(adapter, context, session);
+
+ /*
+ * Create the top level node to deal with the root selection.
+ */
+ IRootVMNode rootNode = new RootDMVMNode(this);
+
+ /*
+ * Create the Group nodes next. They represent the first level shown in the view.
+ */
+ IVMNode modulesNode = new ModulesVMNode(this, getSession());
+ addChildNodes(rootNode, new IVMNode[] { modulesNode });
+
+ /*
+ * Now set this schema set as the layout set.
+ */
+ setRootNode(rootNode);
+ }
+
+ @Override
+ public void refresh() {
+ super.refresh();
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), getSession().getId());
+ IModules modulesService = tracker.getService(IModules.class);
+ if (modulesService instanceof ICachingService) {
+ ((ICachingService)modulesService).flushCache(null);
+ }
+ tracker.dispose();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session disposed, ignore.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPane.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPane.java
new file mode 100644
index 00000000000..f014c8f4c7b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPane.java
@@ -0,0 +1,525 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * QNX Software Systems - Mikhail Khodjaiants - Registers View (Bug 53640)
+ * Wind River Systems - adopted to use with Modules view
+ * Ericsson AB - Modules view for DSF implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail;
+
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.debug.ui.ICDebugUIConstants;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.MessagesForDetailPane;
+import org.eclipse.cdt.dsf.debug.internal.ui.viewmodel.detailsupport.TextViewerAction;
+import org.eclipse.cdt.dsf.debug.service.IModules;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMContext;
+import org.eclipse.cdt.dsf.debug.service.IModules.IModuleDMData;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.jface.action.IMenuListener;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.DocumentEvent;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IDocumentListener;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusAdapter;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.progress.WorkbenchJob;
+import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
+
+
+/**
+ *
+ */
+public class ModuleDetailPane extends ModulesAbstractDetailPane implements IAdaptable, IPropertyChangeListener {
+
+ /**
+ * These are the IDs for the actions in the context menu
+ */
+ protected static final String DETAIL_COPY_ACTION = ActionFactory.COPY.getId() + ".SourceDetailPane"; //$NON-NLS-1$
+ protected static final String DETAIL_SELECT_ALL_ACTION = IDebugView.SELECT_ALL_ACTION + ".SourceDetailPane"; //$NON-NLS-1$
+
+ /**
+ * The ID, name and description of this pane are stored in constants so that the class
+ * does not have to be instantiated to access them.
+ */
+ public static final String ID = "ModuleDetailPane"; //$NON-NLS-1$
+ public static final String NAME = "Module Viewer"; //$NON-NLS-1$
+ public static final String DESCRIPTION = "A detail pane that is based on a source viewer. Displays as text and has actions for assigning values, content assist and text modifications."; //$NON-NLS-1$
+
+
+ /**
+ * The source viewer in which the computed string detail
+ * of selected modules will be displayed.
+ */
+ private SourceViewer fSourceViewer;
+ public Control createControl(Composite parent) {
+ createSourceViewer(parent);
+
+ if (isInView()){
+ createViewSpecificComponents();
+ createActions();
+ DsfUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
+ JFaceResources.getFontRegistry().addListener(this);
+ }
+ return fSourceViewer.getControl();
+ }
+
+ private DetailJob fDetailJob = null;
+ public void display(IStructuredSelection selection) {
+ if (selection == null){
+ clearSourceViewer();
+ return;
+ }
+
+ if (isInView()){
+ fSourceViewer.setEditable(true);
+ }
+
+ if (selection.isEmpty()){
+ clearSourceViewer();
+ return;
+ }
+
+ synchronized (this) {
+ if (fDetailJob != null) {
+ fDetailJob.cancel();
+ }
+ fDetailJob = new DetailJob(selection.getFirstElement());
+ fDetailJob.schedule();
+ }
+
+ }
+
+ /**
+ * Clears the source viewer, removes all text.
+ */
+ protected void clearSourceViewer(){
+ if (fDetailJob != null) {
+ fDetailJob.cancel();
+ }
+ fDetailDocument.set(""); //$NON-NLS-1$
+ fSourceViewer.setEditable(false);
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (fDetailJob != null) fDetailJob.cancel();
+ if (fSourceViewer != null && fSourceViewer.getControl() != null) fSourceViewer.getControl().dispose();
+
+ if (isInView()){
+ DsfUIPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this);
+ JFaceResources.getFontRegistry().removeListener(this);
+ }
+
+ }
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+ public String getID() {
+ return ID;
+ }
+ public String getName() {
+ return NAME;
+ }
+
+ public boolean setFocus() {
+ if (fSourceViewer != null){
+ fSourceViewer.getTextWidget().setFocus();
+ return true;
+ }
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (ITextViewer.class.equals(adapter)) {
+ return fSourceViewer;
+ }
+ return null;
+ }
+
+ public void propertyChange(PropertyChangeEvent event) {
+ String propertyName= event.getProperty();
+ if (propertyName.equals(IDsfDebugUIConstants.DETAIL_PANE_FONT)) {
+ fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IDsfDebugUIConstants.DETAIL_PANE_FONT));
+ }
+ }
+
+
+ /**
+ * Creates the source viewer in the given parent composite
+ *
+ * @param parent Parent composite to create the source viewer in
+ */
+ private void createSourceViewer(Composite parent) {
+
+ // Create & configure a SourceViewer
+ fSourceViewer = new SourceViewer(parent, null, SWT.V_SCROLL | SWT.H_SCROLL);
+ fSourceViewer.setDocument(getDetailDocument());
+ fSourceViewer.getTextWidget().setFont(JFaceResources.getFont(IDsfDebugUIConstants.DETAIL_PANE_FONT));
+ fSourceViewer.getTextWidget().setWordWrap(DsfUIPlugin.getDefault().getPreferenceStore().getBoolean(IDsfDebugUIConstants.PREF_DETAIL_PANE_WORD_WRAP));
+ fSourceViewer.setEditable(false);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(fSourceViewer.getTextWidget(), IDsfDebugUIConstants.DETAIL_PANE);
+ Control control = fSourceViewer.getControl();
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ control.setLayoutData(gd);
+ }
+
+ /**
+ * Variables used to create the detailed information for a selection
+ */
+ private IDocument fDetailDocument;
+
+ /**
+ * Lazily instantiate and return a Document for the detail pane text viewer.
+ */
+ protected IDocument getDetailDocument() {
+ if (fDetailDocument == null) {
+ fDetailDocument = new Document();
+ }
+ return fDetailDocument;
+ }
+
+ /**
+ * Creates listeners and other components that should only be added to the
+ * source viewer when this detail pane is inside a view.
+ */
+ private void createViewSpecificComponents(){
+
+ // Add a document listener so actions get updated when the document changes
+ getDetailDocument().addDocumentListener(new IDocumentListener() {
+ public void documentAboutToBeChanged(DocumentEvent event) {}
+ public void documentChanged(DocumentEvent event) {
+ updateSelectionDependentActions();
+ }
+ });
+
+ // Add the selection listener so selection dependent actions get updated.
+ fSourceViewer.getSelectionProvider().addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ updateSelectionDependentActions();
+ }
+ });
+
+ // Add a focus listener to update actions when details area gains focus
+ fSourceViewer.getControl().addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ getViewSite().setSelectionProvider(fSourceViewer.getSelectionProvider());
+
+ setGlobalAction(IDebugView.SELECT_ALL_ACTION, getAction(DETAIL_SELECT_ALL_ACTION));
+ setGlobalAction(IDebugView.COPY_ACTION, getAction(DETAIL_COPY_ACTION));
+
+ getViewSite().getActionBars().updateActionBars();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ getViewSite().setSelectionProvider(null);
+
+ setGlobalAction(IDebugView.SELECT_ALL_ACTION, null);
+ setGlobalAction(IDebugView.COPY_ACTION, null);
+ getViewSite().getActionBars().updateActionBars();
+
+ }
+ });
+
+ // Add a context menu to the detail area
+ createDetailContextMenu(fSourceViewer.getTextWidget());
+ }
+
+ /**
+ * Create the context menu particular to the detail pane. Note that anyone
+ * wishing to contribute an action to this menu must use
+ * <code>ICDebugUIConstants.MODULES_VIEW_DETAIL_ID</code> as the
+ * <code>targetID</code> in the extension XML.
+ */
+ protected void createDetailContextMenu(Control menuControl) {
+ MenuManager menuMgr= new MenuManager();
+ menuMgr.setRemoveAllWhenShown(true);
+ menuMgr.addMenuListener(new IMenuListener() {
+ public void menuAboutToShow(IMenuManager mgr) {
+ fillDetailContextMenu(mgr);
+ }
+ });
+ Menu menu= menuMgr.createContextMenu(menuControl);
+ menuControl.setMenu(menu);
+
+ getViewSite().registerContextMenu(ICDebugUIConstants.MODULES_VIEW_DETAIL_ID, menuMgr, fSourceViewer.getSelectionProvider());
+
+ }
+ /**
+ * Adds items to the detail pane's context menu including any extension defined
+ * actions.
+ *
+ * @param menu The menu to add the item to.
+ */
+ protected void fillDetailContextMenu(IMenuManager menu) {
+
+ menu.add(new Separator(ICDebugUIConstants.MODULES_GROUP));
+ menu.add(new Separator());
+ menu.add(getAction(DETAIL_COPY_ACTION));
+ menu.add(getAction(DETAIL_SELECT_ALL_ACTION));
+ menu.add(new Separator());
+ menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+
+ }
+ /**
+ * Creates the actions to add to the context menu
+ */
+ private void createActions() {
+ TextViewerAction textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.SELECT_ALL);
+ textAction.configureAction(MessagesForDetailPane.DetailPane_Select_All, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDsfDebugUIConstants.DETAIL_PANE_SELECT_ALL_ACTION);
+ setAction(DETAIL_SELECT_ALL_ACTION, textAction);
+
+ textAction= new TextViewerAction(fSourceViewer, ITextOperationTarget.COPY);
+ textAction.configureAction(MessagesForDetailPane.DetailPane_Copy, "", ""); //$NON-NLS-1$ //$NON-NLS-2$
+ textAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(textAction, IDsfDebugUIConstants.DETAIL_PANE_COPY_ACTION);
+ setAction(DETAIL_COPY_ACTION, textAction);
+
+ setSelectionDependantAction(DETAIL_COPY_ACTION);
+
+ updateSelectionDependentActions();
+ }
+
+
+ /**
+ * Job to compute the details for a selection
+ */
+ class DetailJob extends Job {
+
+ private Object fElement;
+ // whether a result was collected
+ private IProgressMonitor fMonitor;
+
+ public DetailJob(Object element) {
+ super("compute module details"); //$NON-NLS-1$
+ setSystem(true);
+ fElement = element;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fMonitor = monitor;
+ /*
+ * Make sure this is an element we want to deal with.
+ */
+ IModuleDMContext dmc = null;
+ if (fElement instanceof IDMVMContext) {
+ IDMContext vmcdmc = ((IDMVMContext)fElement).getDMContext();
+ dmc = DMContexts.getAncestorOfType(vmcdmc, IModuleDMContext.class);
+ }
+
+ if (dmc == null) return Status.OK_STATUS;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return Status.OK_STATUS;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetModuleDetailsQuery query = new GetModuleDetailsQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ detailComputed(getModuleDetail((IModuleDMData) query.get()));
+ } catch (InterruptedException e) {
+ assert false;
+ return Status.OK_STATUS;
+ } catch (ExecutionException e) {
+ return Status.OK_STATUS;
+ }
+ return Status.OK_STATUS;
+ }
+
+ /**
+ * Set the module details in the detail pane view
+ * @param result
+ */
+ private void detailComputed(final String result) {
+ if (!fMonitor.isCanceled()) {
+ WorkbenchJob setDetail = new WorkbenchJob("set details") { //$NON-NLS-1$
+ @Override
+ public IStatus runInUIThread(IProgressMonitor monitor) {
+ if (!fMonitor.isCanceled()) {
+ getDetailDocument().set(result);
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ setDetail.setSystem(true);
+ setDetail.schedule();
+ }
+ }
+
+ }
+
+ /**
+ * To get the details of the given module selected in Modules View
+ * @param module
+ * @return
+ */
+ private String getModuleDetail( IModuleDMData module ) {
+ StringBuffer sb = new StringBuffer();
+
+ // Type
+ String type = null;
+// switch( module.getType() ) {
+// case ICModule.EXECUTABLE:
+// type = ModulesMessages.getString( "ModulesView.Executable" ); //$NON-NLS-1$
+// break;
+// case ICModule.SHARED_LIBRARY:
+// type = ModulesMessages.getString( "ModulesView.SharedLibrary" ); //$NON-NLS-1$
+// break;
+// }
+ type = ModulesMessages.getString( "ModulesView.SharedLibrary" ); //$NON-NLS-1$
+ if ( type != null ) {
+ sb.append( ModulesMessages.getString( "ModulesView.Type" ) ); //$NON-NLS-1$
+ sb.append( type );
+ sb.append( '\n' );
+ }
+
+ // Symbols flag
+ sb.append( ModulesMessages.getString( "ModulesView.Symbols" ) ); //$NON-NLS-1$
+ sb.append( ( module.isSymbolsLoaded()) ? ModulesMessages.getString( "ModulesView.Loaded" ) : ModulesMessages.getString( "ModulesView.NotLoaded" ) ); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append( '\n' );
+
+ // Symbols file
+ sb.append( ModulesMessages.getString( "ModulesView.SymbolsFile" ) ); //$NON-NLS-1$
+ sb.append( module.getFile());
+ sb.append( '\n' );
+
+ // Base address
+ String baseAddress = module.getBaseAddress();
+ sb.append( ModulesMessages.getString( "ModulesView.BaseAddress" ) ); //$NON-NLS-1$
+ sb.append( baseAddress );
+ sb.append( '\n' );
+
+ // Size
+ long size = module.getSize();
+ if ( size > 0 ) {
+ sb.append( ModulesMessages.getString( "ModulesView.Size" ) ); //$NON-NLS-1$
+ sb.append( size );
+ sb.append( '\n' );
+ }
+
+ return sb.toString();
+ }
+
+
+ public class GetModuleDetailsQuery extends Query<Object> {
+
+ private IModuleDMContext fDmc;
+
+ public GetModuleDetailsQuery(IModuleDMContext dmc) {
+ super();
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), fDmc.getSessionId());
+ IModules service = tracker.getService(IModules.class);
+ tracker.dispose();
+ if (service == null) {
+ rm .setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ service.getModuleData(fDmc, new DataRequestMonitor<IModuleDMData>( session.getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * We're in another dispatch, so we must guard against executor shutdown again.
+ */
+ if (!DsfSession.isSessionActive(session.getId())) {
+ GetModuleDetailsQuery.this.cancel(false);
+ return;
+ }
+ super.handleCompleted();
+ }
+
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPaneFactory.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPaneFactory.java
new file mode 100644
index 00000000000..e3796b39a23
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModuleDetailPaneFactory.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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:
+ * Ericsson AB - Modules view for DSF implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.debug.ui.IDetailPane;
+import org.eclipse.debug.ui.IDetailPaneFactory;
+import org.eclipse.jface.viewers.IStructuredSelection;
+
+public class ModuleDetailPaneFactory implements IDetailPaneFactory {
+ public static final String MODULE_DETAIL_PANE_ID = ModuleDetailPane.ID;
+ public IDetailPane createDetailPane(String paneID) {
+ return new ModuleDetailPane();
+ }
+
+ public String getDefaultDetailPane(IStructuredSelection selection) {
+ return null;
+ }
+
+ public String getDetailPaneDescription(String paneID) {
+ if (paneID.equals(ModuleDetailPane.ID)){
+ return ModuleDetailPane.DESCRIPTION;
+ }
+ return null;
+ }
+
+ public String getDetailPaneName(String paneID) {
+ if (paneID.equals(ModuleDetailPane.ID)){
+ return ModuleDetailPane.NAME;
+ }
+ return null;
+ }
+
+ public Set<?> getDetailPaneTypes(IStructuredSelection selection) {
+ Set<String> possibleIDs = new HashSet<String>(1);
+ possibleIDs.add(ModuleDetailPane.ID);
+ return possibleIDs;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesAbstractDetailPane.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesAbstractDetailPane.java
new file mode 100644
index 00000000000..277cfd054db
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesAbstractDetailPane.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ * Wind River Systems - adopted to use with Modules view
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.debug.ui.IDetailPane;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.texteditor.IUpdate;
+
+/**
+ * Abstract class that holds common methods used by implementors of IDetailPane.
+ */
+public abstract class ModulesAbstractDetailPane implements IDetailPane {
+
+ /**
+ * The <code>IWorkbenchPartSite</code> that the details area (and the
+ * variables view) belongs to.
+ */
+ private IWorkbenchPartSite fWorkbenchPartSite;
+
+ /**
+ * Map of actions. Keys are strings, values
+ * are <code>IAction</code>.
+ */
+ private Map<String,IAction> fActionMap = new HashMap<String,IAction>();
+
+ /**
+ * Collection to track actions that should be updated when selection occurs.
+ */
+ private List<String> fSelectionActions = new ArrayList<String>();
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#init(org.eclipse.ui.IWorkbenchPartSite)
+ */
+ public void init(IWorkbenchPartSite workbench) {
+ fWorkbenchPartSite = workbench;
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.IDetailPane#dispose()
+ */
+ public void dispose() {
+ fActionMap.clear();
+ fSelectionActions.clear();
+ }
+
+ /**
+ * Adds an action to the Map storing actions. Removes it if action is null.
+ *
+ * @param actionID The ID of the action, used as the key in the Map
+ * @param action The action associated with the ID
+ */
+ protected void setAction(String actionID, IAction action) {
+ if (action == null) {
+ fActionMap.remove(actionID);
+ } else {
+ fActionMap.put(actionID, action);
+ }
+ }
+
+ /**
+ * Adds the given action to the global action handler for the ViewSite.
+ * A call to <code>updateActionBars()</code> must be called after changes
+ * to propagate changes through the workbench.
+ *
+ * @param actionID The ID of the action
+ * @param action The action to be set globally
+ */
+ protected void setGlobalAction(String actionID, IAction action){
+ getViewSite().getActionBars().setGlobalActionHandler(actionID, action);
+ }
+
+ /**
+ * Adds the given action to the list of actions that will be updated when
+ * <code>updateSelectionDependentActions()</code> is called. If the string
+ * is null it will not be added to the list.
+ *
+ * @param actionID The ID of the action which should be updated
+ */
+ protected void setSelectionDependantAction(String actionID){
+ if (actionID != null) fSelectionActions.add(actionID);
+ }
+
+ /**
+ * Gets the action out of the map, casts it to an <code>IAction</code>
+ *
+ * @param actionID The ID of the action to find
+ * @return The action associated with the ID or null if none is found.
+ */
+ protected IAction getAction(String actionID) {
+ return fActionMap.get(actionID);
+ }
+
+ /**
+ * Calls the update method of the action with the given action ID.
+ * The action must exist in the action map and must be an instance of
+ * </code>IUpdate</code>
+ *
+ * @param actionId The ID of the action to update
+ */
+ protected void updateAction(String actionId) {
+ IAction action= getAction(actionId);
+ if (action instanceof IUpdate) {
+ ((IUpdate) action).update();
+ }
+ }
+
+ /**
+ * Iterates through the list of selection dependent actions and
+ * updates them. Use <code>setSelectionDependentAction(String actionID)</code>
+ * to add an action to the list. The action must have been added to the known
+ * actions map by calling <code>setAction(String actionID, IAction action)</code>
+ * before it can be updated by this method.
+ */
+ protected void updateSelectionDependentActions() {
+ Iterator<String> iterator= fSelectionActions.iterator();
+ while (iterator.hasNext()) {
+ updateAction(iterator.next());
+ }
+ }
+
+ /**
+ * Gets the view site for this view. May be null if this detail pane
+ * is not part of a view.
+ *
+ * @return The site for this view or <code>null</code>
+ */
+ protected IViewSite getViewSite(){
+ if (fWorkbenchPartSite == null){
+ return null;
+ } else {
+ return (IViewSite) fWorkbenchPartSite.getPart().getSite();
+ }
+ }
+
+ /**
+ * Gets the workbench part site for this view. May be null if this detail pane
+ * is not part of a view.
+ *
+ * @return The workbench part site or <code>null</code>
+ */
+ protected IWorkbenchPartSite getWorkbenchPartSite() {
+ return fWorkbenchPartSite;
+ }
+
+ /**
+ * Returns whether this detail pane is being displayed in a view with a workbench part site.
+ *
+ * @return whether this detail pane is being displayed in a view with a workbench part site.
+ */
+ protected boolean isInView(){
+ return fWorkbenchPartSite != null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.java
new file mode 100644
index 00000000000..a29cb586e50
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ * Wind River Systems, Inc. - extended implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail;
+
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+/**
+ * Comment for .
+ */
+public class ModulesMessages {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.modules.detail.ModulesMessages";//$NON-NLS-1$
+
+ private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle( BUNDLE_NAME );
+
+ private ModulesMessages() {
+ }
+
+ public static String getString( String key ) {
+ try {
+ return RESOURCE_BUNDLE.getString( key );
+ }
+ catch( MissingResourceException e ) {
+ return '!' + key + '!';
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.properties
new file mode 100644
index 00000000000..14cb80d4921
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/modules/detail/ModulesMessages.properties
@@ -0,0 +1,25 @@
+###############################################################################
+# Copyright (c) 2005, 2008 QNX Software Systems and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# QNX Software Systems - initial API and implementation
+# Wind River Systems - adapted to work with platform Modules view (bug 210558)
+###############################################################################
+ModulesView.Executable=executable
+ModulesView.SharedLibrary=shared library
+ModulesView.Type=Type:
+ModulesView.Symbols=Symbols:
+ModulesView.Loaded=loaded
+ModulesView.NotLoaded=not loaded
+ModulesView.SymbolsFile=Symbols file:
+ModulesView.CPU=CPU:
+ModulesView.BaseAddress=Base address:
+ModulesView.Size=Size:
+ModulesView.SymbolsLoaded=\ (symbols loaded)
+ModulesView.SymbolsNotLoaded=(symbols not loaded)
+ModulesView.SelectAll=Select &All
+ModulesView.Copy=&Copy
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValuePreferenceStore.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValuePreferenceStore.java
new file mode 100644
index 00000000000..b0e78f1adac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/FormattedValuePreferenceStore.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ * Provides default implementation of preference storage.
+ */
+@SuppressWarnings("restriction")
+public class FormattedValuePreferenceStore implements IFormattedValuePreferenceStore {
+
+ private static IFormattedValuePreferenceStore fgSingletonReference;
+
+ public static IFormattedValuePreferenceStore getDefault() {
+ if (fgSingletonReference == null) {
+ fgSingletonReference = new FormattedValuePreferenceStore();
+ }
+ return fgSingletonReference;
+ }
+
+ public String getCurrentNumericFormat( IPresentationContext context ) {
+
+ Object prop = context.getProperty( IDebugVMConstants.CURRENT_FORMAT_STORAGE );
+
+ if ( prop != null ) {
+ return (String) prop;
+ }
+ return IFormattedValues.NATURAL_FORMAT;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValuePreferenceStore.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValuePreferenceStore.java
new file mode 100644
index 00000000000..8b6f7d6c41a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValuePreferenceStore.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ *
+ */
+
+@SuppressWarnings("restriction")
+public interface IFormattedValuePreferenceStore {
+ /*
+ * Retrieves for the specified Presentation Context the configured format.
+ *
+ * @param context Specified Presentation Context
+ * @return Format ID.
+ */
+ public String getCurrentNumericFormat( IPresentationContext context );
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValueVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValueVMContext.java
new file mode 100644
index 00000000000..561908d575d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/IFormattedValueVMContext.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+
+/**
+ *
+ */
+public interface IFormattedValueVMContext extends IVMContext {
+ IFormattedValuePreferenceStore getPreferenceStore();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/MessagesForNumberFormat.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/MessagesForNumberFormat.java
new file mode 100644
index 00000000000..3db13710902
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/MessagesForNumberFormat.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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:
+ * Wind River Systems, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForNumberFormat extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.messages"; //$NON-NLS-1$
+
+ public static String NumberFormatContribution_Natural_label;
+ public static String NumberFormatContribution_Decimal_label;
+ public static String NumberFormatContribution_Hex_label;
+ public static String NumberFormatContribution_Octal_label;
+ public static String NumberFormatContribution_Binary_label;
+ public static String NumberFormatContribution_String_label;
+
+ public static String NumberFormatContribution_EmptyFormatsList_label;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForNumberFormat.class);
+ }
+
+ private MessagesForNumberFormat() {}
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsContribution.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsContribution.java
new file mode 100644
index 00000000000..bda57b093c4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsContribution.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.ContributionItem;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.ui.actions.CompoundContributionItem;
+import org.eclipse.ui.menus.IWorkbenchContribution;
+import org.eclipse.ui.services.IServiceLocator;
+
+/**
+ * Dynamic menu contribution that shows available number formats
+ * in the current view.
+ *
+ * @since 1.1
+ */
+@SuppressWarnings("restriction")
+public class NumberFormatsContribution extends CompoundContributionItem implements IWorkbenchContribution {
+
+ private static final Map<String, String> FORMATS = new LinkedHashMap<String, String>();
+ static {
+ FORMATS.put(IFormattedValues.NATURAL_FORMAT, MessagesForNumberFormat.NumberFormatContribution_Natural_label);
+ FORMATS.put(IFormattedValues.HEX_FORMAT, MessagesForNumberFormat.NumberFormatContribution_Hex_label);
+ FORMATS.put(IFormattedValues.DECIMAL_FORMAT, MessagesForNumberFormat.NumberFormatContribution_Decimal_label);
+ FORMATS.put(IFormattedValues.OCTAL_FORMAT, MessagesForNumberFormat.NumberFormatContribution_Octal_label);
+ FORMATS.put(IFormattedValues.BINARY_FORMAT, MessagesForNumberFormat.NumberFormatContribution_Binary_label);
+ FORMATS.put(IFormattedValues.STRING_FORMAT, MessagesForNumberFormat.NumberFormatContribution_String_label);
+ }
+
+ private class SelectNumberFormatAction extends Action {
+ private final IPresentationContext fContext;
+ private final String fFormatId;
+ SelectNumberFormatAction(IPresentationContext context, String formatId) {
+ super(FORMATS.get(formatId), AS_RADIO_BUTTON);
+ fContext = context;
+ fFormatId = formatId;
+ }
+
+ @Override
+ public void run() {
+ if (isChecked()) {
+ fContext.setProperty(IDebugVMConstants.CURRENT_FORMAT_STORAGE, fFormatId);
+ }
+ }
+ }
+
+ private IServiceLocator fServiceLocator;
+
+ private static IContributionItem[] NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS = new IContributionItem[] {
+ new ContributionItem() {
+ @Override
+ public void fill(Menu menu, int index) {
+ MenuItem item = new MenuItem(menu, SWT.NONE);
+ item.setEnabled(false);
+ item.setText(MessagesForNumberFormat.NumberFormatContribution_EmptyFormatsList_label);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+ }
+ };
+
+ @Override
+ protected IContributionItem[] getContributionItems() {
+ IVMProvider provider = VMHandlerUtils.getActiveVMProvider(fServiceLocator);
+
+ // If no part or selection, disable all.
+ if (provider == null) {
+ return NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS;
+ }
+
+ IPresentationContext context = provider.getPresentationContext();
+ Object activeId = context.getProperty(IDebugVMConstants.CURRENT_FORMAT_STORAGE);
+ if (activeId == null) {
+ activeId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ List<Action> actions = new ArrayList<Action>(FORMATS.size());
+ for (String formatId : FORMATS.keySet()) {
+ Action action = new SelectNumberFormatAction(context, formatId);
+ if (formatId.equals(activeId)) {
+ action.setChecked(true);
+ }
+ actions.add(action);
+ }
+
+ if ( actions.isEmpty() ) {
+ return NO_BREAKPOINT_TYPES_CONTRIBUTION_ITEMS;
+ }
+
+ IContributionItem[] items = new IContributionItem[actions.size()];
+ for (int i = 0; i < actions.size(); i++) {
+ items[i] = new ActionContributionItem(actions.get(i));
+ }
+ return items;
+ }
+
+ public void initialize(IServiceLocator serviceLocator) {
+ fServiceLocator = serviceLocator;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsPropertyTester.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsPropertyTester.java
new file mode 100644
index 00000000000..7dc699bf345
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/NumberFormatsPropertyTester.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.numberformat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.actions.VMHandlerUtils;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.ui.IWorkbenchPart;
+
+/**
+ * Property tester for number format information available through the given
+ * object. The object being tested should be either an {@link IVMContext},
+ * through which an instance of {@link IVMProvider} could be obtained.
+ * Or it could be an {@link IWorkbenchPart}, which is tested to see if it
+ * is a debug view through which a caching VM provider can be obtained.
+ * The view's presentation context is used to test the given property.
+ * <p>
+ * Three properties are supported:
+ * <ul>
+ * <li> "areNumberFormatsSupported" - Checks whether number formats are
+ * available at all given the receiver.</li>
+ * <li> "isNumberFormatAvailable" - Checks whether the number format ID in the
+ * expected value is available for the given receiver.</li>
+ * <li> "isNumberFormatActive" - Checks whether the number format ID in the expected
+ * value is the currently active number format for the given receiver.</li>
+ * </ul>
+ * </p>
+ */
+@SuppressWarnings("restriction")
+public class NumberFormatsPropertyTester extends PropertyTester {
+
+ private static final String SUPPORTED = "areNumberFormatsSupported"; //$NON-NLS-1$
+ private static final String AVAILABLE = "isNumberFormatAvailable"; //$NON-NLS-1$
+ private static final String ACTIVE = "isNumberFormatActive"; //$NON-NLS-1$
+
+ private static final List<String> AVAILABLE_FORMATS = new ArrayList<String>();
+ static {
+ AVAILABLE_FORMATS.add(IFormattedValues.NATURAL_FORMAT);
+ AVAILABLE_FORMATS.add(IFormattedValues.HEX_FORMAT);
+ AVAILABLE_FORMATS.add(IFormattedValues.DECIMAL_FORMAT);
+ AVAILABLE_FORMATS.add(IFormattedValues.OCTAL_FORMAT);
+ AVAILABLE_FORMATS.add(IFormattedValues.BINARY_FORMAT);
+ AVAILABLE_FORMATS.add(IFormattedValues.STRING_FORMAT);
+ };
+
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ if (receiver instanceof IVMContext) {
+ IVMProvider provider = ((IVMContext)receiver).getVMNode().getVMProvider();
+ if (provider != null) {
+ return testProvider(provider, property, expectedValue);
+ }
+ } else if (receiver instanceof IDebugView) {
+ IVMProvider provider = VMHandlerUtils.getVMProviderForPart((IDebugView)receiver);
+ if (provider != null) {
+ return testProvider(provider, property, expectedValue);
+ }
+ }
+ return false;
+ }
+
+ private boolean testProvider(IVMProvider provider, String property, Object expectedValue) {
+ if (SUPPORTED.equals(property)) {
+ return true;
+ } else if (AVAILABLE.equals(property)) {
+ return AVAILABLE_FORMATS.contains(expectedValue);
+ } else if (ACTIVE.equals(property)) {
+ Object activeId = provider.getPresentationContext().getProperty(IDebugVMConstants.CURRENT_FORMAT_STORAGE);
+ return expectedValue != null && expectedValue.equals(activeId);
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/messages.properties
new file mode 100644
index 00000000000..fbebfa748d8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/numberformat/messages.properties
@@ -0,0 +1,19 @@
+###############################################################################
+# Copyright (c) 2006, 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:
+# Wind River Systems Inc - copied for non-restricted version for DSDP/DD/DSF
+###############################################################################
+
+NumberFormatContribution_Natural_label=Natural
+NumberFormatContribution_Decimal_label=Decimal
+NumberFormatContribution_Hex_label=Hex
+NumberFormatContribution_Octal_label=Octal
+NumberFormatContribution_Binary_label=Binary
+NumberFormatContribution_String_label=String
+
+NumberFormatContribution_EmptyFormatsList_label=Number formats not available \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/MessagesForRegisterVM.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/MessagesForRegisterVM.java
new file mode 100644
index 00000000000..432b0f07d3d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/MessagesForRegisterVM.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForRegisterVM extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.register.messages"; //$NON-NLS-1$
+
+ public static String RegisterColumnPresentation_description;
+
+ public static String RegisterColumnPresentation_name;
+
+ public static String RegisterColumnPresentation_type;
+
+ public static String RegisterColumnPresentation_value;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForRegisterVM.class);
+ }
+
+ private MessagesForRegisterVM() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldCellModifier.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldCellModifier.java
new file mode 100644
index 00000000000..48c8d7b471c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldCellModifier.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IMnemonic;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.UserEditEvent;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+@SuppressWarnings("restriction")
+public class RegisterBitFieldCellModifier extends WatchExpressionCellModifier {
+
+ public static enum BitFieldEditorStyle { NOTHING, BITFIELDCOMBO, BITFIELDTEXT }
+
+ private AbstractCachingVMProvider fProvider;
+ private BitFieldEditorStyle fStyle;
+ private IBitFieldDMData fBitFieldData = null;
+ private Object fElement = null;
+ private SyncRegisterDataAccess fDataAccess = null;
+ private IFormattedValuePreferenceStore fFormatPrefStore;
+
+ public RegisterBitFieldCellModifier(AbstractCachingVMProvider provider,
+ IFormattedValuePreferenceStore formatPrefStore, BitFieldEditorStyle style, SyncRegisterDataAccess access )
+ {
+ fProvider = provider;
+ fStyle = style;
+ fDataAccess = access;
+ fFormatPrefStore = formatPrefStore;
+ }
+
+ /*
+ * Used to make sure we are dealing with a valid register.
+ */
+ private IBitFieldDMContext getBitFieldDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+ return DMContexts.getAncestorOfType(dmc, IBitFieldDMContext.class);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean canModify(Object element, String property) {
+
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+ if ( IDebugVMConstants.COLUMN_ID__VALUE.equals(property) ) {
+ /*
+ * Make sure we are are dealing with a valid set of information.
+ */
+ if ( getBitFieldDMC(element) == null ) return false;
+
+ fElement = element;
+
+ /*
+ * We need to read the register in order to get the attributes.
+ */
+ fBitFieldData = fDataAccess.readBitField(element);
+
+ if ( ( fBitFieldData != null ) && ( ! fBitFieldData.isWriteable() ) ) return false;
+
+ return true ;
+ } else {
+ return super.canModify(element, property);
+ }
+ }
+
+ @Override
+ public Object getValue(Object element, String property) {
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+ if ( IDebugVMConstants.COLUMN_ID__VALUE.equals(property) ) {
+ /*
+ * Make sure we are working on the editable areas.
+ */
+ if ( element != fElement ) return false;
+
+ if ( fStyle == BitFieldEditorStyle.BITFIELDTEXT ) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fFormatPrefStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ String value = fDataAccess.getFormattedBitFieldValue(fElement, formatId);
+
+ if ( value == null ) { value = "..."; } //$NON-NLS-1$
+
+ return value;
+ }
+ else {
+ /*
+ * This is a COMBO BOX. So we need to take the value of the bitfield and
+ * compare it to the associated mnemonic values to see which mnemonic is
+ * representing the current value. At this point the Bitfield Model data
+ * has already been established since the "canModify()" method is called
+ * first by the flexible hierarchy proxies.
+ */
+ IMnemonic curMnemonic = fBitFieldData.getCurrentMnemonicValue();
+
+ int index = 0 ;
+ for ( IMnemonic mnemonic : fBitFieldData.getMnemonics() ) {
+ if ( mnemonic.equals( curMnemonic ) ) {
+ return new Integer( index );
+ }
+ index ++;
+ }
+
+ return null;
+ }
+ } else {
+ return super.getValue(element, property);
+ }
+ }
+
+ @Override
+ public void modify(Object element, String property, Object value) {
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+ if ( IDebugVMConstants.COLUMN_ID__VALUE.equals(property) ) {
+ if ( fStyle == BitFieldEditorStyle.BITFIELDTEXT ) {
+ if (value instanceof String) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fFormatPrefStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+ fDataAccess.writeBitField(element, (String) value, formatId);
+ fProvider.handleEvent(new UserEditEvent(element));
+ }
+ }
+ else {
+ if (value instanceof Integer) {
+ /*
+ * Get the integer value corresponding to the selected entry.
+ */
+ Integer val = (Integer) value;
+
+ /*
+ * Write the bit field using the selected mnemonic.
+ */
+ fDataAccess.writeBitField(element, fBitFieldData.getMnemonics()[val.intValue()]);
+ fProvider.handleEvent(new UserEditEvent(element));
+ }
+ }
+ } else {
+ super.modify(element, property, value);
+ }
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java
new file mode 100644
index 00000000000..0e96bf90d8a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterBitFieldVMNode.java
@@ -0,0 +1,901 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IMnemonic;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterBitFieldCellModifier.BitFieldEditorStyle;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.DebugPluginImages;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.widgets.Composite;
+
+@SuppressWarnings("restriction")
+public class RegisterBitFieldVMNode extends AbstractExpressionVMNode
+ implements IElementEditor, IElementLabelProvider, IElementMementoProvider
+{
+ protected class BitFieldVMC extends DMVMContext
+ implements IFormattedValueVMContext
+ {
+ private IExpression fExpression;
+ public BitFieldVMC(IDMContext dmc) {
+ super(dmc);
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedPrefStore;
+ }
+
+ public void setExpression(IExpression expression) {
+ fExpression = expression;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) {
+ return fExpression;
+ } else if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapter2.class)) {
+ return getWatchExpressionFactory();
+ } else {
+ return super.getAdapter(adapter);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof BitFieldVMC && super.equals(other)) {
+ BitFieldVMC otherBitField = (BitFieldVMC)other;
+ return (otherBitField.fExpression == null && fExpression == null) ||
+ (otherBitField.fExpression != null && otherBitField.fExpression.equals(fExpression));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() + (fExpression != null ? fExpression.hashCode() : 0);
+ }
+ }
+
+ protected class BitFieldExpressionFactory implements IWatchExpressionFactoryAdapter2 {
+
+ public boolean canCreateWatchExpression(Object element) {
+ return element instanceof BitFieldVMC;
+ }
+
+ /**
+ * Expected format: GRP( GroupName ).REG( RegisterName ).BFLD( BitFieldname )
+ */
+ public String createWatchExpression(Object element) throws CoreException {
+ IRegisterGroupDMData groupData = getSyncRegisterDataAccess().getRegisterGroupDMData(element);
+ IRegisterDMData registerData = getSyncRegisterDataAccess().getRegisterDMData(element);
+ IBitFieldDMData bitFieldData = getSyncRegisterDataAccess().getBitFieldDMData(element);
+
+ if (groupData != null && registerData != null && bitFieldData != null) {
+ StringBuffer exprBuf = new StringBuffer();
+
+ exprBuf.append("GRP( "); exprBuf.append(groupData.getName()); exprBuf.append(" )"); //$NON-NLS-1$ //$NON-NLS-2$
+ exprBuf.append(".REG( "); exprBuf.append(registerData.getName()); exprBuf.append(" )"); //$NON-NLS-1$ //$NON-NLS-2$
+ exprBuf.append(".BFLD( "); exprBuf.append(bitFieldData.getName()); exprBuf.append(" )"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ return exprBuf.toString();
+ }
+
+ return null;
+ }
+ }
+
+ private SyncRegisterDataAccess fSyncRegisterDataAccess = null;
+ protected IWatchExpressionFactoryAdapter2 fBitFieldExpressionFactory = null;
+ private final IFormattedValuePreferenceStore fFormattedPrefStore;
+
+ public RegisterBitFieldVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess access) {
+ super(provider, session, IBitFieldDMContext.class);
+ fSyncRegisterDataAccess = access;
+ fFormattedPrefStore = prefStore;
+ }
+
+
+ @Override
+ public String toString() {
+ return "RegisterBitFieldVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedPrefStore;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public SyncRegisterDataAccess getSyncRegisterDataAccess() {
+ return fSyncRegisterDataAccess;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IWatchExpressionFactoryAdapter2 getWatchExpressionFactory() {
+ if ( fBitFieldExpressionFactory == null ) {
+ fBitFieldExpressionFactory = new BitFieldExpressionFactory();
+ }
+ return fBitFieldExpressionFactory;
+ }
+
+ /**
+ * Private data access routine which performs the extra level of data access needed to
+ * get the formatted data value for a specific register.
+ */
+ private void updateFormattedRegisterValue(final ILabelUpdate update, final int labelIndex, final IBitFieldDMContext dmc, final IBitFieldDMData data)
+ {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+
+ /*
+ * First select the format to be used. This involves checking so see that the preference
+ * page format is supported by the register service. If the format is not supported then
+ * we will pick the first available format.
+ */
+ final IPresentationContext context = update.getPresentationContext();
+ final String preferencePageFormatId = fFormattedPrefStore.getCurrentNumericFormat(context) ;
+
+ regService.getAvailableFormats(
+ dmc,
+ new ViewerDataRequestMonitor<String[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ /*
+ * See if the desired format is supported.
+ */
+ String[] formatIds = getData();
+ String finalFormatId = IFormattedValues.HEX_FORMAT;
+ boolean requestedFormatIsSupported = false;
+
+ for ( String fId : formatIds ) {
+ if ( preferencePageFormatId.equals(fId) ) {
+ /*
+ * Desired format is supported.
+ */
+ finalFormatId = preferencePageFormatId;
+ requestedFormatIsSupported = true;
+ break;
+ }
+ }
+
+ if ( ! requestedFormatIsSupported ) {
+ /*
+ * Desired format is not supported. If there are any formats supported
+ * then use the first available.
+ */
+ if ( formatIds.length != 0 ) {
+ finalFormatId = formatIds[0];
+ }
+ else {
+ /*
+ * Register service does not support any format.
+ */
+ handleFailedUpdate(update);
+ return;
+ }
+ }
+
+ /*
+ * Format has been validated. Get the formatted value.
+ */
+ final FormattedValueDMContext valueDmc = regService.getFormattedValueContext(dmc, finalFormatId);
+
+ getDMVMProvider().getModelData(
+ RegisterBitFieldVMNode.this, update, regService, valueDmc,
+ new ViewerDataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ if (getStatus().getCode() == IDsfStatusConstants.INVALID_STATE) {
+ update.setLabel("...", labelIndex); //$NON-NLS-1$
+ } else {
+ update.setLabel("Error: " + getStatus().getMessage(), labelIndex); //$NON-NLS-1$
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
+ update.done();
+ return;
+ }
+
+ /*
+ * Fill the label/column with the properly formatted data value.
+ */
+ IMnemonic mnemonic = data.getCurrentMnemonicValue();
+ if ( mnemonic != null ) {
+ String mnemstr = mnemonic.getLongName() + " - " + getData().getFormattedValue(); //$NON-NLS-1$
+ update.setLabel(mnemstr , labelIndex);
+ }
+ else {
+ update.setLabel(getData().getFormattedValue() , labelIndex);
+ }
+
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
+
+ // color based on change history
+
+ FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(
+ RegisterBitFieldVMNode.this, update, valueDmc);
+ if(oldData != null && !oldData.getFormattedValue().equals(getData().getFormattedValue())) {
+ update.setBackground(
+ DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(), labelIndex);
+ }
+ update.done();
+ }
+ },
+ getExecutor()
+ );
+ }
+ }
+ );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
+ */
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ /*
+ * Updates the requested label based on the specified column.
+ */
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ final IBitFieldDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IBitFieldDMContext.class);
+
+ getDMVMProvider().getModelData(
+ this,
+ update,
+ regService,
+ dmc,
+ new ViewerDataRequestMonitor<IBitFieldDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * Check that the request was evaluated and data is still
+ * valid. The request could fail if the state of the
+ * service changed during the request, but the view model
+ * has not been updated yet.
+ */
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+ /*
+ * Instead of just failing this outright we are going to attempt to do more here.
+ * Failing it outright causes the view to display ... for all columns in the line
+ * and this is uninformative about what is happening. We may be trying to show a
+ * register whos retrieval has been cancelled by the lower level. Perhaps because
+ * we are stepping extremely fast and state changes cause the register service to
+ * return these requests without ever sending them to the debug engine.
+ *
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null)
+ localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ /*
+ * This used to be easy in that the DMC contained the name. Which allowed us
+ * to display the register name and an error message across from it. Now that
+ * name must come from the data and we could not retrieve the data we do not
+ * have anything intelligent to show here. I think this is going to look very
+ * ugly and will need to be worked on. We know the service has the name with
+ * it, it is just the dynamic part which cannot be obtained ( as explained in
+ * comments above ).
+ */
+ update.setLabel("Unknown name", idx); //$NON-NLS-1$
+ update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ if (getStatus().getCode() == IDsfStatusConstants.INVALID_STATE) {
+ update.setLabel("...", idx); //$NON-NLS-1$
+ } else {
+ update.setLabel("Error: " + getStatus().getMessage(), idx); //$NON-NLS-1$
+ }
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel("...", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ }
+
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+
+ update.done();
+ return;
+ }
+
+ /*
+ * If columns are configured, extract the selected values for each
+ * understood column. First we fill all of those columns which can
+ * be filled without the extra data mining. We also note if we do
+ * have to datamine. Any columns need to set the processing flag
+ * so we know we have further work to do. If there are more columns
+ * which need data extraction they need to be added in both "for"
+ * loops.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null) localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ boolean weAreExtractingFormattedData = false;
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ update.setLabel(getData().getName(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ weAreExtractingFormattedData = true;
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ IBitFieldDMData data = getData();
+ String typeStr = "Unsigned"; //$NON-NLS-1$
+ String ReadAttrStr = "ReadNone"; //$NON-NLS-1$
+ String WriteAddrStr = "WriteNone"; //$NON-NLS-1$
+
+ if ( data.isReadOnce() ) { ReadAttrStr = "ReadOnce"; } //$NON-NLS-1$
+ else if ( data.isReadable() ) { ReadAttrStr = "Readable"; } //$NON-NLS-1$
+
+ if ( data.isReadOnce() ) { WriteAddrStr = "WriteOnce"; } //$NON-NLS-1$
+ else if ( data.isReadable() ) { WriteAddrStr = "Writeable"; } //$NON-NLS-1$
+
+ typeStr += " - " + ReadAttrStr + "/" + WriteAddrStr; //$NON-NLS-1$ //$NON-NLS-2$
+ update.setLabel(typeStr, idx);
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel(getData().getDescription(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ IVMContext vmc = (IVMContext)update.getElement();
+ IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
+ if (expression != null) {
+ update.setLabel(expression.getExpressionText(), idx);
+ } else {
+ update.setLabel(getData().getName(), idx);
+ }
+ }
+
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+
+ if ( ! weAreExtractingFormattedData ) {
+ update.done();
+ } else {
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ updateFormattedRegisterValue(update, idx, dmc, getData() );
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+ }
+ }
+ },
+ getExecutor()
+ );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
+ */
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ final IRegisterDMContext regDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
+
+ if (regDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ IRegisters regService = getServicesTracker().getService(IRegisters.class);
+
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+
+ regService.getBitFields(
+ regDmc,
+ new ViewerDataRequestMonitor<IBitFieldDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleFailure() {
+ handleFailedUpdate(update);
+ }
+
+ @Override
+ protected void handleSuccess() {
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.cdt.dsf.datamodel.IDMContext)
+ */
+ @Override
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new BitFieldVMC(dmc);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
+ */
+ public int getDeltaFlags(Object e) {
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IRegisterChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ if (e instanceof IBitFieldChangedDMEvent) {
+ return IModelDelta.STATE;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, int, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
+ // The following events can affect any bit field's values,
+ // refresh the contents of the parent element (i.e. all the registers).
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IRegisterChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ if (e instanceof IBitFieldChangedDMEvent) {
+ // Create a delta indicating that the value of bit field has changed.
+ parentDelta.addNode( createVMContext(((IBitFieldChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
+ }
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
+ */
+ public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
+
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
+ /*
+ * In order to decide what kind of editor to present we need to know if there are
+ * mnemonics which can be used to represent the values. If there are then we will
+ * create a Combo editor for them. Otherwise we will just make a normal text cell
+ * editor. If there are bit groups then the modifier will check the size of the
+ * value being entered.
+ */
+ IBitFieldDMData bitFieldData = getSyncRegisterDataAccess().readBitField(element);
+
+ if ( bitFieldData != null && bitFieldData.isWriteable() ) {
+
+ IMnemonic[] mnemonics = bitFieldData.getMnemonics();
+
+ if ( mnemonics != null && mnemonics.length != 0 ) {
+
+ /*
+ * Create the list of readable dropdown selections.
+ */
+ String[] StringValues = new String[ mnemonics.length ];
+
+ int idx = 0 ;
+ for ( IMnemonic mnemonic : mnemonics ) {
+ StringValues[ idx ++ ] = mnemonic.getLongName();
+ }
+
+ /*
+ * Not we are complex COMBO and return the right editor.
+ */
+ return new ComboBoxCellEditor(parent, StringValues);
+ }
+ else {
+ /*
+ * Text editor even if we need to clamp the value entered.
+ */
+ return new TextCellEditor(parent);
+ }
+ }
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
+ */
+ public ICellModifier getCellModifier(IPresentationContext context, Object element) {
+
+ /*
+ * In order to decide what kind of modifier to present we need to know if there
+ * are mnemonics which can be used to represent the values.
+ */
+ IBitFieldDMData bitFieldData = getSyncRegisterDataAccess().readBitField(element);
+
+ if ( bitFieldData != null && bitFieldData.isWriteable() ) {
+
+ IMnemonic[] mnemonics = bitFieldData.getMnemonics();
+
+ if ( mnemonics != null && mnemonics.length != 0 ) {
+ /*
+ * Note we are complex COMBO and return the right editor.
+ */
+ return new RegisterBitFieldCellModifier(
+ getDMVMProvider(), fFormattedPrefStore, BitFieldEditorStyle.BITFIELDCOMBO, getSyncRegisterDataAccess() );
+ }
+ else {
+ /*
+ * Text editor even if we need to clamp the value entered.
+ */
+ return new RegisterBitFieldCellModifier(
+ getDMVMProvider(), fFormattedPrefStore, BitFieldEditorStyle.BITFIELDTEXT, getSyncRegisterDataAccess() );
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Expected format: GRP( GroupName ).REG( RegisterName ).BFLD( BitFieldname )
+ */
+
+ public boolean canParseExpression(IExpression expression) {
+ return parseExpressionForBitFieldName(expression.getExpressionText()) != null;
+ }
+
+ private String parseExpressionForBitFieldName(String expression) {
+
+ if (expression.startsWith("GRP(")) { //$NON-NLS-1$
+
+ /*
+ * Get the group portion.
+ */
+ int startIdx = "GRP(".length(); //$NON-NLS-1$
+ int endIdx = expression.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ String remaining = expression.substring(endIdx+1);
+ if ( ! remaining.startsWith(".REG(") ) { //$NON-NLS-1$
+ return null;
+ }
+
+ /*
+ * Get the register portion.
+ */
+ startIdx = ".REG(".length(); //$NON-NLS-1$
+ endIdx = remaining.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ remaining = remaining.substring(endIdx+1);
+
+ /*
+ * Get the bit-field portion.
+ */
+ if ( ! remaining.startsWith(".BFLD(") ) { //$NON-NLS-1$
+ return null;
+ }
+ startIdx = ".BFLD(".length(); //$NON-NLS-1$
+ endIdx = remaining.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ String bitFieldName = remaining.substring(startIdx, endIdx);
+
+ /*
+ * Make sure there is nothing following. If there is then this
+ * is not a properly formed expression and we do not claim it.
+ */
+ remaining = remaining.substring( endIdx + 1);
+
+ if ( remaining.length() != 0 ) {
+ return null;
+ }
+
+ return bitFieldName.trim();
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ @Override
+ protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
+ if (!(element instanceof IDMVMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ final IBitFieldDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IBitFieldDMContext.class);
+ if (dmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ final String bitFieldName = parseExpressionForBitFieldName(expression.getExpressionText());
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ IRegisters registersService = getServicesTracker().getService(IRegisters.class);
+ if (registersService != null) {
+ registersService.getBitFieldData(
+ dmc,
+ new DataRequestMonitor<IBitFieldDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData( getData().getName().equals(bitFieldName) );
+ rm.done();
+ }
+ });
+ } else {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Register service not available", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "DSF session shut down", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
+ */
+ @Override
+ protected void associateExpression(Object element, IExpression expression) {
+ if (element instanceof BitFieldVMC) {
+ ((BitFieldVMC)element).setExpression(expression);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
+ */
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ if (event instanceof ISuspendedDMEvent) {
+ return IModelDelta.CONTENT;
+ }
+
+ if (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) {
+ return IModelDelta.CONTENT;
+ }
+
+ if (event instanceof IMemoryChangedEvent) {
+ return IModelDelta.CONTENT;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpression(final IExpression expression, final int elementIdx, final Object event, final VMDelta parentDelta, final TreePath path, final RequestMonitor rm)
+ {
+ // Always refresh the contents of the view upon suspended event.
+ if (event instanceof ISuspendedDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
+ {
+ // The following events can affect register values, refresh the state
+ // of the expression.
+ if ( event instanceof IRegisterChangedDMEvent ||
+ event instanceof IMemoryChangedEvent ||
+ (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ parentDelta.addNode(element, IModelDelta.STATE);
+ }
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ private final String MEMENTO_NAME = "BITFIELD_MEMENTO_NAME"; //$NON-NLS-1$
+
+ public void compareElements(IElementCompareRequest[] requests) {
+ for ( final IElementCompareRequest request : requests ) {
+ final String mementoName = request.getMemento().getString(MEMENTO_NAME);
+
+ final IBitFieldDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IBitFieldDMContext.class);
+ if (regDmc == null || mementoName == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getBitFieldData(
+ regDmc,
+ new DataRequestMonitor<IBitFieldDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.setEqual( mementoName.equals( "BitField." + getData().getName() ) ); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+ for ( final IElementMementoRequest request : requests ) {
+ final IBitFieldDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IBitFieldDMContext.class);
+ if (regDmc == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getBitFieldData(
+ regDmc,
+ new DataRequestMonitor<IBitFieldDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.getMemento().putString(MEMENTO_NAME, "BitField." + getData().getName()); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterCellModifier.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterCellModifier.java
new file mode 100644
index 00000000000..60b6e8d92f6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterCellModifier.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.UserEditEvent;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+@SuppressWarnings("restriction")
+public class RegisterCellModifier extends WatchExpressionCellModifier {
+
+ private AbstractCachingVMProvider fProvider;
+ private SyncRegisterDataAccess fDataAccess = null;
+ private IFormattedValuePreferenceStore fFormattedValuePreferenceStore;
+
+ public RegisterCellModifier(AbstractCachingVMProvider provider,
+ IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncRegisterDataAccess access)
+ {
+ fProvider = provider;
+ fDataAccess = access;
+ fFormattedValuePreferenceStore = formattedValuePreferenceStore;
+ }
+
+ public SyncRegisterDataAccess getRegisterDataAccess() {
+ return fDataAccess;
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedValuePreferenceStore;
+ }
+ /*
+ * Used to make sure we are dealing with a valid register.
+ */
+ protected IRegisterDMContext getRegisterDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+ return DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean canModify(Object element, String property) {
+
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) {
+ /*
+ * Make sure we are are dealing with a valid set of information.
+ */
+ if ( getRegisterDMC(element) == null ) return false;
+
+ /*
+ * We need to read the register in order to get the attributes.
+ */
+
+ IRegisterDMData regData = fDataAccess.readRegister(element);
+
+ if ( ( regData != null ) && ( ! regData.isWriteable() ) ) return false;
+
+ return true ;
+ } else {
+ return super.canModify(element, property);
+ }
+ }
+
+ @Override
+ public Object getValue(Object element, String property) {
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+ if ( IDebugVMConstants.COLUMN_ID__VALUE.equals(property) ) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fFormattedValuePreferenceStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ String value =
+
+ fDataAccess.getFormattedRegisterValue(element, formatId);
+
+ if ( value == null ) { return "..."; } //$NON-NLS-1$
+ else { return value; }
+ } else {
+ return super.getValue(element, property);
+ }
+ }
+
+ @Override
+ public void modify(Object element, String property, Object value) {
+ /*
+ * If we're in the column value, modify the register data.
+ * Otherwise, call the super-class to edit the watch expression.
+ */
+
+ if ( IDebugVMConstants.COLUMN_ID__VALUE.equals(property) ) {
+
+ if (value instanceof String) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fFormattedValuePreferenceStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ fDataAccess.writeRegister(element, (String) value, formatId);
+ fProvider.handleEvent(new UserEditEvent(element));
+ }
+ } else {
+ super.modify(element, property, value);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterColumnPresentation.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterColumnPresentation.java
new file mode 100644
index 00000000000..03ef9ee3ff5
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterColumnPresentation.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class RegisterColumnPresentation implements IColumnPresentation {
+
+ public static final String ID = DsfUIPlugin.PLUGIN_ID + ".REGISTERS_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+
+ public void init(IPresentationContext context) {
+ }
+
+ public void dispose() {
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getAvailableColumns()
+ public String[] getAvailableColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__NAME, IDebugVMConstants.COLUMN_ID__TYPE, IDebugVMConstants.COLUMN_ID__VALUE, IDebugVMConstants.COLUMN_ID__DESCRIPTION, };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getHeader(java.lang.String)
+ public String getHeader(String id) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(id)) {
+ return MessagesForRegisterVM.RegisterColumnPresentation_name;
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(id)) {
+ return MessagesForRegisterVM.RegisterColumnPresentation_type;
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(id)) {
+ return MessagesForRegisterVM.RegisterColumnPresentation_value;
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(id)) {
+ return MessagesForRegisterVM.RegisterColumnPresentation_description;
+ }
+ return null;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getId()
+ public String getId() {
+ return ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getInitialColumns()
+ public String[] getInitialColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__NAME, IDebugVMConstants.COLUMN_ID__VALUE, IDebugVMConstants.COLUMN_ID__DESCRIPTION };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#isOptional()
+ public boolean isOptional() {
+ return true;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterGroupVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterGroupVMNode.java
new file mode 100644
index 00000000000..0d6fc7b2c9e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterGroupVMNode.java
@@ -0,0 +1,586 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IGroupChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IGroupsChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.DebugPluginImages;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.widgets.Composite;
+
+@SuppressWarnings("restriction")
+public class RegisterGroupVMNode extends AbstractExpressionVMNode
+ implements IElementEditor, IElementLabelProvider, IElementMementoProvider
+{
+ protected class RegisterGroupVMC extends DMVMContext
+ {
+ private IExpression fExpression;
+ public RegisterGroupVMC(IDMContext dmc) {
+ super(dmc);
+ }
+
+ public void setExpression(IExpression expression) {
+ fExpression = expression;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) {
+ return fExpression;
+ } else if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapter2.class)) {
+ return getWatchExpressionFactory();
+ } else {
+ return super.getAdapter(adapter);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof RegisterGroupVMC && super.equals(other)) {
+ RegisterGroupVMC otherGroup = (RegisterGroupVMC)other;
+ return (otherGroup.fExpression == null && fExpression == null) ||
+ (otherGroup.fExpression != null && otherGroup.fExpression.equals(fExpression));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() + (fExpression != null ? fExpression.hashCode() : 0);
+ }
+ }
+
+ protected class RegisterGroupExpressionFactory implements IWatchExpressionFactoryAdapter2 {
+
+ public boolean canCreateWatchExpression(Object element) {
+ return element instanceof RegisterGroupVMC;
+ }
+
+ /**
+ * Expected format: Group(GroupName)
+ */
+ public String createWatchExpression(Object element) throws CoreException {
+ IRegisterGroupDMData groupData = getSyncRegisterDataAccess().getRegisterGroupDMData(element);
+ if (groupData != null) {
+ StringBuffer exprBuf = new StringBuffer();
+ exprBuf.append("GRP( "); //$NON-NLS-1$
+ exprBuf.append(groupData.getName());
+ exprBuf.append(" )"); //$NON-NLS-1$
+ return exprBuf.toString();
+ }
+
+ return null;
+ }
+ }
+
+ final private SyncRegisterDataAccess fSyncRegisterDataAccess;
+ private IWatchExpressionFactoryAdapter2 fRegisterGroupExpressionFactory = null;
+ private WatchExpressionCellModifier fWatchExpressionCellModifier = new WatchExpressionCellModifier();
+
+ public RegisterGroupVMNode(AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
+ super(provider, session, IRegisterGroupDMContext.class);
+ fSyncRegisterDataAccess = syncDataAccess;
+ }
+
+ @Override
+ public String toString() {
+ return "RegisterGroupVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public SyncRegisterDataAccess getSyncRegisterDataAccess() {
+ return fSyncRegisterDataAccess;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IWatchExpressionFactoryAdapter2 getWatchExpressionFactory() {
+ if ( fRegisterGroupExpressionFactory == null ) {
+ fRegisterGroupExpressionFactory = new RegisterGroupExpressionFactory();
+ }
+ return fRegisterGroupExpressionFactory;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
+ */
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+
+ IRegisters regService = getServicesTracker().getService(IRegisters.class);
+
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ regService.getRegisterGroups(
+ createCompositeDMVMContext(update),
+ new ViewerDataRequestMonitor<IRegisterGroupDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ update.done();
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }});
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.cdt.dsf.datamodel.IDMContext)
+ */
+ @Override
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new RegisterGroupVMC(dmc);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
+ */
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ /*
+ * Updates the labels with the required information for each visible column.
+ */
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+
+ final IRegisterGroupDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterGroupDMContext.class);
+ if ( dmc == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ getDMVMProvider().getModelData(
+ this,
+ update,
+ regService,
+ dmc,
+ new ViewerDataRequestMonitor<IRegisterGroupDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * Check that the request was evaluated and data is still
+ * valid. The request could fail if the state of the
+ * service changed during the request, but the view model
+ * has not been updated yet.
+ */
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+ handleFailedUpdate(update);
+ return;
+ }
+
+ /*
+ * If columns are configured, call the protected methods to
+ * fill in column values.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null) localColumns = new String[] { null };
+
+ for (int i = 0; i < localColumns.length; i++) {
+ fillColumnLabel(dmc, getData(), localColumns[i], i, update);
+ }
+ update.done();
+ }
+ },
+ getExecutor());
+ }
+ }
+
+ /*
+ * Based on the specified visible column, provide the appropriate value/label.
+ */
+ protected void fillColumnLabel(IRegisterGroupDMContext dmContext, IRegisterGroupDMData dmData,
+ String columnId, int idx, ILabelUpdate update)
+ {
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(columnId)) {
+ update.setLabel(dmData.getName(), idx);
+ update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER_GROUP), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(columnId)) {
+ update.setLabel(dmData.getDescription(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(columnId)) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ IVMContext vmc = (IVMContext)update.getElement();
+ IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
+ if (expression != null) {
+ update.setLabel(expression.getExpressionText(), idx);
+ } else {
+ update.setLabel(dmData.getName(), idx);
+ }
+ }
+ else if ( columnId == null ) {
+ /*
+ * If the Column ID comes in as "null" then this is the case where the user has decided
+ * to not have any columns. So we need a default action which makes the most sense and
+ * is doable. In this case we elect to simply display the name.
+ */
+ update.setLabel(dmData.getName(), idx);
+ update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER_GROUP), idx);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
+ */
+ public int getDeltaFlags(Object e) {
+ if (e instanceof ISuspendedDMEvent) {
+ return IModelDelta.CONTENT;
+ }
+ else if (e instanceof IGroupsChangedDMEvent) {
+ return IModelDelta.CONTENT;
+ }
+ else if (e instanceof IGroupChangedDMEvent) {
+ return IModelDelta.STATE;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, int, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
+ // Although the register groups themselves are not affected by the
+ // suspended event, typically all the registers are. Add a CONTENT changed
+ // flag to the parent to repaint all the groups and their registers.
+ if (e instanceof ISuspendedDMEvent) {
+ // Create a delta that indicates all groups have changed
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+ else if (e instanceof IGroupsChangedDMEvent) {
+ // Create a delta that indicates all groups have changed
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+ else if (e instanceof IGroupChangedDMEvent) {
+ // Create a delta that indicates that specific group changed
+ parentDelta.addNode( createVMContext(((IGroupChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
+ }
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#canParseExpression(org.eclipse.debug.core.model.IExpression)
+ */
+ public boolean canParseExpression(IExpression expression) {
+ return parseExpressionForGroupName(expression.getExpressionText()) != null;
+ }
+
+ /**
+ * Expected format: Group(GroupName)
+ */
+ private String parseExpressionForGroupName(String expression) {
+ if (expression.startsWith("GRP(")) { //$NON-NLS-1$
+ /*
+ * Extract the group name.
+ */
+ int startIdx = "GRP(".length(); //$NON-NLS-1$
+ int endIdx = expression.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ String groupName = expression.substring(startIdx, endIdx);
+ return groupName.trim();
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
+ */
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+
+ if (event instanceof ISuspendedDMEvent ||
+ event instanceof IGroupsChangedDMEvent)
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ if (event instanceof IGroupChangedDMEvent) {
+ return IModelDelta.STATE;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
+ TreePath path, RequestMonitor rm)
+ {
+ if (event instanceof ISuspendedDMEvent) {
+ // Mark the parent delta indicating that elements were added and/or removed.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ // If the group definitions have changed, refresh the whole expressions
+ // view contents since previously invalid expressions may now evaluate
+ // to valid groups
+ if (event instanceof IGroupsChangedDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
+ {
+ if (event instanceof IGroupChangedDMEvent) {
+ parentDelta.addNode(element, IModelDelta.STATE);
+ }
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ @Override
+ protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
+ if (!(element instanceof IDMVMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ final IRegisterGroupDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IRegisterGroupDMContext.class);
+ if (dmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ final String groupName = parseExpressionForGroupName(expression.getExpressionText());
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ IRegisters registersService = getServicesTracker().getService(IRegisters.class);
+ if (registersService != null) {
+ registersService.getRegisterGroupData(
+ dmc,
+ new DataRequestMonitor<IRegisterGroupDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData( getData().getName().equals(groupName) );
+ rm.done();
+ }
+ });
+ } else {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Register service not available", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "DSF session shut down", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
+ */
+ @Override
+ protected void associateExpression(Object element, IExpression expression) {
+ if (element instanceof RegisterGroupVMC) {
+ ((RegisterGroupVMC)element).setExpression(expression);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
+ */
+ public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
+ */
+ public ICellModifier getCellModifier(IPresentationContext context, Object element) {
+ return fWatchExpressionCellModifier;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ private final String MEMENTO_NAME = "GROUP_MEMENTO_NAME"; //$NON-NLS-1$
+
+ public void compareElements(IElementCompareRequest[] requests) {
+ for (final IElementCompareRequest request : requests ) {
+ final IRegisterGroupDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IRegisterGroupDMContext.class);
+ final String mementoName = request.getMemento().getString(MEMENTO_NAME);
+
+ if (regDmc == null || mementoName == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getRegisterGroupData(
+ regDmc,
+ new DataRequestMonitor<IRegisterGroupDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.setEqual( mementoName.equals( "Group." + getData().getName()) ); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+ for ( final IElementMementoRequest request : requests ) {
+ final IRegisterGroupDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IRegisterGroupDMContext.class);
+ if (regDmc == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getRegisterGroupData(
+ regDmc,
+ new DataRequestMonitor<IRegisterGroupDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.getMemento().putString(MEMENTO_NAME, "Group." + getData().getName()); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterRootDMVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterRootDMVMNode.java
new file mode 100644
index 00000000000..316a0477d2f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterRootDMVMNode.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+
+/*
+ * We are extending the ROOT VM node for the register view so we can
+ * provide Memento providers for the root node. In the Register VM
+ * Provider we are returning a pseudo VMContext selection when the
+ * original input is a child of an execution context we return a selection
+ * which represents an Execution Context instead. This ensures that the
+ * Register View does not collapse and redraw when going from frame to frame
+ * when stepping or just when selecting within the view.
+ */
+@SuppressWarnings("restriction")
+public class RegisterRootDMVMNode extends RootDMVMNode implements IElementMementoProvider {
+
+ public RegisterRootDMVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ public void compareElements(IElementCompareRequest[] requests) {
+ for ( IElementMementoRequest request : requests ) { request.done(); }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+
+ for ( IElementMementoRequest request : requests ) { request.done(); }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java
new file mode 100644
index 00000000000..c48ec9590b9
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMNode.java
@@ -0,0 +1,960 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import java.util.ArrayList;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegistersChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.DebugPluginImages;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.widgets.Composite;
+
+@SuppressWarnings("restriction")
+public class RegisterVMNode extends AbstractExpressionVMNode
+ implements IElementEditor, IElementLabelProvider, IElementMementoProvider
+{
+ protected class RegisterVMC extends DMVMContext
+ implements IFormattedValueVMContext
+ {
+ private IExpression fExpression;
+ public RegisterVMC(IDMContext dmc) {
+ super(dmc);
+ }
+
+ public void setExpression(IExpression expression) {
+ fExpression = expression;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) {
+ return fExpression;
+ } else if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapter2.class)) {
+ return getWatchExpressionFactory();
+ } else {
+ return super.getAdapter(adapter);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof RegisterVMC && super.equals(other)) {
+ RegisterVMC otherReg = (RegisterVMC)other;
+ return (otherReg.fExpression == null && fExpression == null) ||
+ (otherReg.fExpression != null && otherReg.fExpression.equals(fExpression));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() + (fExpression != null ? fExpression.hashCode() : 0);
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedPrefStore;
+ }
+ }
+
+ protected class RegisterExpressionFactory implements IWatchExpressionFactoryAdapter2 {
+
+ public boolean canCreateWatchExpression(Object element) {
+ return element instanceof RegisterVMC;
+ }
+
+ /**
+ * Expected format: GRP( GroupName ).REG( RegisterName )
+ */
+ public String createWatchExpression(Object element) throws CoreException {
+ IRegisterGroupDMData groupData = getSyncRegisterDataAccess().getRegisterGroupDMData(element);
+ IRegisterDMData registerData = getSyncRegisterDataAccess().getRegisterDMData(element);
+
+ if (groupData != null && registerData != null) {
+ StringBuffer exprBuf = new StringBuffer();
+
+ exprBuf.append("GRP( "); exprBuf.append(groupData.getName()); exprBuf.append(" )"); //$NON-NLS-1$ //$NON-NLS-2$
+ exprBuf.append(".REG( "); exprBuf.append(registerData.getName()); exprBuf.append(" )"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ return exprBuf.toString();
+ }
+
+ return null;
+ }
+ }
+
+ private IWatchExpressionFactoryAdapter2 fRegisterExpressionFactory = null;
+ final private SyncRegisterDataAccess fSyncRegisterDataAccess;
+ private final IFormattedValuePreferenceStore fFormattedPrefStore;
+
+ public RegisterVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider, DsfSession session, SyncRegisterDataAccess syncDataAccess) {
+ super(provider, session, IRegisterDMContext.class);
+ fSyncRegisterDataAccess = syncDataAccess;
+ fFormattedPrefStore = prefStore;
+ }
+
+ @Override
+ public String toString() {
+ return "RegisterVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ protected SyncRegisterDataAccess getSyncRegisterDataAccess() {
+ return fSyncRegisterDataAccess;
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedPrefStore;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IWatchExpressionFactoryAdapter2 getWatchExpressionFactory() {
+ if ( fRegisterExpressionFactory == null ) {
+ fRegisterExpressionFactory = new RegisterExpressionFactory();
+ }
+ return fRegisterExpressionFactory;
+ }
+
+ /*
+ * This class is used to hold the associated information needed to finally get the
+ * formatted value for a register DMC. It starts out with the basic set sans the
+ * actual formatted register DMC. Once found this is added to the information.
+ */
+ private class QueuedValueUpdate {
+
+ ILabelUpdate fUpdate;
+ int fIndex ;
+ IRegisterDMContext fDmc;
+ FormattedValueDMContext fValueDmc = null;
+
+ public QueuedValueUpdate( ILabelUpdate update, int index , IRegisterDMContext dmc ) {
+ fUpdate = update;
+ fIndex = index;
+ fDmc = dmc;
+ }
+
+ public ILabelUpdate getUpdate() { return fUpdate; }
+ public int getIndex() { return fIndex; }
+ public IRegisterDMContext getDmc() { return fDmc; }
+
+ public void setValueDmc( FormattedValueDMContext dmc ) { fValueDmc = dmc; }
+ public FormattedValueDMContext getValueDmc() { return fValueDmc; }
+ }
+
+ private void retrieveAllFormattedDataValues( final ArrayList<QueuedValueUpdate> updates ) {
+
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService == null ) {
+ for ( final QueuedValueUpdate up : updates ) {
+ handleFailedUpdate(up.getUpdate());
+ }
+ return;
+ }
+
+ for ( final QueuedValueUpdate up : updates ) {
+
+ final ILabelUpdate update = up.getUpdate();
+ final FormattedValueDMContext valueDmc = up.getValueDmc();
+
+ /*
+ * It is possible that we could not get a formatted DMC. In this case the setup
+ * logic puts a null as the value. So in this case we just complete this one
+ * with nothing.
+ */
+ if ( valueDmc == null ) {
+ update.done();
+ continue;
+ }
+
+ final int idx = up.getIndex();
+
+ getDMVMProvider().getModelData(
+ RegisterVMNode.this,
+ update,
+ regService,
+ valueDmc,
+ new ViewerDataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ if (getStatus().getCode() == IDsfStatusConstants.INVALID_STATE) {
+ update.setLabel("...", idx); //$NON-NLS-1$
+ } else {
+ update.setLabel("Error: " + getStatus().getMessage(), idx); //$NON-NLS-1$
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ update.done();
+ return;
+ }
+ /*
+ * Fill the label/column with the properly formatted data value.
+ */
+ update.setLabel(getData().getFormattedValue(), idx);
+
+ // color based on change history
+ FormattedValueDMData oldData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(RegisterVMNode.this, update, valueDmc);
+ if(oldData != null && !oldData.getFormattedValue().equals(getData().getFormattedValue())) {
+ update.setBackground(DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB(), idx);
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ update.done();
+ }
+ },
+ getSession().getExecutor()
+ );
+ }
+ }
+
+ /**
+ * Private data access routine which performs the extra level of data access needed to
+ * get the formatted data value for a specific register.
+ */
+ private void getFormattedDmcForReqister( final ILabelUpdate update, final IRegisterDMContext dmc, final DataRequestMonitor<FormattedValueDMContext> rm)
+ {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService == null ) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * First select the format to be used. This involves checking so see that the preference
+ * page format is supported by the register service. If the format is not supported then
+ * we will pick the first available format.
+ */
+ final IPresentationContext context = update.getPresentationContext();
+ final String preferencePageFormatId = getPreferenceStore().getCurrentNumericFormat(context) ;
+
+ regService.getAvailableFormats(
+ dmc,
+ new DataRequestMonitor<String[]>(getSession().getExecutor(), rm) {
+ @Override
+ public void handleSuccess() {
+ /*
+ * See if the desired format is supported.
+ */
+ String[] formatIds = getData();
+ String finalFormatId = IFormattedValues.NATURAL_FORMAT;
+ boolean requestedFormatIsSupported = false;
+
+ for ( String fId : formatIds ) {
+ if ( preferencePageFormatId.equals(fId) ) {
+ /*
+ * Desired format is supported.
+ */
+ finalFormatId = preferencePageFormatId;
+ requestedFormatIsSupported = true;
+ break;
+ }
+ }
+
+ if ( ! requestedFormatIsSupported ) {
+ /*
+ * Desired format is not supported. If there are any formats supported
+ * then use the first available.
+ */
+ if ( formatIds.length != 0 ) {
+ finalFormatId = formatIds[0];
+ }
+ else {
+ /*
+ * Register service does not support any format.
+ */
+ handleFailure();
+ return;
+ }
+ }
+
+ /*
+ * Format has been validated. Return it.
+ */
+ rm.setData(regService.getFormattedValueContext(dmc, finalFormatId));
+ rm.done();
+ }
+ }
+ );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate[])
+ */
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ /*
+ * Updates the labels which are controlled by the column being requested.
+ */
+ protected void updateLabelInSessionThread(final ILabelUpdate[] updates) {
+
+ /*
+ * This list represents all the QUEUED requests for formatted DMCs. This allows us to issue the
+ * requests for the data in the same dispatch cycle. Thus the lower level services is given its
+ * best chance to coalesce the registers in to a single request.
+ */
+ final ArrayList<QueuedValueUpdate> valueUpdatesToProcess = new ArrayList<QueuedValueUpdate>();
+
+ final DsfExecutor dsfExecutor = getSession().getExecutor();
+ final CountingRequestMonitor crm =
+ new CountingRequestMonitor(dsfExecutor, null) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ for ( ILabelUpdate up : updates ) {
+ handleFailedUpdate(up);
+ }
+ return;
+ }
+
+ /*
+ * We have all of the formatted DMCs. Go issue the requests for the formatted data
+ * in a single dispatch cycle.
+ */
+ retrieveAllFormattedDataValues( valueUpdatesToProcess );
+ }
+ };
+
+ crm.setDoneCount( calculateTheNumberOfRowsWithValueColumns(updates) );
+
+ /*
+ * Process each update request, creating a QUEUE of requests which need further processing
+ * for the formatted values.
+ */
+ for (final ILabelUpdate update : updates) {
+
+ final IRegisterDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IRegisterDMContext.class);
+ if ( dmc == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ getDMVMProvider().getModelData(
+ this,
+ update,
+ regService,
+ dmc,
+ new ViewerDataRequestMonitor<IRegisterDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ /*
+ * Check that the request was evaluated and data is still
+ * valid. The request could fail if the state of the
+ * service changed during the request, but the view model
+ * has not been updated yet.
+ */
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+ /*
+ * Instead of just failing this outright we are going to attempt to do more here.
+ * Failing it outright causes the view to display ... for all columns in the line
+ * and this is uninformative about what is happening. We may be trying to show a
+ * register whos retrieval has been cancelled by the lower level. Perhaps because
+ * we are stepping extremely fast and state changes cause the register service to
+ * return these requests without ever sending them to the debug engine.
+ *
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null)
+ localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ /*
+ * This used to be easy in that the DMC contained the name. Which allowed us
+ * to display the register name and an error message across from it. Now that
+ * name must come from the data and we could not retrieve the data we do not
+ * have anything intelligent to show here. I think this is going to look very
+ * ugly and will need to be worked on. We know the service has the name with
+ * it, it is just the dynamic part which cannot be obtained ( as explained in
+ * comments above ).
+ */
+ update.setLabel("Unknown name", idx); //$NON-NLS-1$
+ update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ if (getStatus().getCode() == IDsfStatusConstants.INVALID_STATE) {
+ update.setLabel("...", idx); //$NON-NLS-1$
+ } else {
+ update.setLabel("Error: " + getStatus().getMessage(), idx); //$NON-NLS-1$
+ }
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel("...", idx); //$NON-NLS-1$
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ update.setLabel("", idx); //$NON-NLS-1$
+ }
+
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+
+ update.done();
+ return;
+ }
+
+ /*
+ * If columns are configured, extract the selected values for each understood column. First we fill all
+ * of those columns which can be filled without the extra data mining. We also note, if we do have to
+ * datamine. Any columns need to set the processing flag so we know we have further work to do. If there
+ * are more columns which need data extraction they need to be added in both "for" loops.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null) localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ boolean allFieldsProcessed = true;
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ update.setLabel(getData().getName(), idx);
+ update.setImageDescriptor(DebugPluginImages.getImageDescriptor(IDebugUIConstants.IMG_OBJS_REGISTER), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ allFieldsProcessed = false;
+ /*
+ * Create an entry which holds all related data and add it to the list to process
+ * when all the formatted DMCs are gathered.
+ */
+ final QueuedValueUpdate valueUpdate = new QueuedValueUpdate(update,idx,dmc);
+ valueUpdatesToProcess.add(valueUpdate);
+
+ /*
+ * Fetch the associated formatted DMC for this field. Note that every time we
+ * complete the request for a Formatted DMC we tell the Counting Request Monitor
+ * we have completed one in the list.
+ */
+ getFormattedDmcForReqister(
+ update, dmc,
+ new ViewerDataRequestMonitor<FormattedValueDMContext>(dsfExecutor, update) {
+ @Override
+ public void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ valueUpdate.setValueDmc(getData());
+ }
+ else {
+ valueUpdate.setValueDmc(null);
+ }
+ crm.done();
+ }
+ });
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ IRegisterDMData data = getData();
+ String typeStr = "Unsigned"; //$NON-NLS-1$
+ String ReadAttrStr = "ReadNone"; //$NON-NLS-1$
+ String WriteAddrStr = "WriteNone"; //$NON-NLS-1$
+
+ if ( data.isFloat() ) { typeStr = "Floating Point"; } //$NON-NLS-1$
+
+ if ( data.isReadOnce() ) { ReadAttrStr = "ReadOnce"; } //$NON-NLS-1$
+ else if ( data.isReadable() ) { ReadAttrStr = "Readable"; } //$NON-NLS-1$
+
+ if ( data.isReadOnce() ) { WriteAddrStr = "WriteOnce"; } //$NON-NLS-1$
+ else if ( data.isReadable() ) { WriteAddrStr = "Writeable"; } //$NON-NLS-1$
+
+ typeStr += " - " + ReadAttrStr + "/" + WriteAddrStr; //$NON-NLS-1$ //$NON-NLS-2$
+ update.setLabel(typeStr, idx);
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel(getData().getDescription(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ IVMContext vmc = (IVMContext)update.getElement();
+ IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
+ if (expression != null) {
+ update.setLabel(expression.getExpressionText(), idx);
+ } else {
+ update.setLabel(getData().getName(), idx);
+ }
+ }
+ }
+
+ if ( allFieldsProcessed ) {
+ update.done();
+ }
+ }
+ },
+ getSession().getExecutor());
+ }
+ }
+
+ private int calculateTheNumberOfRowsWithValueColumns( ILabelUpdate updates[] ) {
+ int count = 0;
+ for (final ILabelUpdate update : updates) {
+ String[] columns = update.getColumnIds();
+ if (columns == null) columns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int idx = 0; idx < columns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columns[idx])) {
+ count ++;
+ }
+ }
+ }
+ return count;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate[])
+ */
+ @Override
+ public void update(IHasChildrenUpdate[] updates) {
+ // As an optimization, always indicate that register groups have
+ // children.
+ for (IHasChildrenUpdate update : updates) {
+ update.setHasChilren(true);
+ update.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#updateElementsInSessionThread(org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate)
+ */
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+
+ IRegisters regService = getServicesTracker().getService(IRegisters.class);
+
+ if ( regService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ regService.getRegisters(
+ createCompositeDMVMContext(update),
+ new ViewerDataRequestMonitor<IRegisterDMContext[]>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }
+ });
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode#createVMContext(org.eclipse.cdt.dsf.datamodel.IDMContext)
+ */
+ @Override
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new RegisterVMC(dmc);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#getDeltaFlags(java.lang.Object)
+ */
+ public int getDeltaFlags(Object e) {
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IRegistersChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ if (e instanceof IRegisterChangedDMEvent) {
+ return IModelDelta.STATE;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.IVMNode#buildDelta(java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, int, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
+ // The following events can affect any register's values,
+ // refresh the contents of the parent element (i.e. all the registers).
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IRegistersChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ // Create a delta that the whole register group has changed.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ if (e instanceof IRegisterChangedDMEvent) {
+ parentDelta.addNode( createVMContext(((IRegisterChangedDMEvent)e).getDMContext()), IModelDelta.STATE );
+ }
+
+ rm.done();
+ }
+
+ /**
+ * Expected format: GRP( GroupName ).REG( RegisterName )
+ * or: $RegisterName
+ */
+ public boolean canParseExpression(IExpression expression) {
+ return parseExpressionForRegisterName(expression.getExpressionText()) != null;
+ }
+
+ private String parseExpressionForRegisterName(String expression) {
+ if (expression.startsWith("GRP(")) { //$NON-NLS-1$
+ /*
+ * Get the group portion.
+ */
+ int startIdx = "GRP(".length(); //$NON-NLS-1$
+ int endIdx = expression.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ String remaining = expression.substring(endIdx+1);
+ if ( ! remaining.startsWith(".REG(") ) { //$NON-NLS-1$
+ return null;
+ }
+
+ /*
+ * Get the register portion.
+ */
+ startIdx = ".REG(".length(); //$NON-NLS-1$
+ endIdx = remaining.indexOf(')', startIdx);
+ if ( startIdx == -1 || endIdx == -1 ) {
+ return null;
+ }
+ String regName = remaining.substring(startIdx,endIdx);
+ return regName.trim();
+ }
+ else if ( expression.startsWith("$") ) { //$NON-NLS-1$
+ /*
+ * At this point I am leaving this code here to represent the register case. To do this
+ * correctly would be to use the findRegister function and upgrade the register service
+ * to deal with registers that do not have a specified group parent context. I do not
+ * have the time for this right now. So by saying we do not handle this the Expression
+ * VM node will take it and pass it to the debug engine as a generic expression. Most
+ * debug engines ( GDB included ) have an inherent knowledge of the core registers as
+ * part of their expression evaluation and will respond with a flat value for the reg.
+ * This is not totally complete in that you should be able to express a register which
+ * has bit fields for example and the bit fields should be expandable in the expression
+ * view. With this method it will just appear to have a single value and no sub-fields.
+ * I will file a defect/enhancement for this to mark it. This comment will act as the
+ * place-holder for the future work.
+ */
+ return null;
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#testElementForExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ @Override
+ protected void testElementForExpression(Object element, IExpression expression, final DataRequestMonitor<Boolean> rm) {
+ if (!(element instanceof IDMVMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ final IRegisterDMContext dmc = DMContexts.getAncestorOfType(((IDMVMContext)element).getDMContext(), IRegisterDMContext.class);
+ if (dmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ final String regName = parseExpressionForRegisterName(expression.getExpressionText());
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ IRegisters registersService = getServicesTracker().getService(IRegisters.class);
+ if (registersService != null) {
+ registersService.getRegisterData(
+ dmc,
+ new DataRequestMonitor<IRegisterDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData( getData().getName().equals(regName) );
+ rm.done();
+ }
+ });
+ } else {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Register service not available", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.WARNING, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "DSF session shut down", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode#associateExpression(java.lang.Object, org.eclipse.debug.core.model.IExpression)
+ */
+ @Override
+ protected void associateExpression(Object element, IExpression expression) {
+ if (element instanceof RegisterVMC) {
+ ((RegisterVMC)element).setExpression(expression);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#getDeltaFlagsForExpression(org.eclipse.debug.core.model.IExpression, java.lang.Object)
+ */
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ if ( event instanceof IRegisterChangedDMEvent ||
+ event instanceof IMemoryChangedEvent ||
+ (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ return IModelDelta.STATE;
+ }
+
+ if (event instanceof IRegistersChangedDMEvent ||
+ event instanceof ISuspendedDMEvent)
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpression(org.eclipse.debug.core.model.IExpression, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.jface.viewers.TreePath, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
+ TreePath path, RequestMonitor rm)
+ {
+ // If the register definition has changed, refresh all the
+ // expressions in the expression manager. This is because some
+ // expressions that were previously invalid, may now represent new
+ // registers.
+ if (event instanceof IRegistersChangedDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ // Always refresh the contents of the view upon suspended event.
+ if (event instanceof ISuspendedDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionVMNode#buildDeltaForExpressionElement(java.lang.Object, int, java.lang.Object, org.eclipse.cdt.dsf.ui.viewmodel.VMDelta, org.eclipse.cdt.dsf.concurrent.RequestMonitor)
+ */
+ public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta, final RequestMonitor rm)
+ {
+ // The following events can affect register values, refresh the state
+ // of the expression.
+ if ( event instanceof IRegisterChangedDMEvent ||
+ event instanceof IMemoryChangedEvent ||
+ (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ parentDelta.addNode(element, IModelDelta.STATE);
+ }
+
+ rm.done();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellEditor(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.String, java.lang.Object, org.eclipse.swt.widgets.Composite)
+ */
+ public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
+ if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
+ /*
+ * See if the register is writable and if so we will created a
+ * cell editor for it.
+ */
+ IRegisterDMData regData = getSyncRegisterDataAccess().readRegister(element);
+
+ if ( regData != null && regData.isWriteable() ) {
+ return new TextCellEditor(parent);
+ }
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor#getCellModifier(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
+ */
+ public ICellModifier getCellModifier(IPresentationContext context, Object element) {
+ return new RegisterCellModifier(
+ getDMVMProvider(), fFormattedPrefStore, getSyncRegisterDataAccess() );
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ private final String MEMENTO_NAME = "REGISTER_MEMENTO_NAME"; //$NON-NLS-1$
+
+ public void compareElements(IElementCompareRequest[] requests) {
+ for ( final IElementCompareRequest request : requests ) {
+ final IRegisterDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IRegisterDMContext.class);
+ final String mementoName = request.getMemento().getString(MEMENTO_NAME);
+ if (regDmc == null || mementoName == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getRegisterData(
+ regDmc,
+ new DataRequestMonitor<IRegisterDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.setEqual( mementoName.equals( "Register." + getData().getName() ) ); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+ for ( final IElementMementoRequest request : requests ) {
+ final IRegisterDMContext regDmc = findDmcInPath(request.getViewerInput(), request.getElementPath(), IRegisterDMContext.class);
+ if (regDmc == null) {
+ request.done();
+ continue;
+ }
+
+ // Now go get the model data for the single register group found.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ final IRegisters regService = getServicesTracker().getService(IRegisters.class);
+ if ( regService != null ) {
+ regService.getRegisterData(
+ regDmc,
+ new DataRequestMonitor<IRegisterDMData>(regService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if ( getStatus().isOK() ) {
+ // Now make sure the register group is the one we want.
+ request.getMemento().putString(MEMENTO_NAME, "Register." + getData().getName()); //$NON-NLS-1$
+ }
+ request.done();
+ }
+ });
+ } else {
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.done();
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMProvider.java
new file mode 100644
index 00000000000..01badb93297
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/RegisterVMProvider.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.DsfDebugUITools;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+/**
+ * Provides the VIEW MODEL for the DEBUG MODEL REGISTER view.
+ */
+@SuppressWarnings("restriction")
+public class RegisterVMProvider extends AbstractDMVMProvider
+{
+ private IPropertyChangeListener fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (property.equals(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE)) {
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ setDelayEventHandleForViewUpdate(store.getBoolean(property));
+ }
+ }
+ };
+
+ private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ handleEvent(event);
+ }
+ };
+
+ /*
+ * Current default for register formatting.
+ */
+ public RegisterVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
+ super(adapter, context, session);
+
+ context.addPropertyChangeListener(fPresentationContextListener);
+
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ store.addPropertyChangeListener(fPreferencesListener);
+ setDelayEventHandleForViewUpdate(store.getBoolean(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE));
+
+ /*
+ * Create the register data access routines.
+ */
+ SyncRegisterDataAccess regAccess = new SyncRegisterDataAccess(session) ;
+
+ /*
+ * Create the top level node to deal with the root selection.
+ */
+ IRootVMNode rootNode = new RegisterRootDMVMNode(this);
+
+ /*
+ * Create the Group nodes next. They represent the first level shown in the view.
+ */
+ IVMNode registerGroupNode = new RegisterGroupVMNode(this, getSession(), regAccess);
+ addChildNodes(rootNode, new IVMNode[] { registerGroupNode });
+
+ /*
+ * Create the next level which is the registers themselves.
+ */
+ IVMNode registerNode = new RegisterVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
+ addChildNodes(registerGroupNode, new IVMNode[] { registerNode });
+
+ /*
+ * Create the next level which is the bitfield level.
+ */
+ IVMNode bitFieldNode = new RegisterBitFieldVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), regAccess);
+ addChildNodes(registerNode, new IVMNode[] { bitFieldNode });
+
+ /*
+ * Now set this schema set as the layout set.
+ */
+ setRootNode(rootNode);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider#createUpdateModes()
+ */
+ @Override
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider#dispose()
+ */
+ @Override
+ public void dispose() {
+ DsfDebugUITools.getPreferenceStore().removePropertyChangeListener(fPreferencesListener);
+ getPresentationContext().removePropertyChangeListener(fPresentationContextListener);
+ super.dispose();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider#createColumnPresentation(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
+ */
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return new RegisterColumnPresentation();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider#getColumnPresentationId(org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext, java.lang.Object)
+ */
+ @Override
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return RegisterColumnPresentation.ID;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider#canSkipHandlingEvent(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+ /*
+ * To optimize the performance of the view when stepping rapidly, skip all
+ * other events when a suspended event is received, including older suspended
+ * events.
+ */
+ return newEvent instanceof ISuspendedDMEvent;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider#update(org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate)
+ */
+ @Override
+ public void update(IViewerInputUpdate update) {
+ /*
+ * Use the execution context in the current selection as the input provider.
+ * This insures that the REGISTER VIEW will not collapse and expand on stepping or on
+ * re-selection in the DEBUG VIEW. Currently the register content is not stack frame
+ * specific. If it were to become so then we would need to modify this policy.
+ */
+ Object element = update.getElement();
+ if (element instanceof IDMVMContext) {
+ IDMContext ctx = ((IDMVMContext) element).getDMContext();
+
+ IExecutionDMContext execDmc = DMContexts.getAncestorOfType(ctx, IExecutionDMContext.class);
+ if ( execDmc != null ) {
+ /*
+ * This tells the Flexible Hierarchy that element driving this view has not changed
+ * and there is no need to redraw the view. Since this is a somewhat fake VMContext
+ * we provide our Root Layout node as the representative VM node.
+ */
+ update.setInputElement(new ViewInputElement(RegisterVMProvider.this.getRootVMNode(), execDmc));
+ update.done();
+ return;
+ }
+ }
+
+ /*
+ * If we reach here, then we did not override the standard behavior. Invoke the
+ * super class and this will provide the default standard behavior.
+ */
+ super.update(update);
+ }
+
+ /*
+ * Provides a local implementation of the IDMVMContext. This allows us to return one
+ * of our own making, representing the DMContext we want to use as selection criteria.
+ */
+ private class ViewInputElement extends AbstractVMContext implements IDMVMContext {
+
+ final private IDMContext fDMContext;
+
+ public ViewInputElement(IVMNode node, IDMContext dmc) {
+ super(node);
+ fDMContext = dmc;
+ }
+
+ public IDMContext getDMContext() {
+ return fDMContext;
+ }
+
+ /**
+ * The IAdaptable implementation. If the adapter is the DM context,
+ * return the context, otherwise delegate to IDMContext.getAdapter().
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ Object superAdapter = super.getAdapter(adapter);
+ if (superAdapter != null) {
+ return superAdapter;
+ } else {
+ // Delegate to the Data Model to find the context.
+ if (adapter.isInstance(fDMContext)) {
+ return fDMContext;
+ } else {
+ return fDMContext.getAdapter(adapter);
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+
+ if ( obj instanceof ViewInputElement && ((ViewInputElement) obj).fDMContext.equals(fDMContext) ) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return fDMContext.hashCode();
+ }
+ }
+
+ @Override
+ public void refresh() {
+ super.refresh();
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), getSession().getId());
+ IRegisters registerService = tracker.getService(IRegisters.class);
+ if (registerService instanceof ICachingService) {
+ ((ICachingService)registerService).flushCache(null);
+ }
+ tracker.dispose();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session disposed, ignore.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/SyncRegisterDataAccess.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/SyncRegisterDataAccess.java
new file mode 100644
index 00000000000..bca7931582b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/SyncRegisterDataAccess.java
@@ -0,0 +1,813 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.register;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IBitFieldDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IMnemonic;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMData;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterGroupDMData;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
+public class SyncRegisterDataAccess {
+
+ abstract public class RegistersServiceQuery<V, K extends IDMContext> extends Query<V> {
+
+ final protected K fDmc;
+
+ public RegistersServiceQuery(K dmc) {
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<V> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ IRegisters service = getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ doExecute(service, rm);
+ }
+
+ abstract protected void doExecute(IRegisters registersService, DataRequestMonitor<V> rm);
+ }
+
+
+ /**
+ * The session that this data access operates in.
+ */
+ private final DsfSession fSession;
+
+ /**
+ * Need to use the OSGi service tracker here (instead of DsfServiceTracker),
+ * because we're accessing it in non-dispatch thread. DsfServiceTracker is
+ * not thread-safe.
+ */
+ @ThreadSafe
+ private ServiceTracker fServiceTracker;
+
+ public SyncRegisterDataAccess(DsfSession session) {
+ fSession = session;
+ }
+
+ @ThreadSafe
+ private synchronized IRegisters getService() {
+
+ String serviceId = DsfServices.createServiceFilter(IRegisters.class, fSession.getId());
+ if (fServiceTracker == null) {
+ try {
+ fServiceTracker = new ServiceTracker(DsfUIPlugin.getBundleContext(), DsfUIPlugin
+ .getBundleContext().createFilter(serviceId), null);
+ fServiceTracker.open();
+ } catch (InvalidSyntaxException e) {
+ return null;
+ }
+ }
+ return (IRegisters) fServiceTracker.getService();
+ }
+
+ @ThreadSafe
+ public synchronized void dispose() {
+ if (fServiceTracker != null) {
+ fServiceTracker.close();
+ }
+ }
+
+ public class GetBitFieldValueQuery extends RegistersServiceQuery<IBitFieldDMData, IBitFieldDMContext> {
+
+ public GetBitFieldValueQuery(IBitFieldDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IBitFieldDMData> rm) {
+ service.getBitFieldData(
+ fDmc,
+ new DataRequestMonitor<IBitFieldDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public IBitFieldDMContext getBitFieldDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ return DMContexts.getAncestorOfType(dmc, IBitFieldDMContext.class);
+ }
+ return null;
+ }
+
+ public IBitFieldDMData readBitField(Object element) {
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IBitFieldDMContext dmc = getBitFieldDMC(element);
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to request the value from service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetBitFieldValueQuery query = new GetBitFieldValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class SetBitFieldValueQuery extends RegistersServiceQuery<Object, IBitFieldDMContext> {
+
+ private String fValue;
+ private String fFormatId;
+
+ public SetBitFieldValueQuery(IBitFieldDMContext dmc, String value, String formatId) {
+ super(dmc);
+ fValue = value;
+ fFormatId = formatId;
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<Object> rm) {
+ // Write the bit field using a string/format style.
+ service.writeBitField(
+ fDmc, fValue, fFormatId,
+ new DataRequestMonitor<IBitFieldDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(new Object());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public void writeBitField(Object element, String value, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IBitFieldDMContext dmc = getBitFieldDMC(element);
+ if (dmc == null)
+ return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ SetBitFieldValueQuery query = new SetBitFieldValueQuery(dmc, value, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ /*
+ * Return value is irrelevant, any error would come through with an
+ * exception.
+ */
+ query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ } catch (ExecutionException e) {
+ assert false;
+ /*
+ * View must be shutting down, no need to show erro dialog.
+ */
+ }
+ }
+
+ public class SetBitFieldValueMnemonicQuery extends RegistersServiceQuery<Object, IBitFieldDMContext> {
+ IMnemonic fMnemonic;
+
+ public SetBitFieldValueMnemonicQuery(IBitFieldDMContext dmc, IMnemonic mnemonic) {
+ super(dmc);
+ fMnemonic = mnemonic;
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<Object> rm) {
+ // Write the bit field using the mnemonic style.
+ service.writeBitField(
+ fDmc, fMnemonic,
+ new DataRequestMonitor<IBitFieldDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(new Object());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public void writeBitField(Object element, IMnemonic mnemonic) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IBitFieldDMContext dmc = getBitFieldDMC(element);
+ if (dmc == null)
+ return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ SetBitFieldValueMnemonicQuery query = new SetBitFieldValueMnemonicQuery(dmc, mnemonic);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ /*
+ * Return value is irrelevant, any error would come through with an
+ * exception.
+ */
+ query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ } catch (ExecutionException e) {
+ /*
+ * View must be shutting down, no need to show erro dialog.
+ */
+ }
+ }
+
+ public IRegisterGroupDMContext getRegisterGroupDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ return DMContexts.getAncestorOfType(dmc, IRegisterGroupDMContext.class);
+ }
+ return null;
+ }
+
+ public IRegisterDMContext getRegisterDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ return DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
+ }
+ return null;
+ }
+
+ public IFormattedDataDMContext getFormattedDMC(Object element) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext) element).getDMContext();
+ IRegisterDMContext regdmc = DMContexts.getAncestorOfType(dmc, IRegisterDMContext.class);
+ return DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
+ }
+ return null;
+ }
+
+ public class GetRegisterGroupValueQuery extends RegistersServiceQuery<IRegisterGroupDMData, IRegisterGroupDMContext> {
+ public GetRegisterGroupValueQuery(IRegisterGroupDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IRegisterGroupDMData> rm) {
+ service.getRegisterGroupData(
+ fDmc,
+ new DataRequestMonitor<IRegisterGroupDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public IRegisterGroupDMData readRegisterGroup(Object element) {
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IRegisterGroupDMContext dmc = getRegisterGroupDMC(element);
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to request the value from service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetRegisterGroupValueQuery query = new GetRegisterGroupValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class GetRegisterValueQuery extends RegistersServiceQuery<IRegisterDMData, IRegisterDMContext> {
+ public GetRegisterValueQuery(IRegisterDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IRegisterDMData> rm) {
+ service.getRegisterData(
+ fDmc,
+ new DataRequestMonitor<IRegisterDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public IRegisterDMData readRegister(Object element) {
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IRegisterDMContext dmc = getRegisterDMC(element);
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to request the value from service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetRegisterValueQuery query = new GetRegisterValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class SetRegisterValueQuery extends RegistersServiceQuery<Object, IRegisterDMContext> {
+ private String fValue;
+
+ private String fFormatId;
+
+ public SetRegisterValueQuery(IRegisterDMContext dmc, String value, String formatId) {
+ super(dmc);
+ fValue = value;
+ fFormatId = formatId;
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<Object> rm) {
+ /*
+ * Write the bit field using a string/format style.
+ */
+ service.writeRegister(
+ fDmc, fValue, fFormatId,
+ new DataRequestMonitor<IBitFieldDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(new Object());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public void writeRegister(Object element, String value, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IRegisterDMContext dmc = getRegisterDMC(element);
+ if (dmc == null)
+ return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ SetRegisterValueQuery query = new SetRegisterValueQuery(dmc, value, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ /*
+ * Return value is irrelevant, any error would come through with an
+ * exception.
+ */
+ query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ } catch (ExecutionException e) {
+ /*
+ * View must be shutting down, no need to show erro dialog.
+ */
+ }
+ }
+
+ public class GetSupportFormatsValueQuery extends RegistersServiceQuery<String[], IFormattedDataDMContext> {
+
+ public GetSupportFormatsValueQuery(IFormattedDataDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<String[]> rm) {
+ service.getAvailableFormats(fDmc, rm);
+ }
+ }
+
+ public String[] getSupportedFormats(Object element) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IFormattedDataDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ IDMContext vmcdmc = ((IDMVMContext) element).getDMContext();
+ IRegisterDMContext regdmc = DMContexts.getAncestorOfType(vmcdmc, IRegisterDMContext.class);
+ dmc = DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
+ }
+
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetSupportFormatsValueQuery query = new GetSupportFormatsValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class GetFormattedValueValueQuery extends RegistersServiceQuery<String, IFormattedDataDMContext> {
+
+ private String fFormatId;
+
+ public GetFormattedValueValueQuery(IFormattedDataDMContext dmc, String formatId) {
+ super(dmc);
+ fFormatId = formatId;
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<String> rm) {
+ /*
+ * Convert to the proper formatting DMC then go get the formatted
+ * value.
+ */
+
+ FormattedValueDMContext formDmc = service.getFormattedValueContext(fDmc, fFormatId);
+
+ service.getFormattedExpressionValue(
+ formDmc,
+ new DataRequestMonitor<FormattedValueDMData>(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData().getFormattedValue());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public String getFormattedRegisterValue(Object element, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IFormattedDataDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ IDMContext vmcdmc = ((IDMVMContext) element).getDMContext();
+ IRegisterDMContext regdmc = DMContexts.getAncestorOfType(vmcdmc, IRegisterDMContext.class);
+ dmc = DMContexts.getAncestorOfType(regdmc, IFormattedDataDMContext.class);
+ }
+
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetFormattedValueValueQuery query = new GetFormattedValueValueQuery(dmc, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public String getFormattedBitFieldValue(Object element, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IFormattedDataDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ IDMContext vmcdmc = ((IDMVMContext) element).getDMContext();
+ IBitFieldDMContext bitfielddmc = DMContexts.getAncestorOfType(vmcdmc, IBitFieldDMContext.class);
+ dmc = DMContexts.getAncestorOfType(bitfielddmc, IFormattedDataDMContext.class);
+ }
+
+ if (dmc == null)
+ return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null)
+ return null;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard agains RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetFormattedValueValueQuery query = new GetFormattedValueValueQuery(dmc, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class GetRegisterGroupDataQuery extends RegistersServiceQuery<IRegisterGroupDMData, IRegisterGroupDMContext> {
+
+ public GetRegisterGroupDataQuery(IRegisterGroupDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IRegisterGroupDMData> rm) {
+ service.getRegisterGroupData(fDmc, rm);
+ }
+ }
+
+ public IRegisterGroupDMData getRegisterGroupDMData(Object element) {
+ IRegisterGroupDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ dmc = DMContexts.getAncestorOfType(
+ ((IDMVMContext) element).getDMContext(),
+ IRegisterGroupDMContext.class);
+ }
+
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+
+ if (dmc != null && session != null) {
+ GetRegisterGroupDataQuery query = new GetRegisterGroupDataQuery(dmc);
+ session.getExecutor().execute(query);
+
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+ return null;
+ }
+
+
+ public class GetRegisterDataQuery extends RegistersServiceQuery<IRegisterDMData, IRegisterDMContext> {
+
+ public GetRegisterDataQuery(IRegisterDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IRegisterDMData> rm) {
+ service.getRegisterData(fDmc, rm);
+ }
+ }
+
+ public IRegisterDMData getRegisterDMData(Object element) {
+ IRegisterDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ dmc = DMContexts.getAncestorOfType( ((IDMVMContext) element).getDMContext(), IRegisterDMContext.class );
+ }
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+
+ if (dmc != null && session != null) {
+ GetRegisterDataQuery query = new GetRegisterDataQuery(dmc);
+ session.getExecutor().execute(query);
+
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+ return null;
+ }
+
+ public class GetBitFieldQuery extends RegistersServiceQuery<IBitFieldDMData, IBitFieldDMContext> {
+
+ public GetBitFieldQuery(IBitFieldDMContext dmc) {
+ super(dmc);
+ }
+
+ @Override
+ protected void doExecute(IRegisters service, final DataRequestMonitor<IBitFieldDMData> rm) {
+ service.getBitFieldData(fDmc, rm);
+ }
+ }
+
+ public IBitFieldDMData getBitFieldDMData(Object element) {
+ IBitFieldDMContext dmc = null;
+ if (element instanceof IDMVMContext) {
+ dmc = DMContexts.getAncestorOfType( ((IDMVMContext) element).getDMContext(), IBitFieldDMContext.class );
+ }
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+
+ if (dmc != null && session != null) {
+ GetBitFieldQuery query = new GetBitFieldQuery(dmc);
+ session.getExecutor().execute(query);
+
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/messages.properties
new file mode 100644
index 00000000000..a5bb472ba12
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/register/messages.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# Copyright (c) 2007, 2008 Wind River Systems 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
+###############################################################################
+
+RegisterColumnPresentation_name=Name
+RegisterColumnPresentation_type=Type
+RegisterColumnPresentation_value=Value
+RegisterColumnPresentation_description=Description
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/BreakpointHitUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/BreakpointHitUpdatePolicy.java
new file mode 100644
index 00000000000..49ae09bbfaa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/BreakpointHitUpdatePolicy.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.update;
+
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IElementUpdateTester;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+
+/**
+ *
+ */
+public class BreakpointHitUpdatePolicy extends ManualUpdatePolicy {
+
+ public static String BREAKPOINT_HIT_UPDATE_POLICY_ID = "org.eclipse.cdt.dsf.debug.ui.viewmodel.update.breakpointHitUpdatePolicy"; //$NON-NLS-1$
+
+ @Override
+ public String getID() {
+ return BREAKPOINT_HIT_UPDATE_POLICY_ID;
+ }
+
+ @Override
+ public String getName() {
+ return MessagesForVMUpdate.BreakpointHitUpdatePolicy_name;
+ }
+
+ @Override
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ if(event instanceof ISuspendedDMEvent) {
+ ISuspendedDMEvent suspendedEvent = (ISuspendedDMEvent)event;
+ if(suspendedEvent.getReason().equals(StateChangeReason.BREAKPOINT)) {
+ return super.getElementUpdateTester(REFRESH_EVENT);
+ }
+ }
+ return super.getElementUpdateTester(event);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/MessagesForVMUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/MessagesForVMUpdate.java
new file mode 100644
index 00000000000..a734d7d623f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/MessagesForVMUpdate.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.update;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForVMUpdate extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.update.messages"; //$NON-NLS-1$
+
+ public static String BreakpointHitUpdatePolicy_name;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForVMUpdate.class);
+ }
+
+ private MessagesForVMUpdate() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/messages.properties
new file mode 100644
index 00000000000..98e6fad25fd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/update/messages.properties
@@ -0,0 +1,12 @@
+###############################################################################
+# Copyright (c) 2007, 2008 Wind River Systems 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
+###############################################################################
+
+BreakpointHitUpdatePolicy_name=Breakpoint Hit
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/MessagesForVariablesVM.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/MessagesForVariablesVM.java
new file mode 100644
index 00000000000..8ea0064be22
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/MessagesForVariablesVM.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import org.eclipse.osgi.util.NLS;
+
+public class MessagesForVariablesVM extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.messages"; //$NON-NLS-1$
+
+ public static String VariableColumnPresentation_name;
+
+ public static String VariableColumnPresentation_type;
+
+ public static String VariableColumnPresentation_value;
+
+ public static String VariableColumnPresentation_address;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForVariablesVM.class);
+ }
+
+ private MessagesForVariablesVM() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java
new file mode 100644
index 00000000000..e49197e51df
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/SyncVariableDataAccess.java
@@ -0,0 +1,543 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.IFormattedDataDMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+@ThreadSafeAndProhibitedFromDsfExecutor("fSession#getExecutor")
+public class SyncVariableDataAccess {
+
+ /**
+ * The session that this data access operates in.
+ */
+ private final DsfSession fSession;
+
+ /**
+ * Need to use the OSGi service tracker here (instead of DsfServiceTracker),
+ * because we're accessing it in non-dispatch thread. DsfServiceTracker is
+ * not thread-safe.
+ */
+ @ThreadSafe
+ private ServiceTracker fServiceTracker;
+
+
+ public SyncVariableDataAccess(DsfSession session) {
+ fSession = session;
+ }
+
+ @ThreadSafe
+ private synchronized IExpressions getService() {
+
+ if (fServiceTracker == null) {
+ try {
+ fServiceTracker = new ServiceTracker(
+ DsfUIPlugin.getBundleContext(),
+ DsfUIPlugin.getBundleContext().createFilter(getServiceFilter()), null);
+ fServiceTracker.open();
+ } catch (InvalidSyntaxException e) {
+ return null;
+ }
+ }
+ return (IExpressions) fServiceTracker.getService();
+ }
+
+ private String getServiceFilter() {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(&"); //$NON-NLS-1$
+ filter.append("(OBJECTCLASS="); //$NON-NLS-1$
+ filter.append(IExpressions.class.getName());
+ filter.append(')');
+ filter.append('(');
+ filter.append(IDsfService.PROP_SESSION_ID);
+ filter.append('=');
+ filter.append(fSession.getId());
+ filter.append(')');
+ filter.append(')');
+ return filter.toString();
+ }
+
+ @ThreadSafe
+ public synchronized void dispose() {
+ if (fServiceTracker != null) {
+ fServiceTracker.close();
+ }
+ }
+
+ public IExpressionDMContext getVariableDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IExpressionDMContext) ((IAdaptable) element).getAdapter(IExpressionDMContext.class);
+ }
+ return null;
+ }
+
+
+ public class GetVariableValueQuery extends Query<IExpressionDMData> {
+
+ private IExpressionDMContext fDmc;
+
+ public GetVariableValueQuery(IExpressionDMContext dmc) {
+ super();
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<IExpressionDMData> rm) {
+ /*
+ * Guard against the session being disposed. If session is disposed
+ * it could mean that the executor is shut-down, which in turn could
+ * mean that we can't complete the RequestMonitor argument. in that
+ * case, cancel to notify waiting thread.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ IExpressions service = getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service not available", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ service.getExpressionData(fDmc, new DataRequestMonitor<IExpressionDMData>(session.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public IExpressionDMContext getExpressionDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IExpressionDMContext) ((IAdaptable) element).getAdapter(IExpressionDMContext.class);
+ }
+ return null;
+ }
+
+ public IExpressionDMData readVariable(Object element) {
+ /*
+ * Get the DMC and the session. If element is not an expression DMC, or
+ * session is stale, then bail out.
+ */
+ IExpressionDMContext dmc = getExpressionDMC(element);
+ if (dmc == null) return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return null;
+
+ /*
+ * Create the query to request the value from service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetVariableValueQuery query = new GetVariableValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class SetVariableValueQuery extends Query<Object> {
+
+ private IExpressionDMContext fDmc;
+ private String fValue;
+ private String fFormatId;
+
+ public SetVariableValueQuery(IExpressionDMContext dmc, String value, String formatId) {
+ super();
+ fDmc = dmc;
+ fValue = value;
+ fFormatId = formatId;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ IExpressions service = getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * Write the expression value using a string/format style.
+ */
+ service.writeExpression(
+ fDmc,
+ fValue,
+ fFormatId,
+ new DataRequestMonitor<IExpressionDMData>(session.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(new Object());
+ rm.done();
+ }
+ }
+ );
+ }
+ }
+
+ public void writeVariable(Object element, String value, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IExpressionDMContext dmc = getExpressionDMC(element);
+ if (dmc == null) return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ SetVariableValueQuery query = new SetVariableValueQuery(dmc, value, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ /*
+ * Return value is irrelevant, any error would come through with an
+ * exception.
+ */
+ query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ } catch (ExecutionException e) {
+ /*
+ * View must be shutting down, no need to show error dialog.
+ */
+ }
+ }
+
+ public IFormattedDataDMContext getFormattedDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IFormattedDataDMContext) ((IAdaptable) element).getAdapter(IFormattedDataDMContext.class);
+ }
+ return null;
+ }
+
+ public class GetSupportFormatsValueQuery extends Query<Object> {
+
+ IFormattedDataDMContext fDmc;
+
+ public GetSupportFormatsValueQuery(IFormattedDataDMContext dmc) {
+ super();
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ IExpressions service = getService();
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * Get the available formats from the service.
+ */
+ service.getAvailableFormats(
+ fDmc,
+ new DataRequestMonitor<String[]>(session.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(new Object());
+ rm.done();
+ }
+ }
+ );
+ }
+ }
+
+ public String[] getSupportedFormats(Object element) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IFormattedDataDMContext dmc = getFormattedDMC(element);
+ if (dmc == null) return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return null;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetSupportFormatsValueQuery query = new GetSupportFormatsValueQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return (String[]) query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public class GetFormattedValueValueQuery extends Query<Object> {
+
+ private IFormattedDataDMContext fDmc;
+ private String fFormatId;
+
+ public GetFormattedValueValueQuery(IFormattedDataDMContext dmc, String formatId) {
+ super();
+ fDmc = dmc;
+ fFormatId = formatId;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ IExpressions service = getService();
+ if (service == null) {
+ rm .setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * Convert to the proper formatting DMC then go get the formatted value.
+ */
+
+ FormattedValueDMContext formDmc = service.getFormattedValueContext(fDmc, fFormatId);
+
+ service.getFormattedExpressionValue(formDmc, new DataRequestMonitor<FormattedValueDMData>(session.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData().getFormattedValue());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public String getFormattedValue(Object element, String formatId) {
+
+ /*
+ * Get the DMC and the session. If element is not an register DMC, or
+ * session is stale, then bail out.
+ */
+ IFormattedDataDMContext dmc = getFormattedDMC(element);
+ if (dmc == null) return null;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return null;
+
+ /*
+ * Create the query to write the value to the service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ GetFormattedValueValueQuery query = new GetFormattedValueValueQuery(dmc, formatId);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return (String) query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return null;
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @since 1.1
+ */
+ public class CanWriteExpressionQuery extends Query<Boolean> {
+
+ private IExpressionDMContext fDmc;
+
+ public CanWriteExpressionQuery(IExpressionDMContext dmc) {
+ super();
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Boolean> rm) {
+ /*
+ * We're in another dispatch, so we must guard against executor
+ * shutdown again.
+ */
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ rm.done();
+ return;
+ }
+
+ /*
+ * Guard against a disposed service
+ */
+ IExpressions service = getService();
+ if (service == null) {
+ rm .setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service unavailable", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ service.canWriteExpression(fDmc, new DataRequestMonitor<Boolean>(session.getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ /*
+ * All good set return value.
+ */
+ rm.setData(getData());
+ rm.done();
+ }
+ });
+ }
+ }
+
+ public boolean canWriteExpression(Object element) {
+ /*
+ * Get the DMC and the session. If element is not an expression DMC, or
+ * session is stale, then bail out.
+ */
+ IExpressionDMContext dmc = getExpressionDMC(element);
+ if (dmc == null) return false;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return false;
+
+ /*
+ * Create the query to make the request to the service. Note: no need to
+ * guard against RejectedExecutionException, because
+ * DsfSession.getSession() above would only return an active session.
+ */
+ CanWriteExpressionQuery query = new CanWriteExpressionQuery(dmc);
+ session.getExecutor().execute(query);
+
+ /*
+ * Now we have the data, go and get it. Since the call is completed now
+ * the ".get()" will not suspend it will immediately return with the
+ * data.
+ */
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ assert false;
+ return false;
+ } catch (ExecutionException e) {
+ return false;
+ }
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableCellModifier.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableCellModifier.java
new file mode 100644
index 00000000000..7d558cbbd5e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableCellModifier.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.WatchExpressionCellModifier;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.UserEditEvent;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+@SuppressWarnings("restriction")
+public class VariableCellModifier extends WatchExpressionCellModifier {
+
+ private AbstractCachingVMProvider fProvider;
+ private SyncVariableDataAccess fDataAccess = null;
+ private IFormattedValuePreferenceStore fPrefStore;
+
+ public VariableCellModifier(AbstractCachingVMProvider provider,
+ IFormattedValuePreferenceStore formattedValuePreferenceStore, SyncVariableDataAccess access)
+ {
+ fProvider = provider;
+ fDataAccess = access;
+ fPrefStore = formattedValuePreferenceStore;
+ }
+
+ /*
+ * Used to make sure we are dealing with a valid variable.
+ */
+ private IExpressionDMContext getVariableDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IExpressionDMContext)((IAdaptable)element).getAdapter(IExpressionDMContext.class);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean canModify(Object element, String property) {
+ // If we're in the column value, modify the register data. Otherwise, call the super-class to edit
+ // the watch expression.
+
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) {
+ // Make sure we are are dealing with a valid set of information.
+
+ if (getVariableDMC(element) == null) {
+ return false;
+ }
+
+ return fDataAccess.canWriteExpression(element);
+ }
+
+ return super.canModify(element, property);
+ }
+
+ @Override
+ public Object getValue(Object element, String property) {
+ // If we're in the column value, modify the variable value. Otherwise, call the super-class to edit
+ // the watch expression.
+
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fPrefStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ String value = fDataAccess.getFormattedValue(element, formatId);
+
+ if (value == null) {
+ return "..."; //$NON-NLS-1$
+ }
+
+ return value;
+ }
+
+ return super.getValue(element, property);
+ }
+
+ @Override
+ public void modify(Object element, String property, Object value) {
+ /*
+ * If we're in the column value, modify the register data. Otherwise, call the super-class to edit
+ * the watch expression.
+ */
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(property)) {
+ if (value instanceof String) {
+ /*
+ * We let the Model provider supply the current format.
+ */
+ String formatId;
+
+ if ( element instanceof IVMContext) {
+ /*
+ * Find the presentation context and then use it to get the current desired format.
+ */
+ IVMContext ctx = (IVMContext) element;
+ IPresentationContext presCtx = ctx.getVMNode().getVMProvider().getPresentationContext();
+
+ formatId = fPrefStore.getCurrentNumericFormat(presCtx);
+ }
+ else {
+ formatId = IFormattedValues.NATURAL_FORMAT;
+ }
+
+ fDataAccess.writeVariable(element, (String) value, formatId);
+ fProvider.handleEvent(new UserEditEvent(element));
+ }
+ }
+ else {
+ super.modify(element, property, value);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableColumnPresentation.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableColumnPresentation.java
new file mode 100644
index 00000000000..725b02c0c59
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableColumnPresentation.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class VariableColumnPresentation implements IColumnPresentation {
+ public static final String ID = DsfUIPlugin.PLUGIN_ID + ".VARIABLES_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#init(org.eclipse.debug.internal.ui.viewers.provisional.IPresentationContext)
+ public void init(IPresentationContext context) {}
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#dispose()
+ public void dispose() {}
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getAvailableColumns()
+ public String[] getAvailableColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__NAME, IDebugVMConstants.COLUMN_ID__TYPE, IDebugVMConstants.COLUMN_ID__VALUE, IDebugVMConstants.COLUMN_ID__ADDRESS };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getHeader(java.lang.String)
+ public String getHeader(String id) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(id)) {
+ return MessagesForVariablesVM.VariableColumnPresentation_name;
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(id)) {
+ return MessagesForVariablesVM.VariableColumnPresentation_type;
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(id)) {
+ return MessagesForVariablesVM.VariableColumnPresentation_value;
+ } else if (IDebugVMConstants.COLUMN_ID__ADDRESS.equals(id)) {
+ return MessagesForVariablesVM.VariableColumnPresentation_address;
+ }
+ return null;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getId()
+ public String getId() {
+ return ID;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getImageDescriptor(java.lang.String)
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#getInitialColumns()
+ public String[] getInitialColumns() {
+ return new String[] { IDebugVMConstants.COLUMN_ID__NAME, IDebugVMConstants.COLUMN_ID__TYPE, IDebugVMConstants.COLUMN_ID__VALUE };
+ }
+
+ // @see org.eclipse.debug.internal.ui.viewers.provisional.IColumnPresentation#isOptional()
+ public boolean isOptional() {
+ return true;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
new file mode 100644
index 00000000000..bed8ab511e7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
@@ -0,0 +1,995 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IVariableDMData;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.AbstractExpressionVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.IExpressionUpdate;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IFormattedValueVMContext;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.utils.Addr32;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.IInternalDebugUIConstants;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.ui.actions.IWatchExpressionFactoryAdapter2;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IMemento;
+
+@SuppressWarnings({"restriction", "nls"})
+public class VariableVMNode extends AbstractExpressionVMNode
+ implements IElementEditor, IElementLabelProvider, IElementMementoProvider
+{
+
+ private final IFormattedValuePreferenceStore fFormattedPrefStore;
+
+ private final SyncVariableDataAccess fSyncVariableDataAccess;
+
+ public class VariableExpressionVMC extends DMVMContext implements IFormattedValueVMContext {
+
+ private IExpression fExpression;
+
+ public VariableExpressionVMC(IDMContext dmc) {
+ super(dmc);
+ }
+
+ public IFormattedValuePreferenceStore getPreferenceStore() {
+ return fFormattedPrefStore;
+ }
+
+ public void setExpression(IExpression expression) {
+ fExpression = expression;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (fExpression != null && adapter.isAssignableFrom(fExpression.getClass())) {
+ return fExpression;
+ } else if (adapter.isAssignableFrom(IWatchExpressionFactoryAdapter2.class)) {
+ return fVariableExpressionFactory;
+ } else {
+ return super.getAdapter(adapter);
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof VariableExpressionVMC && super.equals(other)) {
+ VariableExpressionVMC otherGroup = (VariableExpressionVMC)other;
+ return (otherGroup.fExpression == null && fExpression == null) ||
+ (otherGroup.fExpression != null && otherGroup.fExpression.equals(fExpression));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.hashCode() + (fExpression != null ? fExpression.hashCode() : 0);
+ }
+ }
+
+ protected class VariableExpressionFactory implements IWatchExpressionFactoryAdapter2 {
+
+ public boolean canCreateWatchExpression(Object element) {
+ return element instanceof VariableExpressionVMC;
+ }
+
+ public String createWatchExpression(Object element) throws CoreException {
+
+ VariableExpressionVMC exprVmc = (VariableExpressionVMC) element;
+
+ IExpressionDMContext exprDmc = DMContexts.getAncestorOfType(exprVmc.getDMContext(), IExpressionDMContext.class);
+ if (exprDmc != null) {
+ return exprDmc.getExpression();
+ }
+
+ return null;
+ }
+ }
+
+ final protected VariableExpressionFactory fVariableExpressionFactory = new VariableExpressionFactory();
+
+ public VariableVMNode(IFormattedValuePreferenceStore prefStore, AbstractDMVMProvider provider,
+ DsfSession session, SyncVariableDataAccess syncVariableDataAccess)
+ {
+ super(provider, session, IExpressions.IExpressionDMContext.class);
+ fFormattedPrefStore = prefStore;
+ fSyncVariableDataAccess = syncVariableDataAccess;
+ }
+
+ @Override
+ public String toString() {
+ return "VariableVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new VariableExpressionVMC(dmc);
+ }
+
+
+ public void update(final ILabelUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ updateLabelInSessionThread(updates);
+ }});
+ } catch (RejectedExecutionException e) {
+ for (ILabelUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ private void fillInExpressionErrorInfo( ILabelUpdate update, IExpressionDMContext dmc, IStatus status ) {
+ /*
+ * Instead of just failing this outright we are going to attempt to do more here.
+ * Failing it outright causes the view to display ... for all columns in the line
+ * and this is uninformative about what is happening. It will be very common that
+ * one or more variables at that given instance in time are not evaluatable. They
+ * may be out of scope and will come back into scope later.
+ */
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null)
+ localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ update.setLabel(dmc.getExpression(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ update.setLabel("", idx);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ update.setLabel("Error : " + status.getMessage(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__ADDRESS.equals(localColumns[idx])) {
+ update.setLabel("", idx);
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel("", idx);
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ update.setLabel(dmc.getExpression(), idx);
+ } else {
+ update.setLabel("", idx);
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+ }
+
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+
+ final IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class);
+
+ if ( dmc == null ) {
+ // Workaround for a bug in platform, where the find operation may use wrong label provider.
+ // See bug 246618.
+ update.done();
+ continue;
+ }
+
+ getDMVMProvider().getModelData(
+ this, update,
+ getServicesTracker().getService(IExpressions.class, null),
+ dmc,
+ new ViewerDataRequestMonitor<IExpressionDMData>(getSession().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ // Check that the request was evaluated and data is still valid. The request could
+ // fail if the state of the service changed during the request, but the view model
+ // has not been updated yet.
+ if (!isSuccess()) {
+ assert getStatus().isOK() ||
+ getStatus().getCode() != IDsfStatusConstants.INTERNAL_ERROR ||
+ getStatus().getCode() != IDsfStatusConstants.NOT_SUPPORTED;
+
+ fillInExpressionErrorInfo( update, dmc, getStatus() );
+
+ update.done();
+ return;
+ }
+
+ // If columns are configured, extract the selected values for each understood column.
+ // First, we fill all of those columns which can be filled without extra data mining.
+ // We also note if we do have to do extra data mining. Any columns need to set the
+ // processing flag so we know we have further work to do. If there are more columns
+ // which need data extraction they need to be added in both "for" loops.
+ String[] localColumns = update.getColumnIds();
+ if (localColumns == null)
+ localColumns = new String[] { IDebugVMConstants.COLUMN_ID__NAME };
+
+ int extractingFormattedDataIndex = -1;
+ int extractingAddressDataIndex = -1;
+
+ for (int idx = 0; idx < localColumns.length; idx++) {
+ if (IDebugVMConstants.COLUMN_ID__NAME.equals(localColumns[idx])) {
+ update.setLabel(getData().getName(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__TYPE.equals(localColumns[idx])) {
+ update.setLabel(getData().getTypeName(), idx);
+ } else if (IDebugVMConstants.COLUMN_ID__VALUE.equals(localColumns[idx])) {
+ extractingFormattedDataIndex = idx;
+ } else if (IDebugVMConstants.COLUMN_ID__ADDRESS.equals(localColumns[idx])) {
+ extractingAddressDataIndex = idx;
+ } else if (IDebugVMConstants.COLUMN_ID__DESCRIPTION.equals(localColumns[idx])) {
+ update.setLabel("", idx);
+ } else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(localColumns[idx])) {
+ IVMContext vmc = (IVMContext)update.getElement();
+ IExpression expression = (IExpression)vmc.getAdapter(IExpression.class);
+ if (expression != null) {
+ update.setLabel(expression.getExpressionText(), idx);
+ } else {
+ update.setLabel(getData().getName(), idx);
+ }
+ }
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], idx);
+ }
+
+ if ( ( extractingFormattedDataIndex == -1 ) && ( extractingAddressDataIndex == -1 ) ) {
+ update.done();
+ } else {
+ /*
+ * We are either updating the value or the address or possibly both.
+ * We will create a overarching monitor to handle completing the update
+ * when either/both of the lower level updates are done.
+ */
+ final DsfExecutor dsfExecutor = getSession().getExecutor();
+
+ final MultiRequestMonitor<RequestMonitor> mrm =
+ new MultiRequestMonitor<RequestMonitor>(dsfExecutor, null) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ update.done();
+ }
+ };
+
+ /*
+ * Deal with the value.
+ */
+ if ( extractingFormattedDataIndex != -1 ) {
+ RequestMonitor rm = new RequestMonitor(dsfExecutor, null) {
+ @Override
+ public void handleCompleted() {
+ mrm.requestMonitorDone(this);
+ }
+ };
+
+ mrm.add(rm);
+ updateFormattedExpressionValue(update, extractingFormattedDataIndex, dmc, getData(),rm);
+ }
+
+ /*
+ * Deal with the address.
+ */
+ if ( extractingAddressDataIndex != -1 ) {
+ RequestMonitor rm = new RequestMonitor(dsfExecutor, null) {
+ @Override
+ public void handleCompleted() {
+ mrm.requestMonitorDone(this);
+ }
+ };
+
+ mrm.add(rm);
+ updateAddressData(update, extractingAddressDataIndex, dmc, rm);
+ }
+ }
+ }
+ },
+ getExecutor()
+ );
+ }
+ }
+
+ /**
+ * Private data access routine which performs the extra level of data access needed to
+ * get the formatted data value for a specific register.
+ */
+ private void updateAddressData(final ILabelUpdate update,
+ final int labelIndex,
+ final IExpressionDMContext dmc,
+ final RequestMonitor monitor)
+ {
+ /*
+ * First select the format to be used. This involves checking so see that the preference
+ * page format is supported by the register service. If the format is not supported then
+ * we will pick the first available format.
+ */
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+
+ // Get the variable information and update the corresponding memory locations
+ if (expressionService != null) {
+ expressionService.getExpressionAddressData(dmc,
+ new DataRequestMonitor<IExpressionDMAddress>(getExecutor(), monitor) {
+ @Override
+ protected void handleCompleted() {
+ if ( isSuccess() ) {
+ // Figure out which memory area was modified
+ IExpressionDMAddress expression = getData();
+ IAddress expAddress = expression.getAddress();
+ if (expAddress instanceof Addr64) {
+ update.setLabel( "0x" + ((Addr64) expAddress).toString(16), labelIndex);
+ }
+ else if (expAddress instanceof Addr32) {
+ update.setLabel( "0x" + ((Addr32) expAddress).toString(16), labelIndex);
+ }
+ else {
+ update.setLabel( "Unknown address format", labelIndex);
+ }
+ }
+ else {
+ /*
+ * We could not get the format. Currently GDB does not handle getting the address of
+ * a constant for example. We could put the error message in, but that would not be
+ * all that helpful top the user. The interface is a new one and perhaps failing to
+ * return a valid set of information is just saying it does not exist. Anyway, for
+ * now we will just put nothing in.
+ */
+ update.setLabel( "", labelIndex);
+ }
+
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
+ monitor.done();
+ }
+ }
+ );
+ }
+ }
+
+ /**
+ * Private data access routine which performs the extra level of data access needed to
+ * get the formatted data value for a specific register.
+ */
+ private void updateFormattedExpressionValue(final ILabelUpdate update,
+ final int labelIndex,
+ final IExpressionDMContext dmc,
+ final IExpressionDMData expressionDMData,
+ final RequestMonitor monitor)
+ {
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+ /*
+ * First select the format to be used. This involves checking so see that the preference
+ * page format is supported by the register service. If the format is not supported then
+ * we will pick the first available format.
+ */
+ final IPresentationContext context = update.getPresentationContext();
+ final String preferencePageFormatId = fFormattedPrefStore.getCurrentNumericFormat(context) ;
+
+ expressionService.getAvailableFormats(
+ dmc,
+ new DataRequestMonitor<String[]>(getSession().getExecutor(), monitor) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ monitor.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Format information not available", null));
+ monitor.done();
+ return;
+ }
+
+ /*
+ * See if the desired format is supported.
+ */
+ final String[] formatIds = getData();
+ String finalFormatId = IFormattedValues.NATURAL_FORMAT;
+ boolean requestedFormatIsSupported = false;
+
+ for ( String fId : formatIds ) {
+ if ( preferencePageFormatId.equals(fId) ) {
+ // The desired format is supported.
+
+ finalFormatId = preferencePageFormatId;
+ requestedFormatIsSupported = true;
+ break;
+ }
+ }
+
+ if ( ! requestedFormatIsSupported ) {
+ /*
+ * Desired format is not supported. If there are any formats supported
+ * then use the first available.
+ */
+ if ( formatIds.length != 0 ) {
+ finalFormatId = formatIds[0];
+ }
+ else {
+ // Expression service does not support any format.
+
+ monitor.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service does not support any formats", null));
+ monitor.done();
+ return;
+ }
+ }
+
+ /*
+ * Format has been validated. Get the formatted value.
+ */
+ final FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(dmc, finalFormatId);
+
+ getDMVMProvider().getModelData(
+ VariableVMNode.this,
+ update,
+ expressionService,
+ valueDmc,
+ new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), monitor) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ monitor.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, getStatus().getMessage(), null));
+ monitor.done();
+ return;
+ }
+
+ final String formattedValue = getData().getFormattedValue();
+ final String formattedStringId = valueDmc.getFormatID();
+
+ if ( formattedStringId.equals(IFormattedValues.STRING_FORMAT) ) {
+ /*
+ * In this case we are being asked to fill in the value information with STRING_FORMAT.
+ * So we do not need to append it to the value as we did in the past.
+ */
+ completeFillinInUpdateWithValue(update, labelIndex, valueDmc, formattedValue, null, null, monitor);
+ }
+ else {
+ /*
+ * The format specified is not STRING_FORMAT and as we did before we need to append
+ * the string information to the value ( if it exists ). So first see if STRING_FORMAT
+ * is supported by the service.
+ */
+ boolean foundStringFormat = false;
+
+ for ( String format : formatIds ) {
+ if ( format.equals(IFormattedValues.STRING_FORMAT) ) {
+ foundStringFormat = true;
+ }
+ }
+
+ if ( foundStringFormat ) {
+ /*
+ * So STRING_FORMAT is supported so we can go get it and append it to the value.
+ *
+ * Note : Currently the Reference Model MI Expression Service does not support the
+ * STRING_FORMAT. The view still pretty much looks the same however, to one
+ * where the STRING_FORMAT is supplied. This is because when GDB is ask to
+ * evaluate a variable it will return the STRING_FORMAT information appended
+ * to the address so it looks good. GDB appends all kinds of usefull info to
+ * requests for data values, based on the value types. So the expressions do
+ * look good. If the Reference Model Expression Service ever does implement
+ * STRING_FORMAT this will need to be revisited. There would be duplicate
+ * information displayed and the view would look broken. However this needs
+ * to be put back in to satisfy Bugzilla defect "225612", which represents a
+ * regression in the display of data from 0.9 to 1.x.
+ */
+ final FormattedValueDMContext stringDmc = expressionService.getFormattedValueContext(dmc, IFormattedValues.STRING_FORMAT);
+
+ getDMVMProvider().getModelData(
+ VariableVMNode.this,
+ update,
+ expressionService,
+ stringDmc,
+ new DataRequestMonitor<FormattedValueDMData>(getSession().getExecutor(), monitor) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ monitor.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, getStatus().getMessage(), null));
+ monitor.done();
+ return;
+ }
+
+ String stringValue = getData().getFormattedValue();
+
+ completeFillinInUpdateWithValue(update, labelIndex, valueDmc, formattedValue, stringDmc, stringValue, monitor);
+ }
+ },
+ getExecutor()
+ );
+ }
+ else {
+ /*
+ * The STRING_FORMAT is not supported. So all we can do is fill it in without it.
+ */
+ completeFillinInUpdateWithValue(update, labelIndex, valueDmc, formattedValue, null, null, monitor);
+ }
+ }
+ }
+ },
+ getExecutor()
+ );
+ }
+ }
+ );
+ }
+
+ private void completeFillinInUpdateWithValue(ILabelUpdate update,
+ int labelIndex,
+ FormattedValueDMContext valueDmc,
+ String value,
+ FormattedValueDMContext stringFormatDmc,
+ String stringFormatValue,
+ RequestMonitor monitor)
+ {
+ /*
+ * Complete filling in the VALUE. The form is
+ *
+ * "Numerical value" "STRING_FORMAT value"
+ *
+ * This makes it so if the value is a pointer to something else we conveniently
+ * fill in the something else ( typically a string ).
+ */
+
+ StringBuffer stringValueBuf = new StringBuffer(value);
+ if(stringFormatValue != null && stringFormatValue.length() > 0)
+ {
+ stringValueBuf.append(" ");
+ stringValueBuf.append(stringFormatValue);
+ }
+ update.setLabel(stringValueBuf.toString(), labelIndex);
+ update.setFontData(JFaceResources.getFontDescriptor(IInternalDebugUIConstants.VARIABLE_TEXT_FONT).getFontData()[0], labelIndex);
+
+ /*
+ * Get old values for comparison ( if available ).
+ */
+ FormattedValueDMData oldStringData = null;
+ FormattedValueDMData oldData =
+
+ (FormattedValueDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, valueDmc);
+
+ if ( stringFormatDmc != null) {
+ oldStringData = (FormattedValueDMData) getDMVMProvider().getArchivedModelData(VariableVMNode.this, update, stringFormatDmc);
+ }
+
+ /*
+ * Highlight the value if either the value (address) has changed or the string (memory at the value) has changed
+ */
+ if ( ( oldData != null && ! oldData.getFormattedValue().equals(value) ) ||
+ ( oldStringData != null && ! oldStringData.getFormattedValue().equals(stringFormatValue) )
+ ) {
+ RGB rgb = DebugUIPlugin.getPreferenceColor(IInternalDebugUIConstants.PREF_CHANGED_VALUE_BACKGROUND).getRGB();
+ update.setBackground(rgb, labelIndex);
+ }
+
+ /*
+ * Now we finally can complete this one.
+ */
+ monitor.done();
+ }
+
+ public CellEditor getCellEditor(IPresentationContext context, String columnId, Object element, Composite parent) {
+ if (IDebugVMConstants.COLUMN_ID__VALUE.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ else if (IDebugVMConstants.COLUMN_ID__EXPRESSION.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+
+ return null;
+ }
+
+ public ICellModifier getCellModifier(IPresentationContext context, Object element) {
+ return new VariableCellModifier(getDMVMProvider(), fFormattedPrefStore, fSyncVariableDataAccess);
+ }
+
+ public boolean canParseExpression(IExpression expression) {
+ // At this point we are going to say we will allow anything as an expression.
+ // Since the evaluation of VM Node implementations searches in the order of
+ // registration and we always make sure we register the VariableVMNode last,
+ // we know that the other possible handlers have passed the expression by. So
+ // we are going to say OK and let the expression evaluation of whatever debug
+ // backend is connected to decide. This does not allow us to put up any good
+ // diagnostic error message ( instead the error will come from the backend ).
+ // But it does allow for the most flexibility
+
+ return true;
+ }
+
+ @Override
+ public void update(final IExpressionUpdate update) {
+ try {
+ getSession().getExecutor().execute(new Runnable() {
+ public void run() {
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+ if (expressionService != null) {
+ IExpressionDMContext expressionDMC = expressionService.createExpression(
+ createCompositeDMVMContext(update),
+ update.getExpression().getExpressionText());
+ VariableExpressionVMC variableVmc = new VariableExpressionVMC(expressionDMC);
+ variableVmc.setExpression(update.getExpression());
+
+ update.setExpressionElement(variableVmc);
+ update.done();
+ } else {
+ handleFailedUpdate(update);
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ handleFailedUpdate(update);
+ }
+ }
+
+
+ @Override
+ protected void handleFailedUpdate(IViewerUpdate update) {
+ if (update instanceof IExpressionUpdate) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Update failed", null)); //$NON-NLS-1$
+ update.done();
+ } else {
+ super.handleFailedUpdate(update);
+ }
+ }
+ @Override
+ protected void associateExpression(Object element, IExpression expression) {
+ if (element instanceof VariableExpressionVMC) {
+ ((VariableExpressionVMC)element).setExpression(expression);
+ }
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ // Get the data model context object for the current node in the hierarchy.
+
+ final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if ( expressionDMC != null ) {
+ getSubexpressionsUpdateElementsInSessionThread( update );
+ }
+ else {
+ getLocalsUpdateElementsInSessionThread( update );
+ }
+ }
+
+ private void getSubexpressionsUpdateElementsInSessionThread(final IChildrenUpdate update) {
+
+ final IExpressionDMContext expressionDMC = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressionDMContext.class);
+
+ if ( expressionDMC != null ) {
+
+ // Get the services we need to use.
+
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+
+ if (expressionService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ final DsfExecutor dsfExecutor = getSession().getExecutor();
+
+ // Call IExpressions.getSubExpressions() to get an Iterable of IExpressionDMContext objects representing
+ // the sub-expressions of the expression represented by the current expression node.
+
+ final DataRequestMonitor<IExpressionDMContext[]> rm =
+ new ViewerDataRequestMonitor<IExpressionDMContext[]>(dsfExecutor, update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }
+ };
+
+ // Make the asynchronous call to IExpressions.getSubExpressions(). The results are processed in the
+ // DataRequestMonitor.handleCompleted() above.
+
+ expressionService.getSubExpressions(expressionDMC, rm);
+ } else {
+ handleFailedUpdate(update);
+ }
+ }
+
+ private void getLocalsUpdateElementsInSessionThread(final IChildrenUpdate update) {
+
+ final IFrameDMContext frameDmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IFrameDMContext.class);
+
+ // Get the services we need to use.
+
+ final IExpressions expressionService = getServicesTracker().getService(IExpressions.class);
+ final IStack stackFrameService = getServicesTracker().getService(IStack.class);
+
+ if ( frameDmc == null || expressionService == null || stackFrameService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ final DsfExecutor dsfExecutor = getSession().getExecutor();
+
+ // Call IStack.getLocals() to get an array of IVariableDMContext objects representing the local
+ // variables in the stack frame represented by frameDmc.
+
+ final DataRequestMonitor<IVariableDMContext[]> rm =
+ new ViewerDataRequestMonitor<IVariableDMContext[]>(dsfExecutor, update) {
+ @Override
+ public void handleCompleted() {
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // For each IVariableDMContext object returned by IStack.getLocals(), call
+ // MIStackFrameService.getModelData() to get the IVariableDMData object. This requires
+ // a MultiRequestMonitor object.
+
+ // First, get the data model context objects for the local variables.
+
+ IVariableDMContext[] localsDMCs = getData();
+
+ if (localsDMCs == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ if ( localsDMCs.length == 0 ) {
+ // There are no locals so just complete the request
+ update.done();
+ return;
+ }
+
+ // Create a List in which we store the DM data objects for the local variables. This is
+ // necessary because there is no MultiDataRequestMonitor. :)
+
+ final List<IVariableDMData> localsDMData = new ArrayList<IVariableDMData>();
+
+ // Create the MultiRequestMonitor to handle completion of the set of getModelData() calls.
+
+ final MultiRequestMonitor<DataRequestMonitor<IVariableDMData>> mrm =
+ new MultiRequestMonitor<DataRequestMonitor<IVariableDMData>>(dsfExecutor, null) {
+ @Override
+ public void handleCompleted() {
+ // Now that all the calls to getModelData() are complete, we create an
+ // IExpressionDMContext object for each local variable name, saving them all
+ // in an array.
+
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ IExpressionDMContext[] expressionDMCs = new IExpressionDMContext[localsDMData.size()];
+
+ int i = 0;
+
+ for (IVariableDMData localDMData : localsDMData) {
+ expressionDMCs[i++] = expressionService.createExpression(frameDmc, localDMData.getName());
+ }
+
+ // Lastly, we fill the update from the array of view model context objects
+ // that reference the ExpressionDMC objects for the local variables. This is
+ // the last code to run for a given call to updateElementsInSessionThread().
+ // We can now leave anonymous-inner-class hell.
+
+ fillUpdateWithVMCs(update, expressionDMCs);
+ update.done();
+ }
+ };
+
+ // Perform a set of getModelData() calls, one for each local variable's data model
+ // context object. In the handleCompleted() method of the DataRequestMonitor, add the
+ // IVariableDMData object to the localsDMData List for later processing (see above).
+
+ for (IVariableDMContext localDMC : localsDMCs) {
+ DataRequestMonitor<IVariableDMData> rm =
+ new ViewerDataRequestMonitor<IVariableDMData>(dsfExecutor, update) {
+ @Override
+ public void handleCompleted() {
+ localsDMData.add(getData());
+ mrm.requestMonitorDone(this);
+ }
+ };
+
+ mrm.add(rm);
+
+ getDMVMProvider().getModelData(VariableVMNode.this, update, stackFrameService, localDMC, rm, getExecutor());
+ }
+ }
+ };
+
+ // Make the asynchronous call to IStack.getLocals(). The results are processed in the
+ // DataRequestMonitor.handleCompleted() above.
+
+ stackFrameService.getLocals(frameDmc, rm);
+ }
+
+ //private final static int MAX_STRING_VALUE_LENGTH = 40;
+
+ public int getDeltaFlags(Object e) {
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IExpressionChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ // Create a delta that the whole register group has changed.
+ return IModelDelta.CONTENT;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(final Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+
+ // The following events can affect any expression's values,
+ // refresh the contents of the parent element (i.e. all the expressions).
+ if ( e instanceof ISuspendedDMEvent ||
+ e instanceof IMemoryChangedEvent ||
+ e instanceof IExpressionChangedDMEvent ||
+ (e instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)e).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ // Create a delta that the whole register group has changed.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ requestMonitor.done();
+ }
+
+ public int getDeltaFlagsForExpression(IExpression expression, Object event) {
+ if ( event instanceof IExpressionChangedDMEvent ||
+ event instanceof IMemoryChangedEvent ||
+ (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ if (event instanceof ISuspendedDMEvent)
+ {
+ return IModelDelta.CONTENT;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDeltaForExpression(IExpression expression, int elementIdx, Object event, VMDelta parentDelta,
+ TreePath path, RequestMonitor rm)
+ {
+ // Always refresh the contents of the view upon suspended event.
+ if (event instanceof ISuspendedDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+
+ public void buildDeltaForExpressionElement(Object element, int elementIdx, Object event, VMDelta parentDelta,
+ RequestMonitor rm)
+ {
+ // The following events can affect expression values, refresh the state
+ // of the expression.
+ if ( event instanceof IExpressionChangedDMEvent ||
+ event instanceof IMemoryChangedEvent ||
+ (event instanceof PropertyChangeEvent &&
+ ((PropertyChangeEvent)event).getProperty() == IDebugVMConstants.CURRENT_FORMAT_STORAGE) )
+ {
+ parentDelta.addNode(element, IModelDelta.CONTENT);
+ }
+
+ rm.done();
+ }
+
+
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ private String produceExpressionElementName( String viewName , IExpressionDMContext expression ) {
+
+ return "Variable." + expression.getExpression(); //$NON-NLS-1$
+ }
+
+ private final String MEMENTO_NAME = "VARIABLE_MEMENTO_NAME"; //$NON-NLS-1$
+
+ public void compareElements(IElementCompareRequest[] requests) {
+
+ for ( IElementCompareRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ String mementoName = memento.getString(MEMENTO_NAME); //$NON-NLS-1$
+
+ if (mementoName != null) {
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof IExpressionDMContext) {
+
+ String elementName = produceExpressionElementName( request.getPresentationContext().getId(), (IExpressionDMContext) dmc );
+ request.setEqual( elementName.equals( mementoName ) );
+ }
+ }
+ }
+ request.done();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+
+ for ( IElementMementoRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof IExpressionDMContext) {
+
+ String elementName = produceExpressionElementName( request.getPresentationContext().getId(), (IExpressionDMContext) dmc );
+ memento.putString(MEMENTO_NAME, elementName);
+ }
+ }
+ request.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java
new file mode 100644
index 00000000000..b6424ae75cf
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMProvider.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.ui.viewmodel.variable;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.ui.DsfDebugUITools;
+import org.eclipse.cdt.dsf.debug.ui.IDsfDebugUIConstants;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValuePreferenceStore;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.update.BreakpointHitUpdatePolicy;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AutomaticUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+
+@SuppressWarnings("restriction")
+public class VariableVMProvider extends AbstractDMVMProvider
+ implements IColumnPresentationFactory
+{
+ private IPropertyChangeListener fPreferencesListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ String property = event.getProperty();
+ if (property.equals(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE)) {
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ setDelayEventHandleForViewUpdate(store.getBoolean(property));
+ }
+ }
+ };
+
+ private IPropertyChangeListener fPresentationContextListener = new IPropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ handleEvent(event);
+ }
+ };
+
+ public VariableVMProvider(AbstractVMAdapter adapter, IPresentationContext context, DsfSession session) {
+ super(adapter, context, session);
+
+ context.addPropertyChangeListener(fPresentationContextListener);
+
+ IPreferenceStore store = DsfDebugUITools.getPreferenceStore();
+ store.addPropertyChangeListener(fPreferencesListener);
+ setDelayEventHandleForViewUpdate(store.getBoolean(IDsfDebugUIConstants.PREF_WAIT_FOR_VIEW_UPDATE_AFTER_STEP_ENABLE));
+
+ /*
+ * Create the variable data access routines.
+ */
+ SyncVariableDataAccess varAccess = new SyncVariableDataAccess(session) ;
+
+ /*
+ * Create the top level node to deal with the root selection.
+ */
+ IRootVMNode rootNode = new RootDMVMNode(this);
+ setRootNode(rootNode);
+
+ /*
+ * Create the next level which represents members of structs/unions/enums and elements of arrays.
+ */
+ IVMNode subExpressioNode = new VariableVMNode(FormattedValuePreferenceStore.getDefault(), this, getSession(), varAccess);
+ addChildNodes(rootNode, new IVMNode[] { subExpressioNode });
+
+ // Configure the sub-expression node to be a child of itself. This way the content
+ // provider will recursively drill-down the variable hierarchy.
+ addChildNodes(subExpressioNode, new IVMNode[] { subExpressioNode });
+ }
+
+ @Override
+ public void dispose() {
+ DsfDebugUITools.getPreferenceStore().removePropertyChangeListener(fPreferencesListener);
+ getPresentationContext().removePropertyChangeListener(fPresentationContextListener);
+ super.dispose();
+ }
+
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return new VariableColumnPresentation();
+ }
+
+ @Override
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return VariableColumnPresentation.ID;
+ }
+
+ @Override
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() };
+ }
+
+ @Override
+ protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+ // To optimize the performance of the view when stepping rapidly, skip all
+ // other events when a suspended event is received, including older suspended
+ // events.
+ return newEvent instanceof ISuspendedDMEvent;
+ }
+
+ @Override
+ public void refresh() {
+ super.refresh();
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ DsfServicesTracker tracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), getSession().getId());
+ IExpressions expressionsService = tracker.getService(IExpressions.class);
+ if (expressionsService instanceof ICachingService) {
+ ((ICachingService)expressionsService).flushCache(null);
+ }
+ tracker.dispose();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session disposed, ignore.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/messages.properties
new file mode 100644
index 00000000000..0b40d097c33
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/messages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2007, 2008 Wind River Systems 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
+# Wind River Systems - added Address
+###############################################################################
+
+VariableColumnPresentation_name=Name
+VariableColumnPresentation_type=Type
+VariableColumnPresentation_value=Value
+VariableColumnPresentation_address=Address
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java
new file mode 100644
index 00000000000..5a2b1e24de3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/internal/ui/DsfUIPlugin.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.internal.ui;
+
+import org.eclipse.cdt.dsf.debug.internal.ui.disassembly.model.SourceDocumentProvider;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfUIPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.dsf.ui"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfUIPlugin fgPlugin;
+
+ private static BundleContext fgBundleContext;
+
+ // The document provider for source documents in the disassembly.
+ private SourceDocumentProvider fSourceDocumentProvider;
+
+ public static boolean DEBUG = false;
+
+ /**
+ * The constructor
+ */
+ public DsfUIPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug")); //$NON-NLS-1$//$NON-NLS-2$
+
+ fSourceDocumentProvider = new SourceDocumentProvider();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ fSourceDocumentProvider.dispose();
+ fSourceDocumentProvider = null;
+ fgPlugin = null;
+ fgBundleContext = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfUIPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+ /**
+ * Returns an image descriptor for the image file at the given
+ * plug-in relative path
+ *
+ * @param path the path
+ * @return the image descriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+ public static SourceDocumentProvider getSourceDocumentProvider() {
+ return getDefault().fSourceDocumentProvider;
+ }
+
+
+ /**
+ * If the debug flag is set the specified message is printed to the console
+ * @param message
+ */
+ public static void debug(String message) {
+ if (DEBUG) {
+ System.out.println(message);
+ }
+ }
+
+ /**
+ * Logs the specified status with this plug-in's log.
+ *
+ * @param status status to log
+ */
+ public static void log(IStatus status) {
+ getDefault().getLog().log(status);
+ }
+
+ /**
+ * Logs the specified throwable with this plug-in's log.
+ *
+ * @param t throwable to log
+ */
+ public static void log(Throwable t) {
+ log(newErrorStatus("Error logged from Debug UI: ", t)); //$NON-NLS-1$
+ }
+
+ /**
+ * Logs an internal error with the specified message.
+ *
+ * @param message the error message to log
+ */
+ public static void logErrorMessage(String message) {
+ // this message is intentionally not internationalized, as an exception may
+ // be due to the resource bundle itself
+ log(newErrorStatus("Internal message logged from Debug UI: " + message, null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns a new error status for this plug-in with the given message
+ * @param message the message to be included in the status
+ * @param exception the exception to be included in the status or <code>null</code> if none
+ * @return a new error status
+ */
+ public static IStatus newErrorStatus(String message, Throwable exception) {
+ return new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDebugUIConstants.INTERNAL_ERROR, message, exception);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/DisplayDsfExecutor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/DisplayDsfExecutor.java
new file mode 100644
index 00000000000..46fbbed0c50
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/DisplayDsfExecutor.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.concurrent;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutable;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+/**
+ * DSF executor which uses the display thread to run the submitted runnables
+ * and callables. The implementation is based on the default DSF executor
+ * which still creates its own thread. However this thread blocks when running
+ * each executable in the display thread.
+ */
+public class DisplayDsfExecutor extends DefaultDsfExecutor
+{
+ /**
+ * Internal mapping of display objects to executors.
+ */
+ private static Map<Display, DisplayDsfExecutor> fExecutors = Collections.synchronizedMap( new HashMap<Display, DisplayDsfExecutor>() );
+
+ /**
+ * Factory method for display executors.
+ * @param display Display to create an executor for.
+ * @return The new (or re-used) executor.
+ */
+ public static DisplayDsfExecutor getDisplayDsfExecutor(Display display) {
+ synchronized (fExecutors) {
+ DisplayDsfExecutor executor = fExecutors.get(display);
+ if (executor == null) {
+ executor = new DisplayDsfExecutor(display);
+ fExecutors.put(display, executor);
+ }
+ return executor;
+ }
+ }
+
+ /**
+ * The display class used by this executor to execute the submitted runnables.
+ */
+ private final Display fDisplay;
+
+ private DisplayDsfExecutor(Display display) {
+ super("Display DSF Executor"); //$NON-NLS-1$
+ fDisplay = display;
+ fDisplay.addListener(SWT.Dispose, new Listener() {
+ public void handleEvent(Event event) {
+ if (event.type == SWT.Dispose) {
+ DisplayDsfExecutor.super.shutdownNow();
+ }
+ }
+ });
+ }
+
+ /**
+ * Override to check if we're in the display thread rather than the helper
+ * thread of the super-class.
+ */
+ @Override
+ public boolean isInExecutorThread() {
+ return Thread.currentThread().equals(fDisplay.getThread());
+ }
+
+ /**
+ * Creates a callable wrapper, which delegates to the display to perform the
+ * operation. The callable blocks the executor thread while each call
+ * is executed in the display thred.
+ * @param <V> Type used in the callable.
+ * @param callable Callable to wrap.
+ * @return Wrapper callable.
+ */
+ private <V> Callable<V> createSWTDispatchCallable(final Callable<V> callable) {
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && callable instanceof DsfExecutable) {
+ assert !((DsfExecutable)callable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)callable).setSubmitted();
+ }
+
+ return new Callable<V>() {
+ @SuppressWarnings("unchecked")
+ public V call() throws Exception {
+ final Object[] v = new Object[1];
+ final Throwable[] e = new Throwable[1];
+
+ try {
+ fDisplay.syncExec(new Runnable() {
+ public void run() {
+ try {
+ v[0] = callable.call();
+ } catch(Throwable exception) {
+ e[0] = exception;
+ }
+ }
+ });
+ } catch (SWTException swtException) {
+ if (swtException.code == SWT.ERROR_DEVICE_DISPOSED) {
+ DisplayDsfExecutor.super.shutdown();
+ }
+ }
+
+ if(e[0] instanceof RuntimeException) {
+ throw (RuntimeException) e[0];
+ } else if (e[0] instanceof Error) {
+ throw (Error) e[0];
+ } else if(e[0] instanceof Exception) {
+ throw (Exception) e[0];
+ }
+
+ return (V) v[0];
+ }
+ };
+ }
+
+ /**
+ * Creates a runnable wrapper, which delegates to the display to perform the
+ * operation. The runnable blocks the executor thread while each call
+ * is executed in the display thred.
+ * @param runnable Runnable to wrap.
+ * @return Wrapper runnable.
+ */
+ private Runnable createSWTDispatchRunnable(final Runnable runnable) {
+
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && runnable instanceof DsfExecutable) {
+ assert !((DsfExecutable)runnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)runnable).setSubmitted();
+ }
+
+ return new Runnable() {
+ public void run() {
+ try {
+ fDisplay.syncExec(new Runnable() {
+ public void run() {
+ runnable.run();
+ }
+ });
+ } catch (SWTException swtException) {
+ if (swtException.code == SWT.ERROR_DEVICE_DISPOSED) {
+ DisplayDsfExecutor.super.shutdownNow();
+ }
+ }
+ }
+ };
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(final Callable<V> callable, long delay, TimeUnit unit) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.schedule(createSWTDispatchCallable(callable), delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.schedule(createSWTDispatchRunnable(command), delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.scheduleAtFixedRate(createSWTDispatchRunnable(command), initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.scheduleWithFixedDelay(createSWTDispatchRunnable(command), initialDelay, delay, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ super.execute(createSWTDispatchRunnable(command));
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> callable) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.submit(createSWTDispatchCallable(callable));
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable command, T result) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.submit(createSWTDispatchRunnable(command), result);
+ }
+
+ @Override
+ public Future<?> submit(Runnable command) {
+ if (fDisplay.isDisposed()) {
+ if (!super.isShutdown()) super.shutdown();
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed."); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ return super.submit(createSWTDispatchRunnable(command));
+ }
+
+ /**
+ * Override to prevent clients from shutting down. The executor will be
+ * shut down when the underlying display is discovered to be shut down.
+ */
+ @Override
+ public void shutdown() {
+ }
+
+ /**
+ * Override to prevent clients from shutting down. The executor will be
+ * shut down when the underlying display is discovered to be shut down.
+ */
+ @SuppressWarnings({ "cast", "unchecked" })
+ @Override
+ public List<Runnable> shutdownNow() {
+ return (List<Runnable>)Collections.EMPTY_LIST;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/SimpleDisplayExecutor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/SimpleDisplayExecutor.java
new file mode 100644
index 00000000000..dae9a513272
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/SimpleDisplayExecutor.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.ui.concurrent;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A simple executor which uses the display thread to run the submitted
+ * runnables. It only implements the {@link Executor}, and NOT the more
+ * sophisticated {@link DsfExecutor} (which extends
+ * {@link java.util.concurrent.ScheduledExecutorService}). However, this
+ * implementation is much more efficient than DisplayDsfExecutor as it does
+ * not use a separate thread or maintain its own queue.
+ */
+public class SimpleDisplayExecutor implements Executor{
+ /**
+ * Internal mapping of display objects to executors.
+ */
+ private static Map<Display, SimpleDisplayExecutor> fExecutors = Collections.synchronizedMap( new HashMap<Display, SimpleDisplayExecutor>() );
+
+ /**
+ * Factory method for display executors.
+ * @param display Display to create an executor for.
+ * @return The new (or re-used) executor.
+ */
+ public static SimpleDisplayExecutor getSimpleDisplayExecutor(Display display) {
+ synchronized (fExecutors) {
+ SimpleDisplayExecutor executor = fExecutors.get(display);
+ if (executor == null) {
+ executor = new SimpleDisplayExecutor(display);
+ fExecutors.put(display, executor);
+ }
+ return executor;
+ }
+ }
+
+ /**
+ * The display class used by this executor to execute the submitted runnables.
+ */
+ private final Display fDisplay;
+
+ private SimpleDisplayExecutor(Display display) {
+ fDisplay = display;
+ }
+
+ public void execute(Runnable command) {
+ try {
+ fDisplay.asyncExec(command);
+ } catch (SWTException e) {
+ if (e.code == SWT.ERROR_DEVICE_DISPOSED) {
+ throw new RejectedExecutionException("Display " + fDisplay + " is disposed", e); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ throw e;
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerCountingRequestMonitor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerCountingRequestMonitor.java
new file mode 100644
index 00000000000..90634ad4dfb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerCountingRequestMonitor.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * Counting multi data request monitor that takes a <code>IViewerUpdate</code>
+ * as a parent. If the IViewerUpdate is canceled, this request monitor becomes
+ * canceled as well.
+ *
+ * @see IViewerUpdate.
+ */
+@SuppressWarnings("restriction")
+public class ViewerCountingRequestMonitor extends CountingRequestMonitor {
+
+ private final IViewerUpdate fUpdate;
+ public ViewerCountingRequestMonitor(Executor executor, IViewerUpdate update) {
+ super(executor, null);
+ fUpdate = update;
+ }
+
+ @Override
+ public synchronized boolean isCanceled() {
+ // isCanceled() is called implicitly by the super-constructor before fUpdate
+ // is initialized. The fUpdate != null is here to protect against an NPE
+ // from that.
+ return (fUpdate != null && fUpdate.isCanceled()) || super.isCanceled();
+ }
+
+ @Override
+ protected void handleSuccess() {
+ fUpdate.done();
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ fUpdate.setStatus(getStatus());
+ fUpdate.done();
+ }
+
+ @Override
+ protected void handleCancel() {
+ fUpdate.setStatus(getStatus());
+ fUpdate.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerDataRequestMonitor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerDataRequestMonitor.java
new file mode 100644
index 00000000000..6db69286cdf
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/concurrent/ViewerDataRequestMonitor.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * Data Request monitor that takean <code>IViewerUpdate</code> as a parent.
+ * If the IViewerUpdate is canceled, this request monitor becomes canceled as well.
+ * @see IViewerUpdate
+ */
+@SuppressWarnings("restriction")
+public class ViewerDataRequestMonitor<V> extends DataRequestMonitor<V> {
+
+ private final IViewerUpdate fUpdate;
+ public ViewerDataRequestMonitor(Executor executor, IViewerUpdate update) {
+ super(executor, null);
+ fUpdate = update;
+ }
+
+ @Override
+ public synchronized boolean isCanceled() {
+ return fUpdate.isCanceled() || super.isCanceled();
+ }
+
+ @Override
+ protected void handleSuccess() {
+ fUpdate.done();
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ fUpdate.setStatus(getStatus());
+ fUpdate.done();
+ }
+
+ @Override
+ protected void handleCancel() {
+ fUpdate.setStatus(getStatus());
+ fUpdate.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMAdapter.java
new file mode 100644
index 00000000000..c98b3b4653f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMAdapter.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * Base implementation for View Model Adapters. The implementation uses
+ * its own single-thread executor for communicating with providers and
+ * layout nodes.
+ */
+@ThreadSafe
+@SuppressWarnings("restriction")
+abstract public class AbstractVMAdapter implements IVMAdapterExtension
+{
+
+ private boolean fDisposed;
+
+ private final Map<IPresentationContext, IVMProvider> fViewModelProviders =
+ Collections.synchronizedMap( new HashMap<IPresentationContext, IVMProvider>() );
+
+ /**
+ * Constructor for the View Model session. It is tempting to have the
+ * adapter register itself here with the session as the model adapter, but
+ * that would mean that the adapter might get accessed on another thread
+ * even before the deriving class is fully constructed. So it it better
+ * to have the owner of this object register it with the session.
+ * @param session
+ */
+ public AbstractVMAdapter() {
+ }
+
+ @ThreadSafe
+ public IVMProvider getVMProvider(IPresentationContext context) {
+ synchronized(fViewModelProviders) {
+ if (fDisposed) return null;
+
+ IVMProvider provider = fViewModelProviders.get(context);
+ if (provider == null) {
+ provider = createViewModelProvider(context);
+ if (provider != null) {
+ fViewModelProviders.put(context, provider);
+ }
+ }
+ return provider;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @since 1.1
+ */
+ public IVMProvider[] getActiveProviders() {
+ synchronized(fViewModelProviders) {
+ return fViewModelProviders.values().toArray(new IVMProvider[fViewModelProviders.size()]);
+ }
+ }
+
+ public void dispose() {
+ IVMProvider[] providers = new IVMProvider[0];
+ synchronized(fViewModelProviders) {
+ providers = fViewModelProviders.values().toArray(new IVMProvider[fViewModelProviders.size()]);
+ fViewModelProviders.clear();
+ fDisposed = true;
+ }
+
+ for (final IVMProvider provider : providers) {
+ try {
+ provider.getExecutor().execute(new Runnable() {
+ public void run() {
+ provider.dispose();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Not much we can do at this point.
+ }
+ }
+ }
+
+ /**
+ * @return whether this VM adapter is disposed.
+ *
+ * @since 1.1
+ */
+ public boolean isDisposed() {
+ return fDisposed;
+ }
+
+ public void update(IHasChildrenUpdate[] updates) {
+ handleUpdate(updates);
+ }
+
+ public void update(IChildrenCountUpdate[] updates) {
+ handleUpdate(updates);
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ handleUpdate(updates);
+ }
+
+ private void handleUpdate(IViewerUpdate[] updates) {
+ IVMProvider provider = getVMProvider(updates[0].getPresentationContext());
+ if (provider != null) {
+ updateProvider(provider, updates);
+ } else {
+ for (IViewerUpdate update : updates) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+ "No model provider for update " + update, null)); //$NON-NLS-1$
+ update.done();
+ }
+ }
+ }
+
+ private void updateProvider(final IVMProvider provider, final IViewerUpdate[] updates) {
+ try {
+ provider.getExecutor().execute(new Runnable() {
+ public void run() {
+ if (updates instanceof IHasChildrenUpdate[]) {
+ provider.update((IHasChildrenUpdate[])updates);
+ } else if (updates instanceof IChildrenCountUpdate[]) {
+ provider.update((IChildrenCountUpdate[])updates);
+ } else if (updates instanceof IChildrenUpdate[]) {
+ provider.update((IChildrenUpdate[])updates);
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+ "Display is disposed, cannot complete update " + update, null)); //$NON-NLS-1$
+ update.done();
+ }
+ }
+ }
+
+ public IModelProxy createModelProxy(Object element, IPresentationContext context) {
+ IVMProvider provider = getVMProvider(context);
+ if (provider != null) {
+ return provider.createModelProxy(element, context);
+ }
+ return null;
+ }
+
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ final IVMProvider provider = getVMProvider(context);
+ if (provider != null) {
+ return provider.createColumnPresentation(context, element);
+ }
+ return null;
+ }
+
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ final IVMProvider provider = getVMProvider(context);
+ if (provider != null) {
+ return provider.getColumnPresentationId(context, element);
+ }
+ return null;
+ }
+
+
+ public void update(IViewerInputUpdate update) {
+ final IVMProvider provider = getVMProvider(update.getPresentationContext());
+ if (provider != null) {
+ provider.update(update);
+ }
+ }
+
+ /**
+ * Creates a new View Model Provider for given presentation context. Returns null
+ * if the presentation context is not supported.
+ */
+ @ThreadSafe
+ abstract protected IVMProvider createViewModelProvider(IPresentationContext context);
+
+ /**
+ * Dispatch given event to VM providers interested in events.
+ *
+ * @since 1.1
+ */
+ protected final void handleEvent(final Object event) {
+ final List<IVMEventListener> eventListeners = new ArrayList<IVMEventListener>();
+
+ aboutToHandleEvent(event);
+
+ for (IVMProvider vmProvider : getActiveProviders()) {
+ if (vmProvider instanceof IVMEventListener) {
+ eventListeners.add((IVMEventListener)vmProvider);
+ }
+ }
+
+ if (!eventListeners.isEmpty()) {
+ final CountingRequestMonitor crm = new CountingRequestMonitor(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isDisposed()) {
+ return;
+ }
+ doneHandleEvent(event);
+ }
+ };
+
+ int count = 0;
+ for (final IVMEventListener vmEventListener : eventListeners) {
+ RequestMonitor listenerRm = null;
+ if (vmEventListener.shouldWaitHandleEventToComplete()) {
+ listenerRm = crm;
+ count++;
+ } else {
+ // Create a dummy executor for the handling of this event.
+ listenerRm = new RequestMonitor(ImmediateExecutor.getInstance(), null);
+ }
+ final RequestMonitor finalListenerRm = listenerRm;
+ vmEventListener.getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ vmEventListener.handleEvent(event, finalListenerRm);
+ }});
+ }
+ crm.setDoneCount(count);
+ } else {
+ doneHandleEvent(event);
+ }
+ }
+
+ /**
+ * Given event is about to be handled.
+ *
+ * @param event
+ *
+ * @since 1.1
+ */
+ protected void aboutToHandleEvent(final Object event) {
+ }
+
+ /**
+ * Given event has been processed by all VM event listeners.
+ *
+ * @param event
+ *
+ * @since 1.1
+ */
+ protected void doneHandleEvent(final Object event) {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMContext.java
new file mode 100644
index 00000000000..aa538f61412
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMContext.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Implementation of basic view model context interface.
+ * <p> The main purpose of the VMC wrapper is to re-direct adapter
+ * queries. The redirecting of adapter queries follows this order:
+ * <ol>
+ * <li>If context implements the adapter itself, it is returned.</li>
+ * <li>If the VM Adapter implements the adapter, the VM Adapter is returned.</li>
+ * <li>If the VM Provider implements the adapter, the VM Provider is returned.</li>
+ * <li>If the VM Node implements the adapter, the VM Node is returned.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Note: Deriving classes must override the Object.equals/hashCode methods.
+ * This is because the view model context objects are just wrappers that are
+ * created by the view model on demand, so the equals methods must use the
+ * object being wrapped to perform a meaningful comparison.
+ */
+abstract public class AbstractVMContext implements IVMContext {
+ protected final IVMNode fNode;
+
+ public AbstractVMContext(IVMNode node) {
+ fNode = node;
+ }
+
+ public IVMNode getVMNode() { return fNode; }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ // If the context implements the given adapter directly, it always takes
+ // precedence.
+ if (adapter.isInstance(this)) {
+ return this;
+ }
+
+ IVMProvider vmProvider = getVMNode().getVMProvider();
+ IVMAdapter vmAdapter = vmProvider.getVMAdapter();
+ if (adapter.isInstance(vmAdapter)) {
+ return vmAdapter;
+ } else if (adapter.isInstance(vmProvider)) {
+ return vmProvider;
+ } else if (adapter.isInstance(getVMNode())) {
+ return getVMNode();
+ }
+ return Platform.getAdapterManager().getAdapter(this, adapter);
+ }
+
+ /** Deriving classes must override. */
+ @Override
+ abstract public boolean equals(Object obj);
+
+ /** Deriving classes must override. */
+ @Override
+ abstract public int hashCode();
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMNode.java
new file mode 100644
index 00000000000..455383a6c38
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMNode.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * Base implementation of the view model node.
+ * The main functionality implemented here is for building the view model
+ * deltas (IModelDelta), based on the flags returned by child nodes.
+ */
+@SuppressWarnings("restriction")
+abstract public class AbstractVMNode implements IVMNode {
+
+ private final AbstractVMProvider fProvider;
+ private boolean fDisposed = false;
+
+ public AbstractVMNode(AbstractVMProvider provider) {
+ fProvider = provider;
+ }
+
+ /**
+ * Accessor method for sub-classes.
+ */
+ protected Executor getExecutor() {
+ return fProvider.getExecutor();
+ }
+
+ public IVMProvider getVMProvider() {
+ return fProvider;
+ }
+
+ public void dispose() {
+ fDisposed = true;
+ }
+
+ public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ }
+
+ protected boolean isDisposed() {
+ return fDisposed;
+ }
+
+ /**
+ * Convenience method that returns a token value in case when the services
+ * that the layout node depends on, are not available.
+ */
+ protected boolean checkUpdate(IViewerUpdate update) {
+ if (update.isCanceled()) {
+ update.done();
+ return false;
+ }
+ if (fDisposed) {
+ handleFailedUpdate(update);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * A convenience method that completes update object in case of an error.
+ * Different types of update need to have some data configured to exhibit
+ * desired behavior in the viewer.
+ * @param update Update to handle.
+ */
+ protected void handleFailedUpdate(IViewerUpdate update) {
+ if (update instanceof IHasChildrenUpdate) {
+ ((IHasChildrenUpdate)update).setHasChilren(false);
+ } else if (update instanceof IChildrenCountUpdate) {
+ ((IChildrenCountUpdate)update).setChildCount(0);
+ } else if (update instanceof ILabelUpdate) {
+ ILabelUpdate labelUpdate = (ILabelUpdate)update;
+ String[] columns = labelUpdate.getColumnIds();
+ for (int i = 0; i < (columns != null ? columns.length : 1); i++) {
+ labelUpdate.setLabel("...", i); //$NON-NLS-1$
+ }
+ }
+ update.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMProvider.java
new file mode 100644
index 00000000000..de4388e247e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/AbstractVMProvider.java
@@ -0,0 +1,722 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.concurrent.SimpleDisplayExecutor;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.UserEditEvent;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * View model provider implements the asynchronous view model functionality for
+ * a single view. This provider is just a holder which further delegates the
+ * model provider functionality to the view model nodes that need
+ * to be configured with each provider.
+ *
+ * <p/>
+ * The view model provider, often does not provide the model for the entire
+ * view. Rather, it needs to be able to plug in at any level in the viewer's
+ * content model and provide data for a sub-tree.
+ *
+ * <p/>
+ * Clients are intended to extend this class.
+ *
+ * @see IAsynchronousContentAdapter
+ * @see IAsynchronousLabelAdapter
+ * @see IModelProxy
+ * @see IVMNode
+ */
+@SuppressWarnings("restriction")
+abstract public class AbstractVMProvider implements IVMProvider, IVMEventListener
+{
+ // debug flags
+ /** @since 1.1 */
+ public static String DEBUG_PRESENTATION_ID = null;
+
+ /** @since 1.1 */
+ public static boolean DEBUG_CONTENT_PROVIDER = false;
+
+ /** @since 1.1 */
+ public static boolean DEBUG_DELTA = false;
+
+ static {
+ DEBUG_PRESENTATION_ID = Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/vm/presentationId"); //$NON-NLS-1$
+ if (!DsfUIPlugin.DEBUG || "".equals(DEBUG_PRESENTATION_ID)) { //$NON-NLS-1$
+ DEBUG_PRESENTATION_ID = null;
+ }
+ DEBUG_CONTENT_PROVIDER = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/vm/contentProvider")); //$NON-NLS-1$
+
+ DEBUG_DELTA = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/vm/delta")); //$NON-NLS-1$
+ }
+
+ /** Reference to the VM adapter that owns this provider */
+ private final AbstractVMAdapter fVMAdapter;
+
+ /** The presentation context that this provider is associated with */
+ private final IPresentationContext fPresentationContext;
+
+ /**
+ * The executor that this VM provider operates in. This executor will be
+ * initialized properly when we can access the display from the
+ * IPresentationContext object (bug 213629). For now utilize the
+ * assumption that there is only one display.
+ */
+ private final Executor fExecutor = SimpleDisplayExecutor.getSimpleDisplayExecutor(Display.getDefault());
+
+ /**
+ * The element content provider implementation that this provider delegates to.
+ * Sub-classes may override the content strategy used for custom functionality.
+ */
+ private final IElementContentProvider fContentStrategy;
+
+ /**
+ * The list of active model proxies in this provider. A new model
+ * proxy is created when a viewer has a new input element
+ * (see {@link #createModelProxy(Object, IPresentationContext)}).
+ * Typically there will be only one active model proxy in a given
+ * provider. However, if a view model provider fills only a sub-tree
+ * in a viewer, and there are several sub-trees active in the same viewer
+ * at the same time, each of these sub-trees will have it's own model
+ * proxy.
+ */
+ private List<IVMModelProxy> fActiveModelProxies = new LinkedList<IVMModelProxy>();
+
+ /**
+ * Convencience constant.
+ */
+ private static final IVMNode[] EMPTY_NODES_ARRAY = new IVMNode[0];
+
+
+ /**
+ * The mapping of parent to child nodes.
+ */
+ private Map<IVMNode,IVMNode[]> fChildNodesMap =
+ new HashMap<IVMNode,IVMNode[]>();
+
+ /**
+ * Cached array of all the configued view model nodes. It is generated
+ * based on the child nodes map.
+ */
+ private IVMNode[] fNodesListCache = null;
+
+ /**
+ * Flag indicating that the provider is disposed.
+ */
+ private boolean fDisposed = false;
+
+ /**
+ * The root node for this model provider. The root layout node could be
+ * null when first created, to allow sub-classes to prorperly configure the
+ * root node in the sub-class constructor.
+ */
+ private IRootVMNode fRootNode;
+
+ private class EventInfo {
+ EventInfo(Object event, RequestMonitor rm) {
+ fEvent = event;
+ fClientRm = rm;
+ }
+ Object fEvent;
+ RequestMonitor fClientRm;
+ }
+
+ private class ModelProxyEventQueue {
+ EventInfo fCurrentEvent = null;
+ RequestMonitor fCurrentRm = null;
+ List<EventInfo> fEventQueue = new LinkedList<EventInfo>();
+ }
+
+ private Map<IVMModelProxy, ModelProxyEventQueue> fProxyEventQueues = new HashMap<IVMModelProxy, ModelProxyEventQueue>();
+
+ /**
+ * Constructs the view model provider for given DSF session. The
+ * constructor is thread-safe to allow VM provider to be constructed
+ * synchronously when a call to getAdapter() is made on an element
+ * in a view.
+ */
+ public AbstractVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
+ fVMAdapter = adapter;
+ fPresentationContext = presentationContext;
+ fContentStrategy = createContentStrategy();
+ }
+
+ public IPresentationContext getPresentationContext() {
+ return fPresentationContext;
+ }
+
+ public AbstractVMAdapter getVMAdapter() {
+ return fVMAdapter;
+ }
+
+ /**
+ * Creates the strategy class that will be used to implement the content
+ * provider interface of this view model provider. This method can be
+ * overridden by sub-classes to provider custom content provider strategy.
+ * <p/>
+ * Note this method can be called by the base class constructor, therefore
+ * it should not reference any fields initialized in the sub-class.
+ *
+ * @return New content provider implementation.
+ */
+ protected IElementContentProvider createContentStrategy() {
+ return new DefaultVMContentProviderStrategy(this);
+ }
+
+ /**
+ * Access method for the content provider strategy.
+ *
+ * @return Content provider implementation currently being used by this
+ * class.
+ */
+ protected IElementContentProvider getContentStrategy() {
+ return fContentStrategy;
+ }
+
+ /**
+ * Creates the strategy class that will be used to implement the content
+ * model proxy of this view model provider. It is normally called by
+ * {@link #createModelProxy(Object, IPresentationContext)} every time the
+ * input in the viewer is updated. This method can be overridden by
+ * sub-classes to provider custom model proxy strategy.
+ *
+ * @return New model proxy implementation.
+ */
+ protected IVMModelProxy createModelProxyStrategy(Object rootElement) {
+ return new DefaultVMModelProxyStrategy(this, rootElement);
+ }
+
+ /**
+ * Returns the list of active proxies in this provider. The returned
+ * list is not a copy and if a sub-class modifies this list, it will
+ * modify the current list of active proxies. This allows the
+ * sub-classes to change how the active proxies are managed and
+ * retained.
+ */
+ protected List<IVMModelProxy> getActiveModelProxies() {
+ return fActiveModelProxies;
+ }
+
+ /**
+ * Processes the given event in the given provider, sending model
+ * deltas if necessary.
+ */
+ public void handleEvent(final Object event) {
+ handleEvent(event, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @since 1.1
+ */
+ public void handleEvent(final Object event, RequestMonitor rm) {
+ CountingRequestMonitor crm = new CountingRequestMonitor(getExecutor(), rm);
+ final List<IVMModelProxy> activeModelProxies= new ArrayList<IVMModelProxy>(getActiveModelProxies());
+ crm.setDoneCount(activeModelProxies.size());
+
+ for (final IVMModelProxy proxyStrategy : activeModelProxies) {
+ if (proxyStrategy.isDeltaEvent(event) || event instanceof UserEditEvent) {
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventReceived(proxyRoot = " + proxyStrategy .getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ if (!fProxyEventQueues.containsKey(proxyStrategy)) {
+ fProxyEventQueues.put(proxyStrategy, new ModelProxyEventQueue());
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventQueued(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ final ModelProxyEventQueue queue = fProxyEventQueues.get(proxyStrategy);
+ if (queue.fCurrentEvent != null) {
+ assert queue.fCurrentRm != null;
+ // Iterate through the events in the queue and check if
+ // they can be skipped. If they can be skipped, then just
+ // mark their RM as done. Stop iterating through the queue
+ // if an event that cannot be skipped is encountered.
+ while (!queue.fEventQueue.isEmpty()) {
+ EventInfo eventToSkipInfo = queue.fEventQueue.get(queue.fEventQueue.size() - 1);
+
+ if (canSkipHandlingEvent(event, eventToSkipInfo.fEvent)) {
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventSkipped(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + eventToSkipInfo + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ queue.fEventQueue.remove(queue.fEventQueue.size() - 1);
+ eventToSkipInfo.fClientRm.done();
+ } else {
+ break;
+ }
+ }
+ // If the queue is empty check if the current event
+ // being processed can be skipped. If so, cancel its
+ // processing
+ if (queue.fEventQueue.isEmpty() && canSkipHandlingEvent(event, queue.fCurrentEvent.fEvent)) {
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventCancelled(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + queue.fCurrentEvent + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ queue.fCurrentRm.cancel();
+ }
+ queue.fEventQueue.add(new EventInfo(event, crm));
+ } else {
+ doHandleEvent(queue, proxyStrategy, new EventInfo(event, crm));
+ }
+ } else {
+ crm.done();
+ }
+ }
+
+ // Clean up model proxies that were removed.
+ List<IVMModelProxy> activeProxies = getActiveModelProxies();
+ for (Iterator<IVMModelProxy> itr = fProxyEventQueues.keySet().iterator(); itr.hasNext();) {
+ if (!activeProxies.contains(itr.next())) {
+ itr.remove();
+ }
+ }
+ }
+
+ private void doHandleEvent(final ModelProxyEventQueue queue, final IVMModelProxy proxyStrategy, final EventInfo eventInfo) {
+ assert queue.fCurrentEvent == null && queue.fCurrentRm == null;
+
+ queue.fCurrentEvent = eventInfo;
+ queue.fCurrentRm = new RequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ queue.fCurrentEvent = null;
+ queue.fCurrentRm = null;
+ if (!queue.fEventQueue.isEmpty()) {
+ EventInfo eventInfo = queue.fEventQueue.remove(0);
+ doHandleEvent(queue, proxyStrategy, eventInfo);
+ }
+ eventInfo.fClientRm.done();
+ }
+ };
+ handleEvent(proxyStrategy, eventInfo.fEvent, queue.fCurrentRm);
+ }
+
+ /**
+ * Handles the given event for the given proxy strategy.
+ * <p>
+ * This method is called by the base {@link #handleEvent(Object)}
+ * implementation to handle the given event using the given model proxy.
+ * The default implementation of this method checks whether the given
+ * proxy is active and if the proxy is active, it is called to generate the
+ * delta which is then sent to the viewer.
+ * </p>
+ * @param proxyStrategy Model proxy strategy to use to process this event.
+ * @param event Event to process.
+ * @param rm Request monitor to call when processing the event is
+ * completed.
+ */
+ protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
+ if (!proxyStrategy.isDisposed()) {
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventProcessing(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ proxyStrategy.createDelta(
+ event,
+ new DataRequestMonitor<IModelDelta>(getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+ if (isSuccess()) {
+ proxyStrategy.fireModelChanged(getData());
+ if (DEBUG_DELTA && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("eventDeltaFired(proxyRoot = " + proxyStrategy.getRootElement() + ", event = " + event + ")" ); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ super.handleCompleted();
+ }
+ @Override public String toString() {
+ return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ });
+ } else {
+ rm.done();
+ }
+ }
+
+ /**
+ * Determines whether processing of a given event can be skipped. This
+ * method is called when there are multiple events waiting to be processed
+ * by the provider. As new events are received from the model, they are
+ * compared with the events in the queue using this method, events at the
+ * end of the queue are tested for removal. If this method returns that a
+ * given event can be skipped in favor of the new event, the skipped event
+ * is removed from the queue. This process is repeated with the new event
+ * until an event which cannot be stopped is found or the queue goes empty.
+ * <p>
+ * This method may be overriden by specific view model provider
+ * implementations extending this abstract class.
+ * </p>
+ * @param newEvent New event that was received from the model.
+ * @param eventToSkip Event which is currently at the end of the queue.
+ * @return True if the event at the end of the queue can be skipped in
+ * favor of the new event.
+ */
+ protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+ return false;
+ }
+
+ /** @since 1.1 */
+ public boolean shouldWaitHandleEventToComplete() {
+ return false;
+ }
+
+ public IRootVMNode getRootVMNode() {
+ return fRootNode;
+ }
+
+ public IVMNode[] getAllVMNodes() {
+ if (fNodesListCache != null) {
+ return fNodesListCache;
+ }
+ List<IVMNode> list = new ArrayList<IVMNode>();
+ for (IVMNode node : fChildNodesMap.keySet()) {
+ if (node != null) {
+ list.add(node);
+ }
+ }
+ fNodesListCache = list.toArray(new IVMNode[list.size()]);;
+ return fNodesListCache;
+ }
+
+ public IVMNode[] getChildVMNodes(IVMNode node) {
+ IVMNode[] retVal = fChildNodesMap.get(node);
+ if (retVal != null) {
+ return retVal;
+ }
+ return EMPTY_NODES_ARRAY;
+ }
+
+ /**
+ * Configures the given array of nodes as children of the given parent node.
+ * Sub-classes should call this method to define the hierarchy of nodes.
+ */
+ protected void addChildNodes(IVMNode parentNode, IVMNode[] childNodes) {
+ // Add to the child nodes array.
+ IVMNode[] existingChildNodes = fChildNodesMap.get(parentNode);
+ if (existingChildNodes == null) {
+ fChildNodesMap.put(parentNode, childNodes);
+ } else {
+ IVMNode[] newNodes = new IVMNode[existingChildNodes.length + childNodes.length];
+ System.arraycopy(existingChildNodes, 0, newNodes, 0, existingChildNodes.length);
+ System.arraycopy(childNodes, 0, newNodes, existingChildNodes.length, childNodes.length);
+ fChildNodesMap.put(parentNode, newNodes);
+ }
+
+ // Make sure that each new expression node has an entry of its own.
+ for (IVMNode childNode : childNodes) {
+ addNode(childNode);
+ }
+
+ fNodesListCache = null;
+ }
+
+ /**
+ * Adds the given node to configured nodes, without creating any
+ * parent-child relationship for it. It is useful for providers which do have
+ * a strict tree hierarchy of ndoes.
+ */
+ protected void addNode(IVMNode node) {
+ if (!fChildNodesMap.containsKey(node)) {
+ fChildNodesMap.put(node, EMPTY_NODES_ARRAY);
+ }
+ }
+
+ /**
+ * Clears all configured nodes. This allows a subclass to reset and
+ * reconfigure its nodes.
+ */
+ protected void clearNodes() {
+ for (IVMNode node : fChildNodesMap.keySet()) {
+ node.dispose();
+ }
+ fChildNodesMap.clear();
+ fRootNode = null;
+ }
+
+ /**
+ * Sets the root node for this provider.
+ */
+ protected void setRootNode(IRootVMNode rootNode) {
+ fRootNode = rootNode;
+ }
+
+ /** Called to dispose the provider. */
+ public void dispose() {
+ clearNodes();
+ fRootNode = null;
+ fDisposed = true;
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ fContentStrategy.update(updates);
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ fContentStrategy.update(updates);
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ fContentStrategy.update(updates);
+ }
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is called by view model provider and it's helper classes instead
+ * of calling the IVMNode method directly, in order to allow additional
+ * processing of the udpate. For example the AbstractCachingVMProvider
+ * overrides this method to optionally return the results for an update from
+ * a cache.
+ */
+ public void updateNode(final IVMNode node, IHasChildrenUpdate[] updates) {
+ IHasChildrenUpdate[] updateProxies = new IHasChildrenUpdate[updates.length];
+ for (int i = 0; i < updates.length; i++) {
+ final IHasChildrenUpdate update = updates[i];
+ if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("updateNodeHasChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ updateProxies[i] = new VMHasChildrenUpdate(
+ update,
+ new ViewerDataRequestMonitor<Boolean>(getExecutor(), updates[i]) {
+ @Override
+ protected void handleSuccess() {
+ update.setHasChilren(getData());
+ update.done();
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) {
+ if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("not-supported:updateNodeHasChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ updateNode(
+ node,
+ new VMChildrenUpdate(
+ update, -1, -1,
+ new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ update.setHasChilren( !getData().isEmpty() );
+ update.done();
+ }
+ })
+ );
+
+ } else {
+ update.setStatus(getStatus());
+ update.done();
+ }
+ }
+
+ });
+ }
+ node.update(updateProxies);
+ }
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is called by view model provider and it's helper classes instead
+ * of calling the IVMNode method directly, in order to allow additional
+ * processing of the udpate. For example the AbstractCachingVMProvider
+ * overrides this method to optionally return the results for an update from
+ * a cache.
+ */
+ public void updateNode(final IVMNode node, final IChildrenCountUpdate update) {
+ if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("updateNodeChildCount(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ node.update(new IChildrenCountUpdate[] {
+ new VMChildrenCountUpdate(
+ update,
+ new ViewerDataRequestMonitor<Integer>(getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ update.setChildCount(getData());
+ update.done();
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) {
+ if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("not-supported:updateNodeChildCount(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ updateNode(
+ node,
+ new VMChildrenUpdate(
+ update, -1, -1,
+ new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ update.setChildCount( getData().size() );
+ update.done();
+ }
+ })
+ );
+ } else {
+ super.handleErrorOrWarning();
+ }
+ }
+
+ })
+ });
+ }
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is called by view model provider and it's helper classes instead
+ * of calling the IVMNode method directly, in order to allow additional
+ * processing of the udpate. For example the AbstractCachingVMProvider
+ * overrides this method to optionally return the results for an update from
+ * a cache.
+ */
+ public void updateNode(IVMNode node, IChildrenUpdate update) {
+ if (DEBUG_CONTENT_PROVIDER && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("updateNodeChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$
+ }
+ node.update(new IChildrenUpdate[] { update });
+ }
+
+
+ /**
+ * Returns whether this provider has been disposed.
+ */
+ protected boolean isDisposed() {
+ return fDisposed;
+ }
+
+ /**
+ * The abstract provider uses a the display-thread executor so that the
+ * provider will operate on the same thread as the viewer. This way no
+ * synchronization is necessary when the provider is called by the viewer.
+ * Also, the display thread is likely to be shut down long after any of the
+ * view models are disposed, so the users of this abstract provider do not
+ * need to worry about the executor throwing the {@link RejectedExecutionException}
+ * exception.
+ */
+ public Executor getExecutor() {
+ return fExecutor;
+ }
+
+ public IModelProxy createModelProxy(Object element, IPresentationContext context) {
+
+ // Iterate through the current active proxies to try to find a proxy with the same
+ // element and re-use it if found. At the same time purge proxies that are no longer
+ IVMModelProxy proxy = null;
+ for (Iterator<IVMModelProxy> itr = getActiveModelProxies().iterator(); itr.hasNext();) {
+ IVMModelProxy next = itr.next();
+ if (next != null) {
+ if (next.getRootElement().equals(element)) {
+ proxy = next;
+ } else if (next.isDisposed()) {
+ itr.remove();
+ }
+ }
+ }
+
+ if (proxy == null) {
+ proxy = createModelProxyStrategy(element);
+ getActiveModelProxies().add(proxy);
+ } else if (proxy.isDisposed()) {
+ // DSF is capable of re-using old proxies which were previously
+ // disposed. However, the viewer which installs a proxy using
+ // a background job to install the proxy calls
+ // IModelProxy.isDisposed(), to check whether the proxy was disposed
+ // before it could be installed. We need to clear the disposed flag
+ // of the re-used proxy here, otherwise the proxy will never get used.
+ // Calling init here will cause the init() method to be called twice
+ // so the IVMModelProxy needs to be prepared for that.
+ // See bug 241024.
+ proxy.init(context);
+ }
+ return proxy;
+ }
+
+ /**
+ * Creates the column presentation for the given object. This method is meant
+ * to be overriden by deriving class to provide view-specific functionality.
+ * The default is to return null, meaning no columns.
+ * <p>
+ * The viewer only reads the column presentation for the root/input element of
+ * the tree/table, so the VMProvider must be configured to own the root element
+ * in the view in order for this setting to be effective.
+ * <p>
+ * Note: since the IColumnEditorFactory interface is synchronous, and since
+ * column info is fairly static, this method is thread-safe, and it will
+ * not be called on the executor thread.
+ *
+ * @see IColumnPresentationFactory#createColumnPresentation(IPresentationContext, Object)
+ */
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return null;
+ }
+
+ /**
+ * Returns the ID of the column presentation for the given object. This method
+ * is meant to be overriden by deriving class to provide view-specific
+ * functionality. The default is to return null, meaning no columns.
+ * <p>
+ * The viewer only reads the column presentation for the root/input element of
+ * the tree/table, so the VMProvider must be configured to own the root element
+ * in the view in order for this setting to be effective.
+ * <p>
+ * Note: since the IColumnEditorFactory interface is synchronous, and since
+ * column info is fairly static, this method is thread-safe, and it will
+ * not be called on the executor thread.
+ *
+ * @see IColumnEditorFactory#getColumnEditorId(IPresentationContext, Object)
+ */
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return null;
+ }
+
+ /**
+ * Calculates the proxy input object to be used for the given input in the given
+ * viewer. By default no proxy object is used an the given element is used
+ * as the input into the view.
+ * <p>
+ * Sub classes can override this method for view-specific behavior.
+ *
+ * @see IViewerInputProvider
+ */
+ public void update(IViewerInputUpdate update) {
+ update.setInputElement(update.getElement());
+ update.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java
new file mode 100644
index 00000000000..02bce411ff1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMContentProviderStrategy.java
@@ -0,0 +1,379 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerCountingRequestMonitor;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * The default strategy for implementing the IElementContentProvider
+ * functionality for an IVMProvider. It implements an algorithm to populate
+ * contents of the view in accordance with the tree structure of the
+ * view model nodes configured in the view model provider.
+ * <p/>
+ * This class may be used by an <code>IVMProvider</code> directly, or it
+ * may be be extended to customize for the provider's needs.
+ * <p/>
+ * This class is closely linked with a view model provider which is required
+ * for the constructor. The view model provider is used to access the correct
+ * executor and the node hierarchy.
+ */
+@ConfinedToDsfExecutor("#getExecutor()")
+@SuppressWarnings("restriction")
+public class DefaultVMContentProviderStrategy implements IElementContentProvider {
+
+ private final AbstractVMProvider fVMProvider;
+
+ public DefaultVMContentProviderStrategy(AbstractVMProvider provider) {
+ fVMProvider = provider;
+ }
+
+ /**
+ * Returns the view model provider that this strategy is configured for.
+ * @return
+ */
+ protected AbstractVMProvider getVMProvider() { return fVMProvider; }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ if (updates.length == 0) return;
+
+ // Optimization: if all the updates belong to the same node, avoid creating any new lists/arrays.
+ boolean allNodesTheSame = true;
+ IVMNode firstNode = getNodeForElement(updates[0].getElement());
+ for (int i = 1; i < updates.length; i++) {
+ if (firstNode != getNodeForElement(updates[i].getElement())) {
+ allNodesTheSame = false;
+ break;
+ }
+ }
+
+ if (allNodesTheSame) {
+ updateNode(firstNode, updates);
+ } else {
+ // Sort the updates by the node.
+ Map<IVMNode,List<IHasChildrenUpdate>> nodeUpdatesMap = new HashMap<IVMNode,List<IHasChildrenUpdate>>();
+ for (IHasChildrenUpdate update : updates) {
+ // Get the VM Context for last element in path.
+ IVMNode node = getNodeForElement(update.getElement());
+ if (node == null) {
+ // Stale update, most likely as a result of the nodes being
+ // changed. Just ignore it.
+ update.done();
+ continue;
+ }
+ if (!nodeUpdatesMap.containsKey(node)) {
+ nodeUpdatesMap.put(node, new ArrayList<IHasChildrenUpdate>());
+ }
+ nodeUpdatesMap.get(node).add(update);
+ }
+
+ // Iterate through the nodes in the sorted map.
+ for (IVMNode node : nodeUpdatesMap.keySet()) {
+ updateNode(node, nodeUpdatesMap.get(node).toArray(new IHasChildrenUpdate[nodeUpdatesMap.get(node).size()]));
+ }
+ }
+ }
+
+ private void updateNode(IVMNode node, final IHasChildrenUpdate[] updates) {
+ // If parent element's node has no children, just set the
+ // result and continue to next element.
+ final IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
+ if (childNodes.length == 0) {
+ for (IHasChildrenUpdate update : updates) {
+ update.setHasChilren(false);
+ update.done();
+ }
+ return;
+ }
+
+ // Create a matrix of element updates:
+ // The first dimension "i" is the list of children updates that came from the viewer.
+ // For each of these updates, there are "j" number of elment updates corresponding
+ // to the number of child nodes in this node.
+ // Each children update from the viewer is complete when all the child nodes
+ // fill in their elements update.
+ // Once the matrix is constructed, the child nodes are given the list of updates
+ // equal to the updates requested by the viewer.
+ VMHasChildrenUpdate[][] elementsUpdates =
+ new VMHasChildrenUpdate[childNodes.length][updates.length];
+ for (int i = 0; i < updates.length; i ++)
+ {
+ final IHasChildrenUpdate update = updates[i];
+
+ final MultiRequestMonitor<DataRequestMonitor<Boolean>> hasChildrenMultiRequestMon =
+ new MultiRequestMonitor<DataRequestMonitor<Boolean>>(getVMProvider().getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ // Status is OK, only if all request monitors are OK.
+ if (isSuccess()) {
+ boolean isContainer = false;
+ for (DataRequestMonitor<Boolean> hasElementsDone : getRequestMonitors()) {
+ isContainer |= hasElementsDone.isSuccess() &&
+ hasElementsDone.getData().booleanValue();
+ }
+ update.setHasChilren(isContainer);
+ } else {
+ update.setStatus(getStatus());
+ }
+ update.done();
+ }
+ };
+
+ for (int j = 0; j < childNodes.length; j++)
+ {
+ elementsUpdates[j][i] = new VMHasChildrenUpdate(
+ update,
+ hasChildrenMultiRequestMon.add(
+ new ViewerDataRequestMonitor<Boolean>(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ hasChildrenMultiRequestMon.requestMonitorDone(this);
+ }
+ }));
+ }
+ }
+
+ for (int j = 0; j < childNodes.length; j++) {
+ getVMProvider().updateNode(childNodes[j], elementsUpdates[j]);
+ }
+ }
+
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ for (final IChildrenCountUpdate update : updates) {
+ IVMNode node = getNodeForElement(update.getElement());
+
+ if (node != null && !update.isCanceled()) {
+ IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
+
+ if (childNodes.length == 0) {
+ update.setChildCount(0);
+ update.done();
+ } else if (childNodes.length == 1) {
+ getVMProvider().updateNode(childNodes[0], update);
+ } else {
+ getChildrenCountsForNode(
+ update,
+ node,
+ new ViewerDataRequestMonitor<Integer[]>(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ int numChildren = 0;
+ for (Integer count : getData()) {
+ numChildren += count.intValue();
+ }
+ update.setChildCount(numChildren);
+ } else {
+ update.setChildCount(0);
+ }
+ update.done();
+ }
+ });
+ }
+ } else {
+ update.done();
+ }
+
+ }
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ for (final IChildrenUpdate update : updates) {
+ // Get the VM Context for last element in path.
+ final IVMNode node = getNodeForElement(update.getElement());
+ if (node != null && !update.isCanceled()) {
+ IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
+ if (childNodes.length == 0) {
+ // Invalid update, just mark done.
+ update.done();
+ } else if (childNodes.length == 1) {
+ getVMProvider().updateNode(childNodes[0], update);
+ } else {
+ getChildrenCountsForNode(
+ update,
+ node,
+ new ViewerDataRequestMonitor<Integer[]>(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ if (!isSuccess()) {
+ update.done();
+ return;
+ }
+
+ updateChildrenWithCounts(update, node, getData());
+ }
+ });
+ }
+ } else {
+ // Stale update. Just ignore.
+ update.done();
+ }
+
+ }
+ }
+
+
+ /**
+ * Calculates the number of elements in each child node for the element in
+ * update. These counts are then used to delegate the children update to
+ * the correct nodes.
+ */
+ private void getChildrenCountsForNode(IViewerUpdate update, IVMNode updateNode, final DataRequestMonitor<Integer[]> rm) {
+
+ IVMNode[] childNodes = getVMProvider().getChildVMNodes(updateNode);
+
+ // Check for an invalid call
+ assert childNodes.length != 0;
+
+ // Get the mapping of all the counts.
+ final Integer[] counts = new Integer[childNodes.length];
+ final MultiRequestMonitor<RequestMonitor> childrenCountMultiReqMon =
+ new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(counts);
+ rm.done();
+ }
+ };
+
+ for (int i = 0; i < childNodes.length; i++) {
+ final int nodeIndex = i;
+ getVMProvider().updateNode(
+ childNodes[i],
+ new VMChildrenCountUpdate(
+ update,
+ childrenCountMultiReqMon.add(
+ new ViewerDataRequestMonitor<Integer>(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleSuccess() {
+ counts[nodeIndex] = getData();
+ }
+
+ @Override
+ protected void handleCompleted() {
+ super.handleCompleted();
+ childrenCountMultiReqMon.requestMonitorDone(this);
+ }
+ }))
+ );
+ }
+ }
+
+ /**
+ * Splits the given children update among the configured child nodes. Then calls
+ * each child node to complete the update.
+ */
+ private void updateChildrenWithCounts(final IChildrenUpdate update, IVMNode node, Integer[] nodeElementCounts) {
+ // Create the multi request monitor to mark update when querying all
+ // children nodes is finished.
+ CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getVMProvider().getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ update.done();
+ }
+ };
+ int multiRmCount = 0;
+
+ // Iterate through all child nodes and if requested range matches, call them to
+ // get their elements.
+ int updateStartIdx = update.getOffset();
+ int updateEndIdx = update.getOffset() + update.getLength();
+ int idx = 0;
+ IVMNode[] nodes = getVMProvider().getChildVMNodes(node);
+ for (int i = 0; i < nodes.length; i++) {
+ final int nodeStartIdx = idx;
+ final int nodeEndIdx = idx + nodeElementCounts[i];
+ idx = nodeEndIdx;
+
+ // Check if update range overlaps the node's range.
+ if (updateStartIdx <= nodeEndIdx && updateEndIdx > nodeStartIdx) {
+ final int elementsStartIdx = Math.max(updateStartIdx - nodeStartIdx, 0);
+ final int elementsEndIdx = Math.min(updateEndIdx - nodeStartIdx, nodeElementCounts[i]);
+ final int elementsLength = elementsEndIdx - elementsStartIdx;
+ if (elementsLength > 0) {
+ getVMProvider().updateNode(
+ nodes[i],
+ new VMChildrenUpdate(
+ update, elementsStartIdx, elementsLength,
+ new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), multiRm) {
+ @Override
+ protected void handleCompleted() {
+ // Workaround for a bug caused by an optimization in the viewer:
+ // The viewer may request more children then there are at a given level.
+ // This causes the update to return with an error.
+ // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
+ // Instead of checking isSuccess(), check getData() != null.
+ if (getData() != null) {
+ for (int i = 0; i < elementsLength && i < getData().size(); i++) {
+ Object child = getData().get(i);
+ if (child != null) {
+ update.setChild(getData().get(i), elementsStartIdx + nodeStartIdx + i);
+ }
+ }
+ }
+ super.handleCompleted();
+ }
+ })
+ );
+ multiRmCount++;
+ }
+ }
+ }
+
+ // Guard against invalid queries.
+ multiRm.setDoneCount(multiRmCount);
+ }
+
+ /**
+ * Convenience method that finds the VMC corresponding to given parent
+ * argument given to isContainer() or retrieveChildren().
+ * @param object Object to find the VMC for.
+ * @return parent VMC, if null it indicates that the object did not originate
+ * from this view or is stale.
+ */
+ protected IVMNode getNodeForElement(Object element) {
+ if (element instanceof IVMContext) {
+ IVMNode node = ((IVMContext)element).getVMNode();
+ if (isOurNode(((IVMContext)element).getVMNode())) {
+ return node;
+ }
+ }
+ return getVMProvider().getRootVMNode();
+ }
+
+ /**
+ * Convenience method which checks whether given layout node is a node
+ * that is configured in this ViewModelProvider.
+ */
+ private boolean isOurNode(IVMNode node) {
+ for (IVMNode nodeToSearch : getVMProvider().getAllVMNodes()) {
+ if (nodeToSearch.equals(node)) return true;
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java
new file mode 100644
index 00000000000..ffc53ee40f6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java
@@ -0,0 +1,673 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2007 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
+ * Wind River Systems - adapted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.ui.viewmodel;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.MultiRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.debug.internal.ui.DebugUIPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.Viewer;
+
+
+/**
+ * This is the default implementation of {@link IModelProxy} interface for
+ * use by a view model provider. It implements an algorithm to walk the
+ * tree hierarchy of nodes configured with a provider in order to compose
+ * an {@link IModelDelta} for a given data model event.
+ * <p/>
+ * This class is closely linked with a view model provider which is required
+ * for the constructor. The view model provider is used to access the correct
+ * executor and the node hierarchy.
+ */
+@ConfinedToDsfExecutor("#getProvider()#getExecutor()")
+@SuppressWarnings("restriction")
+public class DefaultVMModelProxyStrategy implements IVMModelProxy, IVMModelProxyExtension {
+
+ private final AbstractVMProvider fProvider;
+ private final Object fRootElement;
+ private IPresentationContext fContext;
+ private Viewer fViewer;
+ private boolean fDisposed = false;
+ private ListenerList fListeners = new ListenerList();
+ private IDoubleClickListener fDoubleClickListener;
+
+ /**
+ * Creates this model proxy strategy for the given provider.
+ */
+ public DefaultVMModelProxyStrategy(AbstractVMProvider provider, Object rootElement) {
+ fProvider = provider;
+ fRootElement = rootElement;
+ }
+
+ public boolean isDeltaEvent(Object event) {
+ IRootVMNode rootNode = getVMProvider().getRootVMNode();
+ return rootNode != null &&
+ rootNode.isDeltaEvent(getRootElement(), event) &&
+ getDeltaFlags(rootNode, null, event) != 0;
+ }
+
+
+ /**
+ * Returns the view model provider that this strategy is configured for.
+ * @return
+ */
+ protected AbstractVMProvider getVMProvider() {
+ return fProvider;
+ }
+
+
+ private Object[] getListeners() {
+ return fListeners.getListeners();
+ }
+
+ public void addModelChangedListener(IModelChangedListener listener) {
+ fListeners.add(listener);
+ }
+
+ public void removeModelChangedListener(IModelChangedListener listener) {
+ fListeners.remove(listener);
+ }
+
+ public Object getRootElement() {
+ return fRootElement;
+ }
+
+ /** @since 1.1 */
+ public Object getViewerInput() {
+ return fRootElement;
+ }
+
+ /** @since 1.1 */
+ public TreePath getRootPath() {
+ return TreePath.EMPTY;
+ }
+
+ /**
+ * Notifies registered listeners of the given delta.
+ *
+ * @param delta model delta to broadcast
+ */
+ public void fireModelChanged(IModelDelta delta) {
+ final IModelDelta root = getRootDelta(delta);
+ Object[] listeners = getListeners();
+ for (int i = 0; i < listeners.length; i++) {
+ final IModelChangedListener listener = (IModelChangedListener) listeners[i];
+ ISafeRunnable safeRunnable = new ISafeRunnable() {
+ public void handleException(Throwable exception) {
+ DebugUIPlugin.log(exception);
+ }
+
+ public void run() throws Exception {
+ listener.modelChanged(root, DefaultVMModelProxyStrategy.this);
+ }
+
+ };
+ SafeRunner.run(safeRunnable);
+ }
+ }
+
+ /**
+ * Convenience method that returns the root node of the given delta.
+ *
+ * @param delta delta node
+ * @return returns the root of the given delta
+ */
+ protected IModelDelta getRootDelta(IModelDelta delta) {
+ IModelDelta parent = delta.getParentDelta();
+ while (parent != null) {
+ delta = parent;
+ parent = delta.getParentDelta();
+ }
+ return delta;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#dispose()
+ */
+ public void dispose() {
+ fDisposed = true;
+ if (fViewer instanceof StructuredViewer && fDoubleClickListener != null) {
+ ((StructuredViewer) fViewer).removeDoubleClickListener(fDoubleClickListener);
+ fDoubleClickListener= null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelProxy#init(org.eclipse.debug.internal.ui.viewers.IPresentationContext)
+ */
+ public void init(IPresentationContext context) {
+ fDisposed = false;
+ fContext = context;
+ }
+
+ /**
+ * Returns the context this model proxy is installed in.
+ *
+ * @return presentation context, or <code>null</code> if this
+ * model proxy has been disposed
+ */
+ public IPresentationContext getPresentationContext() {
+ return fContext;
+ }
+
+ /* (non-Javadoc)
+ *
+ * Subclasses should override as required.
+ *
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelProxy#installed(org.eclipse.jface.viewers.Viewer)
+ */
+ public void installed(final Viewer viewer) {
+ fViewer = viewer;
+ getVMProvider().getExecutor().execute( new DsfRunnable() {
+ public void run() {
+ fProvider.handleEvent(new ModelProxyInstalledEvent(DefaultVMModelProxyStrategy.this, viewer, fRootElement));
+ }
+ });
+ if (fViewer instanceof StructuredViewer && fDoubleClickListener == null) {
+ ((StructuredViewer) fViewer).addDoubleClickListener(fDoubleClickListener= new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent e) {
+ handleDoubleClick(e);
+ }
+ });
+ }
+ }
+
+ /**
+ * Handle viewer double click.
+ *
+ * @param e the event
+ *
+ * @since 1.1
+ */
+ protected void handleDoubleClick(final DoubleClickEvent e) {
+ final AbstractVMProvider vmProvider= getVMProvider();
+ if (!vmProvider.isDisposed()) {
+ ISelection selection = e.getSelection();
+ if (!selection.isEmpty() && selection instanceof ITreeSelection) {
+ final TreePath path = ((ITreeSelection)selection).getPaths()[0];
+ final Object input = e.getViewer().getInput();
+
+ vmProvider.getExecutor().execute( new DsfRunnable() {
+ public void run() {
+ Object rootElement = getRootElement();
+ boolean eventContainsRootElement = rootElement.equals(input);
+ for (int i = 0; !eventContainsRootElement && i < path.getSegmentCount(); i++) {
+ eventContainsRootElement = rootElement.equals(path.getSegment(i));
+ }
+
+ if (eventContainsRootElement) {
+ vmProvider.handleEvent(e);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Returns the viewer this proxy is installed in.
+ *
+ * @return viewer or <code>null</code> if not installed
+ *
+ * @since 1.1
+ */
+ public Viewer getViewer() {
+ return fViewer;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy#isDisposed()
+ */
+ public boolean isDisposed() {
+ return fDisposed;
+ }
+
+ /**
+ * Recursively calls the VM nodes in the hierarchy of the given node
+ * to calculate the delta flags that are
+ * <p/>
+ * Note: If a child node has a <code>IModelDelta.CONTENT</code> delta
+ * flag, it means that this flag will be added to this node's element.
+ * To allow for optimization change the child's <code>IModelDelta.CONTENT</code>
+ * flag into a <code>IModelDelta.STATE</code> flag.
+ *
+ * @param node
+ * @param event
+ * @return
+ */
+ protected int getDeltaFlags(IVMNode node, ModelDelta parentDelta, Object event) {
+ int flags = node.getDeltaFlags(event);
+ for (IVMNode childNode : getVMProvider().getChildVMNodes(node)) {
+ if (!childNode.equals(node)) {
+ int childNodeDeltaFlags = getDeltaFlags(childNode, parentDelta, event);
+ if ((childNodeDeltaFlags & IModelDelta.CONTENT) != 0) {
+ childNodeDeltaFlags &= ~IModelDelta.CONTENT;
+ childNodeDeltaFlags |= IModelDelta.STATE;
+ }
+ flags |= childNodeDeltaFlags;
+ }
+ }
+ // Optimization: If the parent delta contains the "content" flag, we do
+ // not need to add it to the child. This can shorten delta processing
+ // considerably so check for it.
+ while (parentDelta != null) {
+ if ( (parentDelta.getFlags() & IModelDelta.CONTENT) != 0 ) {
+ flags = flags & ~IModelDelta.CONTENT & ~IModelDelta.STATE;
+ break;
+ }
+ parentDelta = (ModelDelta)parentDelta.getParentDelta();
+ }
+ return flags;
+ }
+
+ /**
+ * Default implementation creates a delta assuming that the root node
+ * is the input object into the view.
+ */
+ public void createDelta(final Object event, final DataRequestMonitor<IModelDelta> rm) {
+ final IRootVMNode rootNode = getVMProvider().getRootVMNode();
+
+ // Always create the rootDelta, no matter what delta flags the child nodes have.
+ rootNode.createRootDelta(
+ getRootElement(), event,
+ new DataRequestMonitor<VMDelta>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Find the root delta for the whole view to use when firing the delta.
+ // Note: the view root is going to be different than the model root
+ // in case when the view model provider is registered to populate only
+ // a sub-tree of a view.
+ final IModelDelta viewRootDelta = getRootDelta(getData());
+
+ // Find the child nodes that have deltas for the given event.
+ final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(rootNode, getData(), event);
+
+ // If no child nodes have deltas we can stop here.
+ if (childNodesWithDeltaFlags.size() == 0) {
+ rm.setData(viewRootDelta);
+ rm.done();
+ return;
+ }
+
+ callChildNodesToBuildDelta(
+ rootNode,
+ childNodesWithDeltaFlags, getData(), event,
+ new RequestMonitor(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(viewRootDelta);
+ rm.done();
+ }
+ });
+ }
+ });
+ }
+
+ protected void buildChildDeltas(final IVMNode node, final Object event, final VMDelta parentDelta,
+ final int nodeOffset, final RequestMonitor rm)
+ {
+ node.getContextsForEvent(
+ parentDelta,
+ event,
+ new DataRequestMonitor<IVMContext[]>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ assert getData() != null;
+ buildChildDeltasForEventContext(getData(), node, event, parentDelta, nodeOffset, rm);
+ } else if (getStatus().getCode() == IDsfStatusConstants.NOT_SUPPORTED) {
+ // The DMC for this node was not found in the event. Call the
+ // super-class to resort to the default behavior which may add a
+ // delta for every element in this node.
+ buildChildDeltasForAllContexts(node, event, parentDelta, nodeOffset, rm);
+ } else {
+ super.handleCompleted();
+ }
+ }
+ });
+ }
+
+ protected void buildChildDeltasForEventContext(final IVMContext[] vmcs, final IVMNode node, final Object event,
+ final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor)
+ {
+ final Map<IVMNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(node, parentDelta, event);
+ if (childNodeDeltas.size() == 0) {
+ // There are no child nodes with deltas, just return to parent.
+ requestMonitor.done();
+ return;
+ }
+
+ // Check if any of the child nodes are will generate IModelDelta.SELECT or
+ // IModelDelta.EXPAND flags. If so, we must calculate the index for this
+ // VMC.
+ boolean calculateIndex = false;
+ if (nodeOffset >= 0) {
+ for (int childDelta : childNodeDeltas.values()) {
+ if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND)) != 0 ) {
+ calculateIndex = true;
+ break;
+ }
+ }
+ }
+
+ if (calculateIndex) {
+ // Calculate the index of this node by retrieving all the
+ // elements and then finding the DMC that the event is for.
+ getVMProvider().updateNode(
+ node,
+ new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), -1, -1,
+ new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ // Check for an empty list of elements. If it's empty then we
+ // don't have to call the children nodes, so return here.
+ // No need to propagate error, there's no means or need to display it.
+ if (getData().isEmpty()) {
+ requestMonitor.done();
+ return;
+ }
+
+ CountingRequestMonitor countingRm =
+ new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
+
+ int count = 0;
+ for (IVMContext vmc : vmcs) {
+ // Find the index of the vmc in the full list of elements.
+ int i;
+ for (i = 0; i < getData().size(); i++) {
+ if (vmc.equals(getData().get(i))) break;
+ }
+ if (i == getData().size()) {
+ // Element not found, no need to generate the delta.
+ continue;
+ }
+
+ // Optimization: Try to find a delta with a matching element, if found use it.
+ // Otherwise create a new delta for the event element.
+ int elementIndex = nodeOffset + i;
+ VMDelta delta = parentDelta.getChildDelta(vmc);
+ if (delta == null || delta.getIndex() != elementIndex) {
+ delta = parentDelta.addNode(vmc, elementIndex, IModelDelta.NO_CHANGE);
+ }
+
+ callChildNodesToBuildDelta(node, childNodeDeltas, delta, event, countingRm);
+ count++;
+ }
+ countingRm.setDoneCount(count);
+ }
+ }));
+ } else {
+ CountingRequestMonitor countingRm =
+ new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
+ int count = 0;
+ for (IVMContext vmc : vmcs) {
+ // Optimization: Try to find a delta with a matching element, if found use it.
+ // Otherwise create a new delta for the event element.
+ VMDelta delta = parentDelta.getChildDelta(vmc);
+ if (delta == null) {
+ delta = parentDelta.addNode(vmc, IModelDelta.NO_CHANGE);
+ }
+ callChildNodesToBuildDelta(node, childNodeDeltas, delta, event, requestMonitor);
+ count++;
+ }
+ countingRm.setDoneCount(count);
+ }
+ }
+
+ /**
+ * Base implementation that handles calling child nodes to build
+ * the model delta. The child nodes are called with all the elements
+ * in this node, which could be very inefficient. In order to build delta
+ * only for specific elements in this node, the class extending
+ * <code>AbstractVMNode</code> should override this method.
+ * @see IVMNode#buildDelta(Object, ModelDelta, int, RequestMonitor)
+ */
+ protected void buildChildDeltasForAllContexts(final IVMNode node, final Object event, final VMDelta parentDelta,
+ final int nodeOffset, final RequestMonitor requestMonitor)
+ {
+ // Find the child nodes that have deltas for the given event.
+ final Map<IVMNode,Integer> childNodesWithDeltaFlags = getChildNodesWithDeltaFlags(node, parentDelta, event);
+
+ // If no child nodes have deltas we can stop here.
+ if (childNodesWithDeltaFlags.size() == 0) {
+ requestMonitor.done();
+ return;
+ }
+
+ // Check if the child delta only has an IModelDelta.STATE flag.
+ // If that's the case, we can skip creating a delta for this node,
+ // because the TreeUpdatePolicy does not use the full path from the
+ // delta to handle these flags. Similarly, the index argument is
+ // not necessary either.
+ boolean mustGetElements = false;
+ for (int childDelta : childNodesWithDeltaFlags.values()) {
+ if ((childDelta & ~IModelDelta.STATE) != 0) {
+ mustGetElements = true;
+ }
+ }
+
+ if (!mustGetElements) {
+ callChildNodesToBuildDelta(node, childNodesWithDeltaFlags, parentDelta, event, requestMonitor);
+ } else {
+ // The given child nodes have deltas potentially for all elements
+ // from this node. Retrieve all elements and call the child nodes with
+ // each element as the parent of their delta.
+ getVMProvider().updateNode(
+ node,
+ new VMChildrenUpdate(
+ parentDelta, getVMProvider().getPresentationContext(), -1, -1,
+ new DataRequestMonitor<List<Object>>(getVMProvider().getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ if (fDisposed) return;
+
+ // Check for an empty list of elements. If it's empty then we
+ // don't have to call the children nodes, so return here.
+ if (getData().size() == 0) {
+ requestMonitor.done();
+ return;
+ }
+
+ final MultiRequestMonitor<RequestMonitor> elementsDeltasMultiRequestMon =
+ new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), requestMonitor);
+
+ // For each element from this node, create a new delta,
+ // and then call all the child nodes to build their delta.
+ for (int i = 0; i < getData().size(); i++) {
+ int elementIndex = nodeOffset >= 0 ? nodeOffset + i : -1;
+ VMDelta delta= parentDelta.getChildDelta(getData().get(i));
+ if (delta == null) {
+ delta= parentDelta.addNode(getData().get(i), elementIndex, IModelDelta.NO_CHANGE);
+ }
+ callChildNodesToBuildDelta(
+ node, childNodesWithDeltaFlags, delta, event,
+ elementsDeltasMultiRequestMon.add(new RequestMonitor(getVMProvider().getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ elementsDeltasMultiRequestMon.requestMonitorDone(this);
+ }
+ }));
+ }
+ }
+ })
+ );
+ }
+ }
+
+ /**
+ * Calls the specified child nodes to build the delta for the given event.
+ * @param childNodes Map of nodes to be invoked, and the corresponding delta
+ * flags that they will generate. This map is generated with a call to
+ * {@link #getChildNodesWithDeltaFlags(Object)}.
+ * @param delta The delta object to build on. This delta should have been
+ * generated by this node, unless the full delta path is not being calculated
+ * due to an optimization.
+ * @param event The event object that the delta is being built for.
+ * @param requestMonitor The result token to invoke when the delta is completed.
+ */
+ protected void callChildNodesToBuildDelta(final IVMNode node, final Map<IVMNode,Integer> childNodes, final VMDelta delta, final Object event, final RequestMonitor requestMonitor) {
+ assert childNodes.size() != 0;
+
+ // Check if any of the child nodes are will generate IModelDelta.SELECT or
+ // IModelDelta.EXPAND flags. If so, we must calculate the index for this
+ // VMC.
+ boolean calculateOffsets = false;
+ for (int childDelta : childNodes.values()) {
+ if ( (childDelta & (IModelDelta.SELECT | IModelDelta.EXPAND | IModelDelta.INSERTED | IModelDelta.REMOVED)) != 0 ) {
+ calculateOffsets = true;
+ break;
+ }
+ }
+
+ getChildNodesElementOffsets(
+ node, delta, calculateOffsets,
+ new DataRequestMonitor<Map<IVMNode, Integer>>(getVMProvider().getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor);
+ int multiRmCount = 0;
+
+ // Set the total count of number of children in the parent delta.
+ delta.setChildCount(getData().get(null));
+
+ for (final IVMNode childNode : childNodes.keySet()) {
+ // Avoid descending into recursive node hierarchy's when calculating the delta.
+ if (node.equals(childNode)) continue;
+
+ final int nodeOffset = getData().get(childNode);
+ childNode.buildDelta(
+ event, delta, nodeOffset,
+ new RequestMonitor(getVMProvider().getExecutor(), multiRm) {
+ @Override
+ protected void handleSuccess() {
+ buildChildDeltas(
+ childNode, event, delta, nodeOffset, new RequestMonitor(getVMProvider().getExecutor(), multiRm));
+ }
+ });
+ multiRmCount++;
+ }
+ multiRm.setDoneCount(multiRmCount);
+ }
+ });
+ }
+
+ /**
+ * Calculates the indexes at which the elements of each of the child
+ * nodes begin. These indexes are necessary to correctly
+ * calculate the deltas for elements in the child nodes.
+ * @param delta The delta object to build on. This delta should have been
+ * generated by this node, unless the full delta path is not being calculated
+ * due to an optimization.
+ * @param doCalculdateOffsets If true, the method calls each node to get its
+ * element count. If false, it causes this method to fill the return data
+ * structure with dummy values. The dummy values indicate that the indexes
+ * are not known and are acceptable in the delta if the delta flags being
+ * generated do not require full index information.
+ * @param rm Return token containing the results. The result data is a
+ * mapping between the child nodes and the indexes at which the child nodes'
+ * elements begin. There is a special value in the map with a <code>null</code>
+ * key, which contains the full element count for all the nodes.
+ */
+ private void getChildNodesElementOffsets(IVMNode node, IModelDelta delta, boolean calculdateOffsets, final DataRequestMonitor<Map<IVMNode, Integer>> rm) {
+ final IVMNode[] childNodes = getVMProvider().getChildVMNodes(node);
+ assert childNodes.length != 0;
+
+ if (calculdateOffsets) {
+ final Integer[] counts = new Integer[childNodes.length];
+ final MultiRequestMonitor<RequestMonitor> childrenCountMultiRequestMon =
+ new MultiRequestMonitor<RequestMonitor>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>();
+ int offset = 0;
+ for (int i = 0; i < childNodes.length; i++) {
+ data.put(childNodes[i], offset);
+ offset += counts[i];
+ }
+ // As the final value, put the total count in the return map, with null key.
+ data.put(null, offset);
+ rm.setData(data);
+ rm.done();
+ }
+ };
+
+ for (int i = 0; i < childNodes.length; i++) {
+ final int nodeIndex = i;
+ getVMProvider().updateNode(
+ childNodes[i],
+ new VMChildrenCountUpdate(
+ delta, getVMProvider().getPresentationContext(),
+ childrenCountMultiRequestMon.add(
+ new DataRequestMonitor<Integer>(getVMProvider().getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ counts[nodeIndex] = getData();
+ childrenCountMultiRequestMon.requestMonitorDone(this);
+ }
+ })
+ )
+ );
+ }
+ } else {
+ Map<IVMNode, Integer> data = new HashMap<IVMNode, Integer>();
+ for (int i = 0; i < childNodes.length; i++) {
+ data.put(childNodes[i], -1);
+ }
+ data.put(null, -1);
+ rm.setData(data);
+ rm.done();
+ }
+ }
+
+ /**
+ * Convenience method that returns the child nodes which return
+ * <code>true</code> to the <code>hasDeltaFlags()</code> test for the given
+ * event.
+ */
+ protected Map<IVMNode, Integer> getChildNodesWithDeltaFlags(IVMNode node, ModelDelta parentDelta, Object e) {
+ Map<IVMNode, Integer> nodes = new HashMap<IVMNode, Integer>();
+ for (final IVMNode childNode : getVMProvider().getChildVMNodes(node)) {
+ if (!childNode.equals(node)) {
+ int delta = getDeltaFlags(childNode, parentDelta, e);
+ if (delta != IModelDelta.NO_CHANGE) {
+ nodes.put(childNode, delta);
+ }
+ }
+ }
+ return nodes;
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IRootVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IRootVMNode.java
new file mode 100644
index 00000000000..ef305c3c81f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IRootVMNode.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+
+/**
+ * Special type of the view model node, which can be used as a root node
+ * for a hierarchy. The root node of a layout hierarchy has to implement this
+ * interface.
+ */
+public interface IRootVMNode extends IVMNode{
+
+ /**
+ * Returns whether the given event should be processed for delta generation.
+ * Root node is different than other nodes in that there is only one root
+ * element in the view model provider hierarchy. This method allows the root
+ * node to match up the root object of the provider with the given event. If
+ * the root node can determine that the given event does not apply to the root
+ * object, it should return false so that the event is ignored.
+ *
+ * @param rootObject The root object of the VM provider
+ * @param event
+ * @return
+ */
+ public boolean isDeltaEvent(Object rootObject, Object event);
+
+ /**
+ * Version of the {@link IVMNode#buildDelta(Object, ViewModelDelta, org.eclipse.cdt.dsf.concurrent.RequestMonitor)}
+ * method, which creates and returns the root node of the delta. It does
+ * not require a parent object for the delta, as this is the root node.
+ * @param event Event to process.
+ * @param rm Result notification, contains the root of the delta.
+ */
+ public void createRootDelta(Object rootObject, Object event, DataRequestMonitor<VMDelta> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapter.java
new file mode 100644
index 00000000000..31db516f116
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapter.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider;
+
+/**
+ * The View Model adapter handles the layout of a given data model within a
+ * set of viewers. This adapter should be returned by an adapter factory for
+ * the input object of the viewer, and this adapter implementation will then
+ * populate the view contents.
+ */
+@ThreadSafe
+@SuppressWarnings("restriction")
+public interface IVMAdapter
+ extends IElementContentProvider, IModelProxyFactory, IColumnPresentationFactory, IViewerInputProvider
+{
+ /**
+ * Returns the View Model Provider that is registered for the given presentation
+ * context. Returns <code>null</code> if there is none.
+ */
+ public IVMProvider getVMProvider(IPresentationContext presentationContext);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapterExtension.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapterExtension.java
new file mode 100644
index 00000000000..87804008999
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMAdapterExtension.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+/**
+ * Extension to the IVMAdapter interface which allows access to the array of active
+ * providers.
+ *
+ * @since 1.1
+ */
+public interface IVMAdapterExtension extends IVMAdapter {
+
+ /**
+ * Retrieves the currently active VM providers in this adapter.
+ *
+ * @return array of VM providers
+ */
+ public IVMProvider[] getActiveProviders();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMContext.java
new file mode 100644
index 00000000000..d43c1842faf
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMContext.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * View model element which is stored as the data object of nodes in the viewer.
+ * The implementation of this interface is usually a wrapper object for an object
+ * from some data model, which is then used to correctly implement the
+ * {@link #equals(Object)} and {@link #hashCode()} methods of this wrapper.
+ */
+@Immutable
+public interface IVMContext extends IAdaptable {
+
+ /**
+ * Returns the view model node that originated this element.
+ */
+ public IVMNode getVMNode();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMEventListener.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMEventListener.java
new file mode 100644
index 00000000000..1c9800834b2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMEventListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.ui.viewmodel;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * A listener participating in event notifications sent out from VM adapter.
+ *
+ * @since 1.1
+ */
+public interface IVMEventListener {
+
+ /**
+ * Returns the executor that needs to be used to access this event listener.
+ */
+ public Executor getExecutor();
+
+ /**
+ * Process the given event and indicate completion with request monitor.
+ */
+ public void handleEvent(final Object event, RequestMonitor rm);
+
+ /**
+ * Returns whether the event handling manager should wait for this listener
+ * to complete handling this event, or whether the event listener can process
+ * the event asynchronously.
+ */
+ public boolean shouldWaitHandleEventToComplete();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java
new file mode 100644
index 00000000000..b688ea52529
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxy.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+
+/**
+ * View Model extension to the platform IModelProxy interface. This extension
+ * allows the IVMProvider implementation to delegate the model proxy implementation
+ * into a separate object.
+ * <br/>
+ * Note: The IVMModelProxy.init() may be called twice when installed, as a
+ * workaround for bug 241024.
+ */
+@SuppressWarnings("restriction")
+public interface IVMModelProxy extends IModelProxy {
+
+ /**
+ * Returns the root element that this model proxy was created for.
+ */
+ public Object getRootElement();
+
+ /**
+ * Returns whether the given event applies to the root element and the
+ * nodes in this model proxy.
+ */
+ public boolean isDeltaEvent(Object event);
+
+ /**
+ * Creates a model delta for the given event.
+ */
+ public void createDelta(final Object event, final DataRequestMonitor<IModelDelta> rm);
+
+ /**
+ * Sends the given delta to this model proxy's listeners.
+ */
+ public void fireModelChanged(IModelDelta delta);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxyExtension.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxyExtension.java
new file mode 100644
index 00000000000..812f4b39e3e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMModelProxyExtension.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * View Model extension to IVMModelProxy interface. This extension
+ * allows access to the viewer.
+ *
+ * @since 1.1
+ */
+public interface IVMModelProxyExtension extends IVMModelProxy {
+
+ /**
+ * Returns the viewer.
+ */
+ public Viewer getViewer();
+
+ /**
+ * Returns the viewer input that was set to the viewer when this proxy
+ * was created.
+ */
+ public Object getViewerInput();
+
+ /**
+ * Returns the full path for the root element. If the path is empty, it
+ * means that the root element is the viewer input.
+ * @return
+ */
+ public TreePath getRootPath();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMNode.java
new file mode 100644
index 00000000000..36279034b92
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMNode.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ * View model nodes are configured with a view model provider to collectively
+ * define the layout of a view. Each layout node generates elements of type
+ * {@link IVMContext} which are then stored in the viewer.
+ *
+ * <p/>
+ * NOTE: This interface extends <code>IElementContentProvider</code> but it has
+ * slightly different parameter requirements. For the
+ * {@link IElementContentProvider#update(IChildrenUpdate[])} method, this class
+ * can accept an update where {@link IChildrenUpdate#getOffset()} and
+ * {@link IChildrenUpdate#getLength()} may return -1. In this case the
+ * implementation should return all available elements for the given parent.<br>
+ * Also the for the {@link IElementContentProvider#update(IHasChildrenUpdate[])} and
+ * {@link IElementContentProvider#update(IChildrenCountUpdate[])} methods, the
+ * implementation may return an error with an error code of {@link IDsfService#NOT_SUPPORTED}.
+ * In this case the caller of this update should call
+ * {@link IElementContentProvider#update(IChildrenUpdate[])}
+ * instead.
+ *
+ * @see AbstractDMVMProvider
+ * @see IElementContentProvider
+ */
+@ConfinedToDsfExecutor("")
+@SuppressWarnings("restriction")
+public interface IVMNode extends IElementContentProvider
+{
+ /**
+ * Retrieves the view model provider that this node is configured with.
+ */
+ public IVMProvider getVMProvider();
+
+ /**
+ * Returns the potential delta flags that would be generated by this node
+ * for the given event.
+ * @param event Event to process.
+ * @return IModelDelta flags
+ * @see #buildDelta(Object, VMDelta, int, RequestMonitor)
+ * @see IModelDelta
+ */
+ public int getDeltaFlags(Object event);
+
+ /**
+ * Builds model delta information based on the given event.
+ * <p>
+ * Model deltas, which are used to control the state of elements in the viewer, are
+ * generated by the layout nodes by recursively calling this method on all the nodes
+ * in the layout tree. Each node implements two methods: {@link #getDeltaFlags(Object)},
+ * and <code>buildDelta()</code>. A parent node which is processing a
+ * <code>buildDelta</code> operation needs to determine which of its elements are
+ * affected by a given event, set appropriate flags on these elements, and then
+ * it needs to call its child nodes with those elements to give the child nodes a
+ * chance to add onto the delta.
+ * </p>
+ * <p>
+ * The <code>getDeltaFlags()</code> is a synchronous
+ * call which tells the parent node whether on not to call the child node's
+ * <code>buildDelta</code> with the given event. If a child node return
+ * <code>true</code>, it only indicates that the node may add delta flags, but it
+ * does not require it to do so.
+ * </p>
+ *
+ * @param event Event to process.
+ * @param parent Parent model delta node that this object should add delta
+ * data to.
+ * @param nodeOffset The offset of the first element in this node. This offset
+ * depends on the elements returned by the siblings of this layout node.
+ * @param requestMonitor Return token, which notifies the caller that the calculation is
+ * complete.
+ */
+ public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor);
+
+ /**
+ * Retireves the view model elements for the given data model event. This method
+ * is optional and it allows the view model provider to optimize event processing
+ * by avoiding the need to retrieve all possible elements for the given node.
+ * </p>
+ * For example: If a threads node implementation is given a thread stopped event in
+ * this method, and the stopped event included a reference to the thread. Then
+ * the implementation should create a view model context for that thread and return it
+ * here.
+ *
+ * @param parentDelta The parent delta in the processing of this event.
+ * @param event The event to check for the data model object.
+ * @param Request monitor for the array of elements corresponding to the
+ * given event.
+ */
+ public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm);
+
+ /**
+ * Releases the resources held by this node.
+ */
+ public void dispose();
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMProvider.java
new file mode 100644
index 00000000000..5aa50485756
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/IVMProvider.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputProvider;
+
+/**
+ * The view model provider handles the layout of a given model within a
+ * single viewer. The View Model Adapter delegates calls for view content to
+ * this object for a view that this provider handles.
+ *
+ * <p/>
+ * A given view model provider is typically configured with a number of
+ * {@link IVMNode} objects which are organized in a parent-child hierarchy.
+ * The node hierarchy has a root node which is retrieved using {@link #getRootVMNode()}.
+ *
+ * <p/>
+ * Note on concurency: The view model provider is single-threaded and it has to be
+ * accessed only using the <code>Executor</code> returned by {@link #getExecutor()}.
+ * The thread of this executor should be the display thread used by the viewer
+ * corresponding to the view model provider. Currently the flexible hierarchy
+ * interfaces that this interface extends do not guarantee that their methods
+ * will be called on the display thread, although from their use we are making
+ * this assumption (bug 213629). {@link IElementContentProvider} is an
+ * exception to this, it is called by the TreeModelViewer on a background
+ * thread, however it is not expected that the viewer will be calling the
+ * IVMProvider directly. Rather, it is expected that the viewer will call
+ * {@link IVMAdapter} which implements <code>IElementContentProvider</code>,
+ * and <code>IVMAdapter</code> implementation is expected to switch to
+ * provider's thread before delegating the call to it.
+ */
+@ConfinedToDsfExecutor("#getExecutor()")
+@SuppressWarnings("restriction")
+public interface IVMProvider
+ extends IElementContentProvider, IModelProxyFactory, IColumnPresentationFactory, IViewerInputProvider
+{
+ /**
+ * Returns the presentation context of the viewer that this provider
+ * is configured for.
+ */
+ public IPresentationContext getPresentationContext();
+
+ /**
+ * Returns the VM Adapter associated with the provider.
+ */
+ public IVMAdapter getVMAdapter();
+
+ /**
+ * Returns the executor that needs to be used to access this provider.
+ */
+ public Executor getExecutor();
+
+ /**
+ * Returns the root node that is configured in this provider.
+ * It may return null, if a root node is not yet configured.
+ */
+ public IRootVMNode getRootVMNode();
+
+ /**
+ * Returns an array of nodes which are configured as child nodes of the given node.
+ */
+ public IVMNode[] getChildVMNodes(IVMNode node);
+
+ /**
+ * Retrieves the list of all nodes configured for this provider.
+ */
+ public IVMNode[] getAllVMNodes();
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is different than calling the IVMNode update method directly in that
+ * it allows the provider to do additional processing on the update such as caching.
+ */
+ public void updateNode(final IVMNode node, IHasChildrenUpdate[] updates);
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is different than calling the IVMNode update method directly in that
+ * it allows the provider to do additional processing on the update such as caching.
+ */
+ public void updateNode(final IVMNode node, IChildrenCountUpdate updates);
+
+ /**
+ * Calls the given view model node to perform the given updates. This
+ * method is different than calling the IVMNode update method directly in that
+ * it allows the provider to do additional processing on the update such as caching.
+ */
+ public void updateNode(IVMNode node, IChildrenUpdate updates);
+
+
+ /**
+ * Cleans up the resources associated with this provider.
+ */
+ public void dispose();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/ModelProxyInstalledEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/ModelProxyInstalledEvent.java
new file mode 100644
index 00000000000..741f7588780
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/ModelProxyInstalledEvent.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.jface.viewers.Viewer;
+
+/**
+ * Event generated by an IModelProxy implementation when it is installed
+ * into a viewer.
+ */
+@SuppressWarnings("restriction")
+public class ModelProxyInstalledEvent {
+ private final IModelProxy fProxy;
+ private final Viewer fViewer;
+ private final Object fRootElement;
+
+ public ModelProxyInstalledEvent(IModelProxy proxy, Viewer viewer, Object rootElement) {
+ fProxy = proxy;
+ fViewer = viewer;
+ fRootElement = rootElement;
+ }
+
+ /**
+ * Returns the IModelProxy that generated this event.
+ */
+ public IModelProxy getModelProxy() {
+ return fProxy;
+ }
+
+ /**
+ * Returns the element that this model proxy was registered for.
+ */
+ public Object getRootElement() {
+ return fRootElement;
+ }
+
+ /**
+ * Returns the viewer that installed this model proxy.
+ */
+ public Viewer getViewer() {
+ return fViewer;
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/RootVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/RootVMNode.java
new file mode 100644
index 00000000000..41bbef29e45
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/RootVMNode.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ * Default implementation of a root view model node. This class may be sub-classed
+ * to implement model-specific event handling.
+ */
+@SuppressWarnings("restriction")
+public class RootVMNode extends AbstractVMNode implements IRootVMNode {
+
+ public RootVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ public void update(IChildrenUpdate[] updates) {
+ throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
+ }
+
+ public void update(IChildrenCountUpdate[] updates) {
+ throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
+ }
+
+ public void update(IHasChildrenUpdate[] updates) {
+ throw new UnsupportedOperationException("Root view model node should never be queried for list of elements."); //$NON-NLS-1$
+ }
+
+ /**
+ * Default implementation does not examine the event and assumes that every
+ * event should be processed to generate a delta.
+ */
+ public boolean isDeltaEvent(Object rootObject, Object event) {
+ if (event instanceof ModelProxyInstalledEvent) {
+ return rootObject.equals( ((ModelProxyInstalledEvent)event).getRootElement() );
+ }
+ return true;
+ }
+
+ /**
+ * Default implementation creates a delta assuming that the root layout node
+ * is the input object into the view.
+ */
+ public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<VMDelta> rm) {
+ rm.setData(new VMDelta(rootObject, 0, IModelDelta.NO_CHANGE));
+ rm.done();
+ }
+
+
+ public int getDeltaFlags(Object event) {
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object event, VMDelta parent, int nodeOffset, RequestMonitor requestMonitor) {
+ requestMonitor.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenCountUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenCountUpdate.java
new file mode 100644
index 00000000000..a4929a91361
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenCountUpdate.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Helper class implementation of the {@link IChildrenCountUpdate} update object.
+ *
+ * @see VMViewerUpdate
+ */
+@SuppressWarnings("restriction")
+public class VMChildrenCountUpdate extends VMViewerUpdate implements IChildrenCountUpdate {
+ final private DataRequestMonitor<Integer> fCountRequestMonitor;
+
+ public VMChildrenCountUpdate(IViewerUpdate clientUpdate, DataRequestMonitor<Integer> rm) {
+ super(clientUpdate, rm);
+ fCountRequestMonitor = rm;
+ }
+
+ public VMChildrenCountUpdate(IModelDelta delta, IPresentationContext presentationContext, DataRequestMonitor<Integer> rm) {
+ super(delta, presentationContext, rm);
+ fCountRequestMonitor = rm;
+ }
+
+ public VMChildrenCountUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, DataRequestMonitor<Integer> rm) {
+ super(elementPath, viewerInput, presentationContext, rm);
+ fCountRequestMonitor = rm;
+ }
+
+ public void setChildCount(int count) {
+ fCountRequestMonitor.setData(count);
+ }
+
+ @Override
+ public String toString() {
+ return "VMChildrenCountUpdate: " + getElement(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void done() {
+ assert isCanceled() || fCountRequestMonitor.getData() != null || !fCountRequestMonitor.isSuccess();
+ super.done();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenUpdate.java
new file mode 100644
index 00000000000..73bcc1f9ea4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMChildrenUpdate.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Helper class implementation of the {@link IChildrenUpdate} update object.
+ *
+ * @see VMViewerUpdate
+ */
+@SuppressWarnings("restriction")
+public class VMChildrenUpdate extends VMViewerUpdate implements IChildrenUpdate {
+ private final int fOffset;
+ private final int fLength;
+ protected final List<Object> fElements;
+
+ public VMChildrenUpdate(IViewerUpdate clientUpdate, int offset, int length,
+ DataRequestMonitor<List<Object>> requestMonitor)
+ {
+ super(clientUpdate, requestMonitor);
+ fOffset = offset;
+ fLength = length;
+ fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
+ }
+
+ public VMChildrenUpdate(IModelDelta delta, IPresentationContext presentationContext, int offset, int length,
+ DataRequestMonitor<List<Object>> rm)
+ {
+ super(delta, presentationContext, rm);
+ fOffset = offset;
+ fLength = length;
+ fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
+ }
+
+ public VMChildrenUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext,
+ int offset, int length, DataRequestMonitor<List<Object>> rm)
+ {
+ super(elementPath, viewerInput, presentationContext, rm);
+ fOffset = offset;
+ fLength = length;
+ fElements = length > 0 ? new ArrayList<Object>(length) : new ArrayList<Object>();
+ }
+
+ public int getOffset() {
+ return fOffset;
+ }
+
+ public int getLength() {
+ return fLength;
+ }
+
+ public void setChild(Object element, int offset) {
+ // Calculate the index in array based on configured offset.
+ int idx = offset - (fOffset > 0 ? fOffset : 0);
+
+ // To make sure that index is in valid range.
+ if (idx < 0 || (fLength > 0 && idx >= fLength)) return;
+
+ // Increase the list size if needed.
+ ensureElementsSize(idx + 1);
+
+ // Finally set the element in elements list.
+ fElements.set(idx, element);
+ }
+
+ private void ensureElementsSize(int size) {
+ while (fElements.size() < size) {
+ fElements.add(null);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "VMChildrenUpdate:" + getElement() + " {"+ getOffset() + "->" + (getOffset() + getLength()) + "}"; //$NON-NLS-1$ //$NON-NLS-2$//$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ @Override
+ public void done() {
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<List<Object>> rm = (DataRequestMonitor<List<Object>>)getRequestMonitor();
+
+ /* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=202109
+ *
+ * A flexible hierarchy bug/optimization causes query with incorrect
+ * IChildrenUpdate[] array length.
+ *
+ * The problem manifests itself while deleting a register node.
+ * For example, if the register view displays:
+ * PC
+ * EAX
+ * EBX
+ * ECX
+ * EDX
+ * And EBX is deleted, forcing a refresh, the viewer will query
+ * for IChildrenUpdate[5] and IChildrenCountUpdate at the same time.
+ *
+ * To avoid this problem do not generate an error if the list of
+ * children is smaller than the list of requested indexes. Also,
+ * do not check if any of the elements are null.
+ */
+ rm.setData(fElements);
+ super.done();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMDelta.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMDelta.java
new file mode 100644
index 00000000000..2e20cc6e2e2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMDelta.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * 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
+ * Wind River Systems - adapted to use in DSF
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDeltaVisitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+
+/**
+ * This delta class mostly just duplicates the ModelDelta implemention, but
+ * it allows clients to modify the flags after the original object is
+ * constructed.
+ *
+ * @see IModelDelta#getNodes()
+ */
+@SuppressWarnings("restriction")
+public class VMDelta extends ModelDelta {
+
+ private VMDelta fParent;
+ private Object fElement;
+ private int fFlags;
+ private VMDelta[] fNodes = EMPTY_NODES;
+ private Object fReplacement;
+ private int fIndex;
+ private static final VMDelta[] EMPTY_NODES = new VMDelta[0];
+ private int fChildCount = -1;
+
+ /**
+ * Constructs a new delta for the given element.
+ *
+ * @param vmcElement model element
+ * @param flags change flags
+ */
+ public VMDelta(Object element, int flags) {
+ super(element, flags);
+ fElement = element;
+ fFlags = flags;
+ }
+
+ /**
+ * Constructs a new delta for the given element to be replaced
+ * with the specified replacement element.
+ *
+ * @param vmcElement model element
+ * @param replacement replacement element
+ * @param flags change flags
+ */
+ public VMDelta(Object element, Object replacement, int flags) {
+ super(element, replacement, flags);
+ fElement = element;
+ fReplacement = replacement;
+ fFlags = flags;
+ }
+
+ /**
+ * Constructs a new delta for the given element to be inserted at
+ * the specified index.
+ *
+ * @param vmcElement model element
+ * @param index insertion position
+ * @param flags change flags
+ */
+ public VMDelta(Object element, int index, int flags) {
+ super(element, index, flags);
+ fElement = element;
+ fIndex = index;
+ fFlags = flags;
+ }
+
+ /**
+ * Constructs a new delta for the given element at the specified index
+ * relative to its parent with the given number of children.
+ *
+ * @param element model element
+ * @param index insertion position
+ * @param flags change flags
+ * @param childCount number of children this node has
+ */
+ public VMDelta(Object element, int index, int flags, int childCount) {
+ super(element, index, flags, childCount);
+ fElement = element;
+ fIndex = index;
+ fFlags = flags;
+ fChildCount = childCount;
+ }
+
+ /**
+ * Returns the non-VMC element if one is set, otherwise returns the VMC
+ * element of this delta node.
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getElement()
+ */
+ @Override
+ public Object getElement() {
+ return fElement;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getFlags()
+ */
+ @Override
+ public int getFlags() {
+ return fFlags;
+ }
+
+ /**
+ * Sets this delta's flags.
+ *
+ * @param flags
+ */
+ @Override
+ public void setFlags(int flags) {
+ fFlags = flags;
+ }
+
+ @Override
+ public void setChildCount(int count) {
+ fChildCount = count;
+ }
+
+ /**
+ * Adds a child node to this delta with the given element and change flags,
+ * and returns the child delta.
+ *
+ * @param element child element to add
+ * @param flags change flags for child
+ * @return newly created child delta
+ */
+ @Override
+ public VMDelta addNode(Object element, int flags) {
+ VMDelta node = new VMDelta(element, flags);
+ node.setParent(this);
+ addDelta(node);
+ return node;
+ }
+
+ /**
+ * Adds a child node to this delta to replace the given element with the
+ * specified replacement element and change flags, and returns the
+ * newly created child delta.
+ *
+ * @param element child element to add to this delta
+ * @param replacement replacement element for the child element
+ * @param flags change flags
+ * @return newly created child delta
+ */
+ @Override
+ public VMDelta addNode(Object element, Object replacement, int flags) {
+ VMDelta node = new VMDelta(element, replacement, flags);
+ node.setParent(this);
+ addDelta(node);
+ return node;
+ }
+
+ /**
+ * Adds a child delta to this delta to insert the specified element at
+ * the given index, and returns the newly created child delta.
+ *
+ * @param element child element in insert
+ * @param index index of insertion
+ * @param flags change flags
+ * @return newly created child delta
+ */
+ @Override
+ public VMDelta addNode(Object element, int index, int flags) {
+ VMDelta node = new VMDelta(element, index, flags);
+ node.setParent(this);
+ addDelta(node);
+ return node;
+ }
+
+ /**
+ * Adds a child delta to this delta at the specified index with the
+ * given number of children, and returns the newly created child delta.
+ *
+ * @param element child element in insert
+ * @param index index of the element relative to parent
+ * @param flags change flags
+ * @param numChildren the number of children the element has
+ * @return newly created child delta
+ */
+ @Override
+ public VMDelta addNode(Object element, int index, int flags, int numChildren) {
+ VMDelta node = new VMDelta(element, index, flags, numChildren);
+ node.setParent(this);
+ addDelta(node);
+ return node;
+ }
+
+ /**
+ * Returns the child delta for the given element, or <code>null</code> if none.
+ *
+ * @param element child element
+ * @return corresponding delta node, or <code>null</code>
+ *
+ * @since 1.1
+ */
+ @Override
+ public VMDelta getChildDelta(Object element) {
+ if (fNodes != null) {
+ for (int i = 0; i < fNodes.length; i++) {
+ VMDelta delta = fNodes[i];
+ if (element.equals(delta.getElement())) {
+ return delta;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the parent delta of this delta
+ *
+ * @param node parent delta
+ */
+ void setParent(VMDelta node) {
+ fParent = node;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getParent()
+ */
+ @Override
+ public VMDelta getParentDelta() {
+ return fParent;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getReplacementElement()
+ */
+ @Override
+ public Object getReplacementElement() {
+ return fReplacement;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getIndex()
+ */
+ @Override
+ public int getIndex() {
+ return fIndex;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.IModelDelta#getNodes()
+ */
+ @Override
+ public VMDelta[] getChildDeltas() {
+ return fNodes;
+ }
+
+ private void addDelta(VMDelta delta) {
+ if (fNodes.length == 0) {
+ fNodes = new VMDelta[]{delta};
+ } else {
+ VMDelta[] nodes = new VMDelta[fNodes.length + 1];
+ System.arraycopy(fNodes, 0, nodes, 0, fNodes.length);
+ nodes[fNodes.length] = delta;
+ fNodes = nodes;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("Model Delta Start\n"); //$NON-NLS-1$
+ appendDetail(buf, this);
+ buf.append("Model Delta End\n"); //$NON-NLS-1$
+ return buf.toString();
+ }
+
+ private void appendDetail(StringBuffer buf, VMDelta delta) {
+ buf.append("\tElement: "); //$NON-NLS-1$
+ buf.append(delta.getElement());
+ buf.append('\n');
+ buf.append("\t\tFlags: "); //$NON-NLS-1$
+ int flags = delta.getFlags();
+ if (flags == 0) {
+ buf.append("NO_CHANGE"); //$NON-NLS-1$
+ } else {
+ if ((flags & IModelDelta.ADDED) > 0) {
+ buf.append("ADDED | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.CONTENT) > 0) {
+ buf.append("CONTENT | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.EXPAND) > 0) {
+ buf.append("EXPAND | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.INSERTED) > 0) {
+ buf.append("INSERTED | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.REMOVED) > 0) {
+ buf.append("REMOVED | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.REPLACED) > 0) {
+ buf.append("REPLACED | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.SELECT) > 0) {
+ buf.append("SELECT | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.STATE) > 0) {
+ buf.append("STATE | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.INSTALL) > 0) {
+ buf.append("INSTALL | "); //$NON-NLS-1$
+ }
+ if ((flags & IModelDelta.UNINSTALL) > 0) {
+ buf.append("UNINSTALL | "); //$NON-NLS-1$
+ }
+ }
+ buf.append('\n');
+ buf.append("\t\tIndex: "); //$NON-NLS-1$
+ buf.append(delta.fIndex);
+ buf.append(" Child Count: "); //$NON-NLS-1$
+ buf.append(delta.fChildCount);
+ buf.append('\n');
+ IModelDelta[] nodes = delta.getChildDeltas();
+ for (int i = 0; i < nodes.length; i++) {
+ appendDetail(buf, (VMDelta)nodes[i]);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#getChildCount()
+ */
+ @Override
+ public int getChildCount() {
+ return fChildCount;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.ui.viewers.provisional.IModelDelta#accept(org.eclipse.debug.internal.ui.viewers.provisional.IModelDeltaVisitor)
+ */
+ @Override
+ public void accept(IModelDeltaVisitor visitor) {
+ doAccept(visitor, 0);
+ }
+
+ @Override
+ protected void doAccept(IModelDeltaVisitor visitor, int depth) {
+ if (visitor.visit(this, depth)) {
+ ModelDelta[] childDeltas = getChildDeltas();
+ for (int i = 0; i < childDeltas.length; i++) {
+ ((VMDelta)childDeltas[i]).doAccept(visitor, depth+1);
+ }
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMHasChildrenUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMHasChildrenUpdate.java
new file mode 100644
index 00000000000..3c20145dc2b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMHasChildrenUpdate.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Helper class implementation of the {@link IHasChildrenUpdate} update object.
+ *
+ * @see VMViewerUpdate
+ */
+@SuppressWarnings("restriction")
+public class VMHasChildrenUpdate extends VMViewerUpdate implements IHasChildrenUpdate {
+
+ final private DataRequestMonitor<Boolean> fHasElemsRequestMonitor;
+
+ public VMHasChildrenUpdate(IViewerUpdate clientUpdate, DataRequestMonitor<Boolean> rm) {
+ super(clientUpdate, rm);
+ fHasElemsRequestMonitor = rm;
+ }
+
+ public VMHasChildrenUpdate(IModelDelta delta, IPresentationContext presentationContext, DataRequestMonitor<Boolean> rm) {
+ super(delta, presentationContext, rm);
+ fHasElemsRequestMonitor = rm;
+ }
+
+ public VMHasChildrenUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, DataRequestMonitor<Boolean> rm) {
+ super(elementPath, viewerInput, presentationContext, rm);
+ fHasElemsRequestMonitor = rm;
+ }
+
+ public void setHasChilren(boolean hasChildren) {
+ fHasElemsRequestMonitor.setData(hasChildren);
+ }
+
+ @Override
+ public String toString() {
+ return "VMHasChildrenUpdate: " + getElement(); //$NON-NLS-1$
+ }
+
+ @Override
+ public void done() {
+ assert isCanceled() || fHasElemsRequestMonitor.getData() != null || !fHasElemsRequestMonitor.isSuccess();
+ super.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMViewerUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMViewerUpdate.java
new file mode 100644
index 00000000000..004bf39ec2d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/VMViewerUpdate.java
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Helper class implementation of the update objects used with
+ * {@link IElementContentProvider}, {@link IElementLabelProvider},
+ * and {@link IElementMementoProvider}. The viewer update can be constructed
+ * using a higher level update object or a set of parameters to fulfill the
+ * <code>IViewerUpdate</code> interface.
+ */
+@SuppressWarnings("restriction")
+public class VMViewerUpdate implements IViewerUpdate {
+
+ /**
+ * The request monitor to be called when this update is completed.
+ */
+ final private RequestMonitor fRequestMonitor;
+
+ /**
+ * A higher-level update that this update is based on. If specified, the given
+ * update is used to delegate calls to {@link #cancel()} and {@link #isCanceled()}.
+ */
+ final private IViewerUpdate fClientUpdate;
+
+ /**
+ * The flag indicating whether this update was cancelled. This flag is not used
+ * if the {@link #fClientUpdate} is initialized.
+ */
+ final private AtomicBoolean fCanceled;
+
+ /**
+ * The viewer input object for this update.
+ */
+ final private Object fViewerInput;
+
+ /**
+ * The element object of this update.
+ */
+ final private Object fElement;
+
+ /**
+ * The element path of this update.
+ */
+ final private TreePath fElementPath;
+
+ /**
+ * The presentation context of this update.
+ */
+ final private IPresentationContext fPresentationContext;
+
+ /**
+ * Creates a viewer update based on a higher-level update. The update element
+ * information as well as cancel requests are delegated to the given client
+ * update.
+ * <p/>
+ * Note: this update will not automatically call the client update's
+ * {@link IRequest#done()} method. The user of this update should supply
+ * a request monitor which properly completes the client update.
+ *
+ * @param clientUpdate Client update that this update is based on.
+ * @param requestMonitor Call-back invoked when this update completes.
+ */
+ public VMViewerUpdate(IViewerUpdate clientUpdate, RequestMonitor requestMonitor) {
+ fViewerInput = clientUpdate.getViewerInput();
+ fElement = clientUpdate.getElement();
+ fElementPath = clientUpdate.getElementPath();
+ fPresentationContext = clientUpdate.getPresentationContext();
+ fRequestMonitor = requestMonitor;
+ fClientUpdate = clientUpdate;
+ fCanceled = null;
+ }
+
+ /**
+ * Request monitor which uses a model delta to calculate the element information.
+ * This update is useful when calculating a model delta for a given view model node.
+ *
+ * @param delta Model delta of a parent element.
+ * @param presentationContext Presentation context for this update.
+ * @param requestMonitor Call-back invoked when this update completes.
+ */
+ public VMViewerUpdate(IModelDelta delta, IPresentationContext presentationContext, RequestMonitor requestMonitor) {
+ List<Object> elementList = new LinkedList<Object>();
+ IModelDelta listDelta = delta;
+ elementList.add(0, listDelta.getElement());
+ while (listDelta.getParentDelta() != null) {
+ listDelta = listDelta.getParentDelta();
+ elementList.add(0, listDelta.getElement());
+ }
+ fViewerInput = elementList.get(0);
+ fElement = elementList.get(elementList.size() - 1);
+ elementList.remove(0);
+ fElementPath = new TreePath(elementList.toArray());
+ fPresentationContext = presentationContext;
+ fRequestMonitor = requestMonitor;
+ fClientUpdate = null;
+ fCanceled = new AtomicBoolean(false);
+ }
+
+ /**
+ * Creates a viewer update with the given parameters.
+ *
+ * @param elementPath The path to the element for which the update is generated.
+ * @param viewerInput Input into the viewer of the update.
+ * @param presentationContext Presentation context for this update.
+ * @param requestMonitor Call-back invoked when this update completes.
+ */
+ public VMViewerUpdate(TreePath elementPath, Object viewerInput, IPresentationContext presentationContext, RequestMonitor requestMonitor) {
+ fViewerInput = viewerInput;
+ fElement = elementPath.getSegmentCount() != 0 ? elementPath.getLastSegment() : viewerInput;
+ fElementPath = elementPath;
+ fPresentationContext = presentationContext;
+ fRequestMonitor = requestMonitor;
+ fClientUpdate = null;
+ fCanceled = new AtomicBoolean(false);
+ }
+
+ protected RequestMonitor getRequestMonitor() {
+ return fRequestMonitor;
+ }
+
+ public Object getViewerInput() { return fViewerInput; }
+ public Object getElement() { return fElement; }
+ public TreePath getElementPath() { return fElementPath; }
+ public IPresentationContext getPresentationContext() { return fPresentationContext; }
+ public IStatus getStatus() { return fRequestMonitor.getStatus(); }
+ public void setStatus(IStatus status) { fRequestMonitor.setStatus(status); }
+
+ public boolean isCanceled() {
+ if (fClientUpdate != null) {
+ return fClientUpdate.isCanceled();
+ } else {
+ return fCanceled.get();
+ }
+ }
+ public void cancel() {
+ if (fClientUpdate != null) {
+ fClientUpdate.cancel();
+ } else {
+ fCanceled.set(true);
+ }
+ }
+
+ public void done() {
+ try {
+ if ( isCanceled() ) {
+ fRequestMonitor.cancel();
+ fRequestMonitor.setStatus(new Status( IStatus.CANCEL, DsfUIPlugin.PLUGIN_ID," Update was cancelled") ); //$NON-NLS-1$
+ }
+ fRequestMonitor.done();
+ } catch (RejectedExecutionException e) {
+ // If the request monitor cannot be invoked still, try to complete the update to avoid
+ // leaving the viewer in an inconsistent state.
+ if (fClientUpdate != null) {
+ fClientUpdate.done();
+ }
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMAdapter.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMAdapter.java
new file mode 100644
index 00000000000..18465e69f95
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMAdapter.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+
+/**
+ * Base implementation for DSF-based view model adapters.
+ */
+@ThreadSafe
+abstract public class AbstractDMVMAdapter extends AbstractVMAdapter
+{
+ private final DsfSession fSession;
+
+ /**
+ * It is theoretically possible for a VM adapter to be disposed before it
+ * has a chance to register itself as event listener. This flag is used
+ * to avoid removing itself as listener in such situation.
+ */
+ private boolean fRegisteredAsEventListener = false;
+
+ /**
+ * Constructor for the View Model session. It is tempting to have the
+ * adapter register itself here with the session as the model adapter, but
+ * that would mean that the adapter might get accessed on another thread
+ * even before the deriving class is fully constructed. So it it better
+ * to have the owner of this object register it with the session.
+ * @param session
+ */
+ public AbstractDMVMAdapter(DsfSession session) {
+ super();
+ fSession = session;
+ // Add ourselves as listener for DM events events.
+ try {
+ session.getExecutor().execute(new Runnable() {
+ public void run() {
+ if (DsfSession.isSessionActive(getSession().getId())) {
+ getSession().addServiceEventListener(AbstractDMVMAdapter.this, null);
+ fRegisteredAsEventListener = true;
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session shut down, not much we can do but wait to be disposed.
+ }
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ getSession().getExecutor().execute(new Runnable() {
+ public void run() {
+ if (fRegisteredAsEventListener && getSession().isActive()) {
+ fSession.removeServiceEventListener(AbstractDMVMAdapter.this);
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session shut down.
+ }
+ super.dispose();
+ }
+
+ /**
+ * Returns the DSF session that this adapter is associated with.
+ * @return
+ */
+ protected DsfSession getSession() { return fSession; }
+
+ /**
+ * Handle "data model changed" event by generating a delta object for each
+ * view and passing it to the corresponding view model provider. The view
+ * model provider is then responsible for filling-in and sending the delta
+ * to the viewer.
+ *
+ * @param event
+ *
+ * @since 1.1
+ */
+ @DsfServiceEventHandler
+ public final void eventDispatched(final IDMEvent<?> event) {
+ // We're in session's executor thread (session in which the event originated).
+ if (isDisposed()) return;
+
+ handleEvent(event);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMNode.java
new file mode 100644
index 00000000000..1dac1af30da
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMNode.java
@@ -0,0 +1,411 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITreeSelection;
+import org.eclipse.jface.viewers.TreePath;
+
+
+/**
+ * View model node based on a single Data Model Context type.
+ * The assumption in this implementation is that elements of this node have
+ * a single IDMContext associated with them, and all of these contexts
+ * are of the same class type.
+ */
+@SuppressWarnings("restriction")
+abstract public class AbstractDMVMNode extends AbstractVMNode implements IVMNode {
+
+ /**
+ * IVMContext implementation used for this schema node.
+ */
+ @Immutable
+ protected class DMVMContext extends AbstractVMContext implements IDMVMContext {
+ private final IDMContext fDmc;
+
+ public DMVMContext(IDMContext dmc) {
+ super(AbstractDMVMNode.this);
+ fDmc = dmc;
+ }
+
+ public IDMContext getDMContext() { return fDmc; }
+
+ /**
+ * The IAdaptable implementation. If the adapter is the DM context,
+ * return the context, otherwise delegate to IDMContext.getAdapter().
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ Object superAdapter = super.getAdapter(adapter);
+ if (superAdapter != null) {
+ return superAdapter;
+ } else {
+ // Delegate to the Data Model to find the context.
+ if (adapter.isInstance(fDmc)) {
+ return fDmc;
+ } else {
+ return fDmc.getAdapter(adapter);
+ }
+ }
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof AbstractDMVMNode.DMVMContext)) return false;
+ DMVMContext otherVmc = (DMVMContext)other;
+ return AbstractDMVMNode.this.equals(otherVmc.getVMNode()) &&
+ fDmc.equals(otherVmc.fDmc);
+ }
+
+ @Override
+ public int hashCode() {
+ return AbstractDMVMNode.this.hashCode() + fDmc.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return fDmc.toString();
+ }
+ }
+
+ private DsfSession fSession;
+
+ private DsfServicesTracker fServicesTracker;
+
+ /**
+ * Concrete class type that the elements of this schema node are based on.
+ * Even though the data model type is a parameter the DMContextVMLayoutNode,
+ * this type is erased at runtime, so a concrete class typs of the DMC
+ * is needed for instanceof chacks.
+ */
+ private Class<? extends IDMContext> fDMCClassType;
+
+ /**
+ * Constructor initializes instance data, except for the child nodes.
+ * Child nodes must be initialized by calling setChildNodes()
+ * @param session
+ * @param dmcClassType
+ * @see #setChildNodes(IVMNode[])
+ */
+ public AbstractDMVMNode(AbstractDMVMProvider provider, DsfSession session, Class<? extends IDMContext> dmcClassType) {
+ super(provider);
+ fSession = session;
+ fServicesTracker = new DsfServicesTracker(DsfUIPlugin.getBundleContext(), session.getId());
+ fDMCClassType = dmcClassType;
+ }
+
+ @Override
+ public void dispose() {
+ fServicesTracker.dispose();
+ super.dispose();
+ }
+
+ @Override
+ public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm) {
+ if (event instanceof IDMEvent<?>) {
+ IDMEvent<?> dmEvent = (IDMEvent<?>)event;
+ IDMContext dmc = DMContexts.getAncestorOfType(dmEvent.getDMContext(), fDMCClassType);
+ if (dmc != null) {
+ rm.setData(new IVMContext[] { createVMContext(dmc) });
+ rm.done();
+ return;
+ }
+ }
+ super.getContextsForEvent(parentDelta, event, rm);
+ }
+
+ protected AbstractDMVMProvider getDMVMProvider() {
+ return (AbstractDMVMProvider)getVMProvider();
+ }
+
+ protected DsfSession getSession() {
+ return fSession;
+ }
+
+ protected DsfServicesTracker getServicesTracker() {
+ return fServicesTracker;
+ }
+
+ @Override
+ protected boolean checkUpdate(IViewerUpdate update) {
+ if (!super.checkUpdate(update)) return false;
+
+ // Extract the VMC from the update (whatever the update sub-class.
+ Object element = update.getElement();
+ if (element instanceof IDMVMContext) {
+ // If update element is a DMC, check if session is still alive.
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+ if (dmc.getSessionId() != getSession().getId() || !DsfSession.isSessionActive(dmc.getSessionId())) {
+ handleFailedUpdate(update);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convenience method that checks whether the given dmc context is null. If it is null, an
+ * appropriate error message is set in the update.
+ * @param dmc Data Model Context (DMC) to check.
+ * @param update Update to handle in case the DMC is null.
+ * @return true if the DMC is NOT null, indicating that it's OK to proceed.
+ *
+ * This method has been deprecated. Users should simply perform this functionality in-line
+ *
+ * Example :
+ *
+ * IExampleDmc dmc = final TimerDMContext dmc = findDmcInPath(...)
+ * if ( dmc == null ) {
+ * handleFailedUpdate(update);
+ * //
+ * // Perform whatever cleanup or completion is needed because of a lack of
+ * // a valid data model context.
+ * //
+ * ........
+ * return;
+ * }
+ */
+
+ @Deprecated
+ protected boolean checkDmc(IDMContext dmc, IViewerUpdate update) {
+ if (dmc == null) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "No valid context found.", null)); //$NON-NLS-1$
+ handleFailedUpdate(update);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * A convenience method that checks whether a given service exists. If the service does not
+ * exist, the update is filled in with the appropriate error message.
+ * @param serviceClass Service class to find.
+ * @param filter Service filter to use in addition to the service class name.
+ * @param update Update object to fill in.
+ * @return true if service IS found, indicating that it's OK to proceed.
+ *
+ * This method has been deprecated. Users should simply perform this functionality in-line
+ *
+ * Example :
+ *
+ * IExampleService service = getServicesTracker().getService(IExampleService.class,null);
+ * if ( service == null ) {
+ * handleFailedUpdate(update);
+ * //
+ * // Perform whatever cleanup or completion is needed because of a lack of the service.
+ * //
+ * ........
+ * return;
+ * }
+ */
+ @Deprecated
+ protected boolean checkService(Class<? extends IDsfService> serviceClass, String filter, IViewerUpdate update) {
+ if (getServicesTracker().getService(serviceClass, filter) == null) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service " + serviceClass.getName() + " not available.", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ handleFailedUpdate(update);
+ return false;
+ }
+ return true;
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ for (IHasChildrenUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ updateHasElementsInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ protected void updateHasElementsInSessionThread(final IHasChildrenUpdate update) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Not implemented, clients should call to update all children instead.", null)); //$NON-NLS-1$
+ update.done();
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ for (IChildrenCountUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ updateElementCountInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ protected void updateElementCountInSessionThread(final IChildrenCountUpdate update) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "Not implemented, clients should call to update all children instead.", null)); //$NON-NLS-1$
+ update.done();
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ // After every dispatch, must check if update still valid.
+ for (IChildrenUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ updateElementsInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ abstract protected void updateElementsInSessionThread(IChildrenUpdate update);
+
+ /**
+ * Utility method that takes an array of DMC object and creates a
+ * corresponding array of IVMContext elements base on that.
+ * @param parent The parent for generated IVMContext elements.
+ * @param dmcs Array of DMC objects to build return array on.
+ * @return Array of IVMContext objects.
+ */
+ protected IVMContext[] dmcs2vmcs(IDMContext[] dmcs) {
+ IVMContext[] vmContexts = new IVMContext[dmcs.length];
+ for (int i = 0; i < dmcs.length; i++) {
+ vmContexts[i] = createVMContext(dmcs[i]);
+ }
+ return vmContexts;
+ }
+
+ /**
+ * Fill update request with view model contexts based on given data model contexts.
+ * Assumes that data model context elements start at index 0.
+ *
+ * @param update the viewer update request
+ * @param dmcs the data model contexts
+ */
+ protected void fillUpdateWithVMCs(IChildrenUpdate update, IDMContext[] dmcs) {
+ fillUpdateWithVMCs(update, dmcs, 0);
+ }
+
+ /**
+ * Fill update request with view model contexts based on given data model contexts.
+ *
+ * @param update the viewer update request
+ * @param dmcs the data model contexts
+ * @param firstIndex the index of the first data model context
+ *
+ * @since 1.1
+ */
+ protected void fillUpdateWithVMCs(IChildrenUpdate update, IDMContext[] dmcs, int firstIndex) {
+ int updateIdx = update.getOffset() != -1 ? update.getOffset() : 0;
+ final int endIdx = updateIdx + (update.getLength() != -1 ? update.getLength() : dmcs.length);
+ int dmcIdx = updateIdx - firstIndex;
+ if (dmcIdx < 0) {
+ updateIdx -= dmcIdx;
+ dmcIdx = 0;
+ }
+ while (updateIdx < endIdx && dmcIdx < dmcs.length) {
+ update.setChild(createVMContext(dmcs[dmcIdx++]), updateIdx++);
+ }
+ }
+
+ protected IDMVMContext createVMContext(IDMContext dmc) {
+ return new DMVMContext(dmc);
+ }
+
+ /**
+ * Creates a default CompositeDMVMContext which represents the selection.
+ * This can be overridden by view model providers which for their own purposes.
+ * @param update defines the selection to be updated to
+ * @return DM Context which represent the current selection
+ */
+ protected IDMContext createCompositeDMVMContext(IViewerUpdate update) {
+ return new CompositeDMVMContext(update);
+ }
+
+ /**
+ * Searches for a DMC of given type in the tree patch contained in given
+ * VMC. Only a DMC in the same session will be returned.
+ * @param <V> Type of the DMC that will be returned.
+ * @param vmc VMC element to search.
+ * @param dmcType Class object for matching the type.
+ * @return DMC, or null if not found.
+ */
+ protected <T extends IDMContext> T findDmcInPath(Object inputObject, TreePath path, Class<T> dmcType) {
+ T retVal = null;
+ for (int i = path.getSegmentCount() - 1; i >= 0; i--) {
+ if (path.getSegment(i) instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext)path.getSegment(i)).getDMContext();
+ if ( dmc.getSessionId().equals(getSession().getId()) ) {
+ retVal = DMContexts.getAncestorOfType(dmc, dmcType);
+ if (retVal != null) break;
+ }
+ }
+ }
+ // Search the root object of the layout hierarchy.
+ if (retVal == null) {
+ if (inputObject instanceof ITreeSelection) {
+ ITreeSelection inputSelection = (ITreeSelection)inputObject;
+ if (inputSelection.getPaths().length == 1) {
+ retVal = findDmcInPath(null, inputSelection.getPaths()[0], dmcType);
+ }
+ } else if (inputObject instanceof IStructuredSelection) {
+ Object rootElement = ((IStructuredSelection)inputObject).getFirstElement();
+ if (rootElement instanceof IDMVMContext) {
+ retVal = DMContexts.getAncestorOfType(((IDMVMContext)rootElement).getDMContext(), dmcType);
+ }
+ } else if (inputObject instanceof IDMVMContext) {
+ retVal = DMContexts.getAncestorOfType(((IDMVMContext)inputObject).getDMContext(), dmcType);
+ }
+ }
+
+ return retVal;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMProvider.java
new file mode 100644
index 00000000000..1b7d36109a2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/AbstractDMVMProvider.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.update.AbstractCachingVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousContentAdapter;
+import org.eclipse.debug.internal.ui.viewers.provisional.IAsynchronousLabelAdapter;
+
+/**
+ * View model provider implements the asynchronous view model functionality for
+ * a single view. This provider is just a holder which further delegates the
+ * model provider functionality to the view model nodes that need
+ * to be configured with each provider.
+ * <p>
+ * The view model provider, often does not provide the model for the entire
+ * view. Rather, it needs to be able to plug in at any level in the viewer's
+ * content model and provide data for a sub-tree.
+ *
+ * @see IAsynchronousContentAdapter
+ * @see IAsynchronousLabelAdapter
+ * @see IModelProxy
+ * @see IVMNode
+ */
+@ConfinedToDsfExecutor("fSession#getExecutor")
+@SuppressWarnings("restriction")
+abstract public class AbstractDMVMProvider extends AbstractCachingVMProvider
+{
+ private final DsfSession fSession;
+ /**
+ * Constructs the view model provider for given DSF session. The
+ * constructor is thread-safe to allow VM provider to be constructed
+ * synchronously when a call to getAdapter() is made on an element
+ * in a view.
+ */
+ public AbstractDMVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
+ super(adapter, presentationContext);
+ fSession = session;
+ }
+
+ public DsfSession getSession() { return fSession; }
+
+ /**
+ * @deprecated Kept for API compatibility reasons.
+ * Events are now received and dispatched by the VM adapter.
+ */
+ @Deprecated
+ @DsfServiceEventHandler
+ public void eventDispatched(final IDMEvent<?> event) {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/CompositeDMVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/CompositeDMVMContext.java
new file mode 100644
index 00000000000..b09782f0d66
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/CompositeDMVMContext.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.datamodel.CompositeDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Object used to combine several DM Contexts found in a tree path of a viewer
+ * update. This object allows the view model to pass complete data model context
+ * information found in the view to the services.
+ */
+@SuppressWarnings("restriction")
+public class CompositeDMVMContext extends CompositeDMContext {
+
+ /**
+ * Have to pass in an empty array of contexts to parent constructor
+ * in order to be able to calculate the
+ */
+ private static IDMContext[] EMPTY_CONTEXTS_ARRAY = new IDMContext[0];
+
+ /**
+ * The list of parent contexts derived from the input object and
+ * the path. It is calculated on demand.
+ */
+ private IDMContext[] fParents;
+
+ /**
+ * Creates a composite context based in a viewer update.
+ */
+ public CompositeDMVMContext(IViewerUpdate update) {
+ this(update.getViewerInput(), update.getElementPath());
+ }
+
+ /**
+ * Creates a composite context based on a viewer input and a tree path.
+ */
+ public CompositeDMVMContext(Object viewerInputObject, TreePath treePath) {
+ super(EMPTY_CONTEXTS_ARRAY);
+ List<IDMContext> parentsList = new ArrayList<IDMContext>(treePath.getSegmentCount() + 1);
+ for (int i = treePath.getSegmentCount() - 1; i >=0 ; i--) {
+ if (treePath.getSegment(i) instanceof IDMVMContext) {
+ parentsList.add( ((IDMVMContext)treePath.getSegment(i)).getDMContext() );
+ }
+ }
+ if (viewerInputObject instanceof IDMVMContext) {
+ parentsList.add( ((IDMVMContext)viewerInputObject).getDMContext() );
+ }
+
+ fParents = parentsList.toArray(new IDMContext[parentsList.size()]);
+}
+
+ @Override
+ public IDMContext[] getParents() {
+ return fParents;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/IDMVMContext.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/IDMVMContext.java
new file mode 100644
index 00000000000..12b989fcd71
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/IDMVMContext.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+
+/**
+ * Interface for a view model context based on a DSF data model context.
+ */
+public interface IDMVMContext extends IVMContext {
+
+ public static Object REFRESH_EVENT = new Object();
+
+ /**
+ * returns the data model context that this view model context wraps.
+ */
+ public IDMContext getDMContext();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/RootDMVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/RootDMVMNode.java
new file mode 100644
index 00000000000..c847131020e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/datamodel/RootDMVMNode.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.datamodel;
+
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.RootVMNode;
+
+/**
+ * This is is a standard root node which listens to the selection in Debug View.
+ * Views such as variables and registers base their content on the
+ * selection in Debug view, and this node provides tracking of that selection.
+ * <p>
+ * Note: The variables/registers views track the selection using the same
+ * IDebugContextListener interface, but they only use the first element of the
+ * selection, as in IStructuredSelection.getFirstElement(). Therefore the root
+ * node also has to use the first element as the root object instead of the
+ * whole selection.
+ */
+public class RootDMVMNode extends RootVMNode
+ implements IRootVMNode
+{
+ public RootDMVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+
+ @Override
+ public String toString() {
+ return "RootDMVMNode"; //$NON-NLS-1$
+ }
+
+ /**
+ * If the input object is a Data Model context, and the event is a DMC event.
+ * Then we can filter the event to make sure that the view does not
+ * react to events that relate to objects outside this view.
+ *
+ * The logic is such:
+ * - iterate through the full hierarchy of the DMC in the event,
+ * - for each DMC in event, search for a DMC of the same type in the input
+ * event,
+ * - if an ancestor of that type is found, it indicates that the event
+ * and the input object share the same hierarchy
+ * - finally compare the DMContexts from the event to the DMC from the input
+ * object,
+ * - if there is a match then we know that the event relates
+ * to the hierarchy in view,
+ * - if there is no match, then we know that the event related to a
+ * some sibling of the input object, and no delta should be generated,
+ * - if none of the ancestor types matched, then the event is completely
+ * unrelated to the input object, and the layout nodes in the view must
+ * determine whether a delta is needed.
+ */
+ @Override
+ public boolean isDeltaEvent(Object rootObject, Object event) {
+ if (rootObject instanceof IDMVMContext) {
+ IDMContext inputDmc = ((IDMVMContext)rootObject).getDMContext();
+ if (event instanceof IDMEvent && inputDmc != null) {
+ boolean potentialMatchFound = false;
+ boolean matchFound = false;
+
+ IDMContext eventDmc = ((IDMEvent<?>)event).getDMContext();
+ for (IDMContext eventDmcAncestor : DMContexts.toList(eventDmc)) {
+ IDMContext inputDmcAncestor = DMContexts.getAncestorOfType(inputDmc, eventDmcAncestor.getClass());
+ if (inputDmcAncestor != null) {
+ potentialMatchFound = true;
+ if (inputDmcAncestor.equals(eventDmcAncestor)) {
+ return true;
+ }
+ }
+ }
+ if (potentialMatchFound && !matchFound) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/package.html b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/package.html
new file mode 100644
index 00000000000..12e15efaf52
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/package.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Eclipse Device Debug - Debugger Services Framework - View Model</title>
+</head>
+<body>
+Provides a set of&nbsp; utilities and interfaces for defining the
+conent and layout of views based on Debugger Services Framework (DSF).<br>
+<br>
+<h2>Package Specification</h2>
+<p>The DSF data model is designed in a way to make it easy to achieve
+modularity in the services that collectively make-up its
+contents.&nbsp; This design goal makes it difficult to display the data
+in a view, because its layout of the data needs to depend on the type
+of view.&nbsp; This package is used to make it simpler to take the
+contents of a data model and display them in various debug views, using
+the platform debug flexible-hierarchy asynchronous debug
+views.&nbsp;&nbsp; <br>
+</p>
+<h3>Development Plans</h3>
+This package is also a work in progress and it is missing a major
+feature.&nbsp;
+This feature is to be able to create a complete view layout using a
+simple data specification (XML or other format).&nbsp; Still further, a
+feature to build on this, should allow users to modify the view layout
+using GUI tools and to apply the modified layout at runtime.<br>
+<p><br>
+</p>
+</body>
+</html>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IElementPropertiesProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IElementPropertiesProvider.java
new file mode 100644
index 00000000000..3aa62cc54eb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IElementPropertiesProvider.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+
+/**
+ * Provides context-sensitive properties. Can be registered as an adapter for
+ * an element or implemented directly
+ */
+public interface IElementPropertiesProvider {
+
+ /**
+ * Updates the specified property sets.
+ *
+ * @param updates each update specifies the element and context for which
+ * a set of properties is requested and stores them
+ */
+ public void update(IPropertiesUpdate[] updates);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/ILabelAttributeChangedListener.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/ILabelAttributeChangedListener.java
new file mode 100644
index 00000000000..fecec2e4ea1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/ILabelAttributeChangedListener.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+/**
+ *
+ */
+public interface ILabelAttributeChangedListener {
+
+ public void attributesChanged();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java
new file mode 100644
index 00000000000..6657c7d5499
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/IPropertiesUpdate.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+/**
+ * Context sensitive properties update request for an element.
+ */
+@SuppressWarnings("restriction")
+public interface IPropertiesUpdate extends IViewerUpdate {
+ /**
+ * Returns the list of element properties that the provider should set.
+ * If <code>null</code>, all available properties should be set.
+ */
+ public String[] getProperties();
+
+ /**
+ * Sets the given property to update.
+ * @param property Property ID.
+ * @param value Property value.
+ */
+ public void setProperty(String property, Object value);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelAttribute.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelAttribute.java
new file mode 100644
index 00000000000..4b98d28e81a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelAttribute.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+/**
+ * This is a base class for a label attribute used in generating label
+ * information based on properties of an element. There are currently
+ * four types of attributes: text, image, font, and color, and a given
+ * attribute can be either enabled or disabled based on the element
+ * properties.
+ * <p/>
+ * Clients are intended to override this class and its extensions to
+ * implement the {@link LabelAttribute#isEnabled(Map)} and
+ * {@link LabelAttribute#getPropertyNames()} methods as needed. Clients can
+ * also override how the attribute settings are stored, for example in
+ * order to use a preference.
+ *
+ * @see PropertyBasedLabelProvider
+ * @see LabelColumnInfo
+ */
+@SuppressWarnings("restriction")
+abstract public class LabelAttribute {
+ public static final String[] EMPTY_PROPERTY_NAMES_ARRAY = new String[0];
+
+ /**
+ * Listeners for when this attribute is modified.
+ */
+ private ListenerList fListeners = new ListenerList();
+
+ public LabelAttribute() {
+ }
+
+ /**
+ * Disposes this attribute.
+ */
+ public void dispose() {
+ }
+
+ /**
+ * Registers the given listener for changes in this attribute. A change in
+ * the attributes of a label should cause a view to repaint.
+ * @param listener Listener to register.
+ */
+ public void addChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.add(listener);
+ }
+
+ /**
+ * Unregisters the given listener.
+ * @param listener Listener to unregister.
+ */
+ public void removeChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.remove(listener);
+ }
+
+ /**
+ * Calls the listeners to notify them that this attribute has changed.
+ */
+ protected void fireAttributeChanged() {
+ Object[] listeners = fListeners.getListeners();
+ for (Object listener : listeners) {
+ ((ILabelAttributeChangedListener)listener).attributesChanged();
+ }
+ }
+
+ /**
+ * Returns the propertis that are needed by this attribute in order to
+ * determine whether this attribute is enabled and/or for the actual
+ * attribute itself.
+ * @return Array of names of properties for the element properties provider.
+ */
+ public String[] getPropertyNames() {
+ return EMPTY_PROPERTY_NAMES_ARRAY;
+ }
+
+ /**
+ * Returns whether this attribute is enabled for an element which has
+ * the given properties.
+ * @param properties Map or element properties. The client should ensure
+ * that all properties specified by {@link #getPropertyNames()} are
+ * supplied in this map.
+ * @return true if this attribute is enabled.
+ */
+ public boolean isEnabled(Map<String, Object> properties) {
+ return true;
+ }
+
+ /**
+ * Updates the label with this attribute.
+ *
+ * @param update Label update object to write to.
+ * @param columnIndex Colum index to write at.
+ * @param properties Element properties to use.
+ */
+ abstract public void updateAttribute(ILabelUpdate update, int columnIndex, Map<String, Object> properties);
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColor.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColor.java
new file mode 100644
index 00000000000..ef09f7814b6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColor.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.Map;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.swt.graphics.RGB;
+
+/**
+ * The color attribute of a label. It determines what foreground and
+ * background color to use for the given label.
+ *
+ * @see LabelAttribute
+ * @see LabelColumnInfo
+ * @see PropertyBasedLabelProvider
+ */
+
+@SuppressWarnings("restriction")
+public class LabelColor extends LabelAttribute {
+ private RGB fForeground;
+ private RGB fBackground;
+
+ public LabelColor() {
+ this(null, null);
+ }
+
+ public LabelColor(RGB foreground, RGB background) {
+ fForeground = foreground;
+ fBackground = background;
+ }
+
+ public RGB getForeground() {
+ return fForeground;
+ }
+
+ public RGB getBackground() {
+ return fBackground;
+ }
+
+ public void setForeground(RGB foreground) {
+ fForeground = foreground;
+ fireAttributeChanged();
+ }
+
+ public void setBackground(RGB background) {
+ fBackground = background;
+ fireAttributeChanged();
+ }
+
+ @Override
+ public void updateAttribute(ILabelUpdate update, int columnIndex, Map<String, Object> properties) {
+ RGB foreground = getForeground();
+ if (foreground != null) {
+ update.setForeground(foreground, columnIndex);
+ }
+
+ RGB background = getBackground();
+ if (background != null) {
+ update.setBackground(background, columnIndex);
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColumnInfo.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColumnInfo.java
new file mode 100644
index 00000000000..f058385178f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelColumnInfo.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+/**
+ * Class used by the PropertyBasedLabelProvider to generate store
+ * label attributes related to a single column. Each column info is
+ * configured with an array of attributes (there are currently four
+ * types of attributes: text, image, font, and color), which are
+ * evaluated in order to generate the label.
+ * <p/>
+ * Clients are not intended to extend this class.
+ *
+ * @see PropertyBasedLabelProvider
+ */
+@SuppressWarnings("restriction")
+@ThreadSafe
+public class LabelColumnInfo implements ILabelAttributeChangedListener {
+
+ private static final LabelAttribute[] EMPTY_ATTRIBUTES_ARRAY = new LabelAttribute[0];
+
+ /**
+ * Calculated list of property names that need to be retrieved to
+ * generate the label for this column.
+ */
+ private String[] fPropertyNames;
+
+ /**
+ * Array of label attribute objects.
+ */
+ private LabelAttribute[] fLabelAttributes;
+
+ /**
+ * Listeners for when column attributes are modified.
+ */
+ private ListenerList fListeners = new ListenerList();
+
+ /**
+ * Creates the column info object with given array of attributes.
+ * @param attributeInfos Attributes for the label.
+ */
+ public LabelColumnInfo(LabelAttribute[] attributes)
+ {
+ fLabelAttributes = attributes;
+
+ List<String> names = new LinkedList<String>();
+ for (LabelAttribute attr : attributes) {
+ attr.addChangedListener(this);
+ for (String name : attr.getPropertyNames()) {
+ names.add(name);
+ }
+ }
+
+ fPropertyNames = names.toArray(new String[names.size()]);
+ }
+
+ /**
+ * Disposes this column info object and the attribute objects
+ * within it.
+ */
+ public void dispose() {
+ for (LabelAttribute attr : fLabelAttributes) {
+ attr.dispose();
+ attr.removeChangedListener(this);
+ }
+ fLabelAttributes = EMPTY_ATTRIBUTES_ARRAY;
+ fPropertyNames = null;
+ }
+
+ /**
+ * Returns the property names that need to be retrieved in order
+ * to generate the label for this column.
+ */
+ public String[] getPropertyNames() { return fPropertyNames; }
+
+ /**
+ * Returns the list of configured label attributes for this column.
+ */
+ public LabelAttribute[] getLabelAttributes() { return fLabelAttributes; }
+
+ /**
+ * Registers the given listener for changes in the attributes of this
+ * column. A change in the attributes of a label should cause
+ * a view to repaint.
+ * @param listener Listener to register.
+ */
+ public void addChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.add(listener);
+ }
+
+ /**
+ * Unregisters the given listener.
+ * @param listener Listener to unregister.
+ */
+ public void removeChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.remove(listener);
+ }
+
+ /**
+ * Listener method called by the attribute objects.
+ * @see ILabelAttributeChangedListener
+ */
+ public void attributesChanged() {
+ Object[] listeners = fListeners.getListeners();
+ for (Object listener : listeners) {
+ ((ILabelAttributeChangedListener)listener).attributesChanged();
+ }
+ }
+
+ /**
+ * Updates the label parameters for this column based on the provided
+ * properties. The label information is written to the givne label
+ * update under the given column index.
+ * @param update Update to write to.
+ * @param columnIndex Column to write label information under.
+ * @param properties Map of properties to use to generate the label.
+ */
+ public void updateColumn(ILabelUpdate update, int columnIndex, Map<String,Object> properties) {
+ boolean textSet = false;
+ boolean imageSet = false;
+ boolean fontSet = false;
+ boolean colorSet = false;
+
+ LabelAttribute[] labelAttributes = getLabelAttributes();
+ for (LabelAttribute info : labelAttributes) {
+
+ if (!(info instanceof LabelText && textSet) &&
+ !(info instanceof LabelImage && imageSet) &&
+ !(info instanceof LabelFont && fontSet) &&
+ !(info instanceof LabelColor && colorSet) &&
+ info.isEnabled(properties))
+ {
+ info.updateAttribute(update, columnIndex, properties);
+
+ textSet = textSet || info instanceof LabelText;
+ imageSet = imageSet || info instanceof LabelImage;
+ fontSet = fontSet || info instanceof LabelFont;
+ colorSet = colorSet || info instanceof LabelColor;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelFont.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelFont.java
new file mode 100644
index 00000000000..e4eef88041e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelFont.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.Map;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.graphics.FontData;
+
+/**
+ * The font attribute of a label.
+ *
+ * @see LabelAttribute
+ * @see LabelColumnInfo
+ * @see PropertyBasedLabelProvider
+ */
+@SuppressWarnings("restriction")
+public class LabelFont extends LabelAttribute {
+ private static final FontData DEFAULT_FONT = JFaceResources.getDefaultFontDescriptor().getFontData()[0];
+
+ /**
+ * The font data of this attribute.
+ */
+ private FontData fFontData;
+
+ public LabelFont() {
+ this(DEFAULT_FONT);
+ }
+
+ public LabelFont(FontData fontData) {
+ fFontData = fontData;
+ }
+
+ public FontData getFontData() {
+ return fFontData;
+ }
+
+ public void setFontData(FontData fontData) {
+ fFontData = fontData;
+ fireAttributeChanged();
+ }
+
+ @Override
+ public void updateAttribute(ILabelUpdate update, int columnIndex, Map<String, Object> properties) {
+ update.setFontData(getFontData(), columnIndex);
+ }
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelImage.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelImage.java
new file mode 100644
index 00000000000..797031d14e0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelImage.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.Map;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ * The image attribute of a label.
+ *
+ * @see LabelAttribute
+ * @see LabelColumnInfo
+ * @see PropertyBasedLabelProvider
+ */
+@SuppressWarnings("restriction")
+public class LabelImage extends LabelAttribute {
+ private ImageDescriptor fImageDescriptor;
+
+ public LabelImage() {
+ this(null);
+ }
+
+ public LabelImage(ImageDescriptor image) {
+ fImageDescriptor = image;
+ }
+
+ public ImageDescriptor getImageDescriptor() {
+ return fImageDescriptor;
+ }
+
+ public void setImageDescriptor(ImageDescriptor image) {
+ fImageDescriptor = image;
+ fireAttributeChanged();
+ }
+
+ @Override
+ public void updateAttribute(ILabelUpdate update, int columnIndex, Map<String, Object> properties) {
+ ImageDescriptor descriptor = getImageDescriptor();
+ if (descriptor != null) {
+ update.setImageDescriptor(descriptor, columnIndex);
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelText.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelText.java
new file mode 100644
index 00000000000..534000f21bc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/LabelText.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.text.MessageFormat;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+/**
+ * The text attribute of a label. It uses a message format string in order to
+ * compose the text string. The parameter names determine the array of objects
+ * given to the message format.
+ *
+ * @see MessageFormat#format(Object[], StringBuffer, java.text.FieldPosition)
+ * @see LabelAttribute
+ * @see LabelColumnInfo
+ * @see PropertyBasedLabelProvider
+ */
+@SuppressWarnings("restriction")
+public class LabelText extends LabelAttribute {
+
+ public static final MessageFormat DEFAULT_MESSAGE = new MessageFormat(MessagesForProperties.DefaultLabelMessage_label);
+
+ /**
+ * Message format used to generate the label text.
+ *
+ */
+ private MessageFormat fMessageFormat;
+
+ /**
+ * The property names needed for the message format. The property values
+ * corresponding to these names are given the the {@link MessageFormat#format(Object[], StringBuffer, java.text.FieldPosition)}
+ * method.
+ */
+ private String[] fPropertyNames;
+
+ public LabelText() {
+ this(DEFAULT_MESSAGE, EMPTY_PROPERTY_NAMES_ARRAY);
+ }
+
+ public LabelText(MessageFormat format, String[] propertyNames) {
+ fMessageFormat = format;
+ fPropertyNames = propertyNames;
+ }
+
+ @Override
+ public String[] getPropertyNames() {
+ return fPropertyNames;
+ }
+
+ public MessageFormat getMessageFormat() {
+ return fMessageFormat;
+ }
+
+ public void setMessageFormat(MessageFormat messageFormat) {
+ fMessageFormat = messageFormat;
+ fireAttributeChanged();
+ }
+
+ @Override
+ public void updateAttribute(ILabelUpdate update, int columnIndex, Map<String, Object> properties) {
+ String[] propertyNames = getPropertyNames();
+ Object[] propertyValues = new Object[propertyNames.length];
+ for (int i = 0; i < propertyNames.length; i++) {
+ propertyValues[i] = properties.get(propertyNames[i]);
+ }
+
+ try {
+ update.setLabel(getMessageFormat().format(propertyValues, new StringBuffer(), null).toString(), columnIndex);
+ } catch (IllegalArgumentException e) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, 0, "Failed formatting a message for column " + columnIndex + ", for update " + update, e)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java
new file mode 100644
index 00000000000..35e5688db8c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/MessagesForProperties.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import org.eclipse.osgi.util.NLS;
+
+class MessagesForProperties extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.ui.viewmodel.properties.messages"; //$NON-NLS-1$
+
+ public static String DefaultLabelMessage_label;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, MessagesForProperties.class);
+ }
+
+ private MessagesForProperties() {
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertyBasedLabelProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertyBasedLabelProvider.java
new file mode 100644
index 00000000000..8865d9bedcd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/PropertyBasedLabelProvider.java
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.properties;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMViewerUpdate;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+/**
+ * A configurable label provider which uses element's property label provider
+ * to set element's label attributes.
+ * <p>
+ * When this provider is registered for an element it calculates the properties
+ * that need to be retrieved based on view's active columns, and then it calls the
+ * element's property provider to retrieve those properties. After the property
+ * values are retrieved, they are processed in order to produce correct label text,
+ * images, fonts, and colors, for the given element.
+ */
+@SuppressWarnings("restriction")
+@ThreadSafe
+public class PropertyBasedLabelProvider
+ implements IElementLabelProvider, ILabelAttributeChangedListener
+{
+ private static final String[] EMPTY_PROPERTY_NAMES_ARRAY = new String[0];
+
+ /**
+ * Properties update used as to collect property data from the provider.
+ */
+ private class PropertiesUpdate extends VMViewerUpdate implements IPropertiesUpdate {
+
+ private final String[] fProperties;
+ private final Map<String, Object> fValues;
+
+ public PropertiesUpdate(String[] properties, ILabelUpdate labelUpdate, DataRequestMonitor<Map<String,Object>> rm) {
+ super(labelUpdate, rm);
+ fProperties = properties;
+ fValues = fProperties != null
+ ? new HashMap<String, Object>(properties.length * 4 / 3, 0.75f)
+ : new HashMap<String, Object>();
+ }
+
+ public String[] getProperties() {
+ return fProperties;
+ }
+
+ public void setProperty(String property, Object value) {
+ fValues.put(property, value);
+ }
+
+ /**
+ * Overrides the standard done in order to store the retrieved values
+ * in the client's request monitor.
+ */
+ @Override
+ public void done() {
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<Map<String,Object>> rm = (DataRequestMonitor<Map<String,Object>>)getRequestMonitor();
+ if (fProperties == null || fValues.size() >= fProperties.length) {
+ rm.setData(fValues);
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.REQUEST_FAILED, "Incomplete properties updated", null)); //$NON-NLS-1$
+ }
+ super.done();
+ }
+ }
+
+ /**
+ * Attribute information for each column by column ID.
+ */
+ private Map<String, LabelColumnInfo> fColumnInfos = Collections.synchronizedMap(new HashMap<String,LabelColumnInfo>());
+
+ private ListenerList fListeners = new ListenerList();
+
+ /**
+ * Standard constructor. A property based label constructor does not
+ * initialize column attribute information {@link #setColumnInfo(String, LabelColumnInfo)}
+ * must be called to configure each column.
+ */
+ public PropertyBasedLabelProvider() {
+ }
+
+ /**
+ * Disposes this label provider and its configured column info objects.
+ */
+ public void dispose() {
+ LabelColumnInfo[] infos = null;
+ synchronized (fColumnInfos) {
+ infos = fColumnInfos.values().toArray(new LabelColumnInfo[fColumnInfos.size()]);
+ fColumnInfos.clear();
+ }
+ for (LabelColumnInfo info : infos) {
+ info.dispose();
+ }
+ }
+
+ /**
+ * Sets the given column info object for the given column ID. This column
+ * info will be used to generate the label when the given column is visibile.
+ * @param columnId Column ID that the given column info is being registered for.
+ * @param info Column 'info' object containing column attributes.
+ * @return The previous column info object configured for this ID.
+ */
+ public LabelColumnInfo setColumnInfo(String columnId, LabelColumnInfo info) {
+ LabelColumnInfo oldInfo = fColumnInfos.put(columnId, info);
+ info.addChangedListener(this);
+ if (oldInfo != null) {
+ info.removeChangedListener(this);
+ }
+ return oldInfo;
+ }
+
+ /**
+ * Returns the given column info object for the given column ID.
+ * @param columnId Column ID to retrieve the column info for.
+ * @@return Column 'info' object containing column attributes.
+ */
+ public LabelColumnInfo getColumnInfo(String column) {
+ return fColumnInfos.get(column);
+ }
+
+ /**
+ * Registers the given listener for changes in the attributes of this
+ * label provider. A change in the attributes of a label should cause
+ * a view to repaint.
+ * @param listener Listener to register.
+ */
+ public void addChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.add(listener);
+ }
+
+ /**
+ * Unregisters the given listener.
+ * @param listener Listener to unregister.
+ */
+ public void removeChangedListener(ILabelAttributeChangedListener listener) {
+ fListeners.remove(listener);
+ }
+
+ /**
+ * Listener method called by label provider's column info objects.
+ * @see ILabelAttributeChangedListener
+ */
+ public void attributesChanged() {
+ Object[] listeners = fListeners.getListeners();
+ for (Object listener : listeners) {
+ ((ILabelAttributeChangedListener)listener).attributesChanged();
+ }
+ }
+
+ public void update(ILabelUpdate[] labelUpdates) {
+ IElementPropertiesProvider propertiesProvider = getElementPropertiesProvider(labelUpdates[0].getElement());
+ if (propertiesProvider == null) {
+ for (ILabelUpdate update : labelUpdates) {
+ update.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, "Properties-based label provider " + this + " failed to generate a label, no properties provider registered for element: " + labelUpdates[0].getElement())); //$NON-NLS-1$ //$NON-NLS-2$
+ update.done();
+ }
+ return;
+ }
+
+ String[] columnIds = labelUpdates[0].getColumnIds();
+ String[] propertyNames = calcPropertyNamesForColumns(columnIds);
+
+ // Call the properties provider. Create a request monitor for each label update.
+ // We can use an immediate executor for the request monitor because the label provider
+ // is thread safe.
+ IPropertiesUpdate[] propertiesUpdates = new IPropertiesUpdate[labelUpdates.length];
+ for (int i = 0; i < labelUpdates.length; i++) {
+ final ILabelUpdate labelUpdate = labelUpdates[i];
+ propertiesUpdates[i] = new PropertiesUpdate(
+ propertyNames, labelUpdates[i],
+ new ViewerDataRequestMonitor<Map<String, Object>>(ImmediateExecutor.getInstance(), labelUpdates[i]) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ updateLabel(labelUpdate, getData());
+ }
+ labelUpdate.done();
+ }
+ });
+ }
+ propertiesProvider.update(propertiesUpdates);
+ }
+
+ /**
+ * Calculates the names of properties that have to be retrieved from the property
+ * provider to generate the labels for given columns.
+ * @param columnIds Column IDs to check.
+ * @return Array of property names.
+ */
+ private String[] calcPropertyNamesForColumns(String[] columnIds) {
+ if (columnIds == null) {
+ LabelColumnInfo columnInfo = getColumnInfo(null);
+ if (columnInfo != null) {
+ return columnInfo.getPropertyNames();
+ } else {
+ return EMPTY_PROPERTY_NAMES_ARRAY;
+ }
+ } else {
+ List<String> properties = new LinkedList<String>();
+ for (String columnId : columnIds) {
+ LabelColumnInfo info = getColumnInfo(columnId);
+ if (info != null) {
+ String[] infoPropertyNames = info.getPropertyNames();
+ for (int i = 0; i < infoPropertyNames.length; i++) {
+ properties.add(infoPropertyNames[i]);
+ }
+ }
+ }
+ return properties.toArray(new String[properties.size()]);
+ }
+ }
+
+ /**
+ * Updates the label information based on given map of properties.
+ * @param update Label update to write to.
+ * @param properties Properties retrieved from the element properties provider.
+ */
+ protected void updateLabel(ILabelUpdate update, Map<String,Object> properties) {
+ if (update.getColumnIds() == null) {
+ LabelColumnInfo info = getColumnInfo(null);
+ if (info != null) {
+ info.updateColumn(update, 0, properties);
+ }
+ } else {
+ String[] columnIds = update.getColumnIds();
+
+ for (int i = 0; i < columnIds.length; i++) {
+ LabelColumnInfo info = getColumnInfo(columnIds[i]);
+ if (info != null) {
+ info.updateColumn(update, i, properties);
+ }
+ }
+ }
+
+ update.done();
+ }
+
+ private IElementPropertiesProvider getElementPropertiesProvider(Object element) {
+ if (element instanceof IAdaptable) {
+ return (IElementPropertiesProvider)((IAdaptable)element).getAdapter(IElementPropertiesProvider.class);
+ }
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/messages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/messages.properties
new file mode 100644
index 00000000000..6e78cb987b1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/properties/messages.properties
@@ -0,0 +1,11 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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
+###############################################################################
+DefaultLabelMessage_label=<unknown>
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java
new file mode 100644
index 00000000000..632a1dc2607
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java
@@ -0,0 +1,1090 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.concurrent.SimpleDisplayExecutor;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerCountingRequestMonitor;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxy;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxyExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenCountUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMHasChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+/**
+ * Base implementation of a caching view model provider.
+ */
+@SuppressWarnings("restriction")
+public class AbstractCachingVMProvider extends AbstractVMProvider implements ICachingVMProvider, ICachingVMProviderExtension {
+
+ private boolean fDelayEventHandleForViewUpdate = false;
+
+ // debug flag
+ static boolean DEBUG_CACHE = false;
+
+ static {
+ DEBUG_CACHE = DsfUIPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/vm/cache")); //$NON-NLS-1$
+ }
+
+ private static final int MAX_CACHE_SIZE = 1000;
+
+ /**
+ * Class representing a key to an element's data in the cache. The main
+ * components of this key are the viewer input and the path, they uniquely
+ * identify an element. The root element is used to track when a given
+ * root element is no longer in the cache and can therefore be disposed.
+ * The node is needed because different nodes have different lists of
+ * children for the same parent element.
+ */
+ private static class ElementDataKey {
+ ElementDataKey(Object rootElement, IVMNode node, Object viewerInput, TreePath path) {
+ fRootElement = rootElement;
+ fNode = node;
+ fViewerInput = viewerInput;
+ fPath = path;
+ }
+
+ final Object fRootElement;
+ final IVMNode fNode;
+ final Object fViewerInput;
+ final TreePath fPath;
+
+ @Override
+ public String toString() {
+ return fNode.toString() + " " + //$NON-NLS-1$
+ (fPath.getSegmentCount() == 0 ? fViewerInput.toString() : fPath.getLastSegment().toString());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ElementDataKey)) return false;
+ ElementDataKey key = (ElementDataKey)obj;
+ return
+ (fNode == null && key.fNode == null || (fNode != null && fNode.equals(key.fNode))) &&
+ (fRootElement == null && key.fRootElement == null || (fRootElement != null && fRootElement.equals(key.fRootElement))) &&
+ (fViewerInput == null && key.fViewerInput == null || (fViewerInput != null && fViewerInput.equals(key.fViewerInput))) &&
+ (fPath == null && key.fPath == null || (fPath != null && fPath.equals(key.fPath)));
+ }
+
+ @Override
+ public int hashCode() {
+ return
+ (fRootElement != null ? fRootElement.hashCode() : 0) +
+ (fNode != null ? fNode.hashCode() : 0) +
+ (fViewerInput != null ? fViewerInput.hashCode() : 0) +
+ (fPath != null ? fPath.hashCode() : 0);
+ }
+ }
+
+ /**
+ * A base class for the entry in the cache. Since the cache maintains
+ * a double-linked list through all the entries, the linked list references
+ * are maintained in this class.
+ */
+ private static class Entry {
+ final Object fKey;
+
+ Entry fNext;
+ Entry fPrevious;
+
+ Entry(Object key) {
+ fKey = key;
+ }
+
+ void insert(Entry nextEntry) {
+ fNext = nextEntry;
+ fPrevious = nextEntry.fPrevious;
+ fPrevious.fNext = this;
+ fNext.fPrevious = this;
+ }
+
+ void remove() {
+ fPrevious.fNext = fNext;
+ fNext.fPrevious = fPrevious;
+ }
+
+ void reinsert(Entry nextEntry) {
+ fPrevious.fNext = fNext;
+ fNext.fPrevious = fPrevious;
+
+ fNext = nextEntry;
+ fPrevious = nextEntry.fPrevious;
+ fPrevious.fNext = this;
+ fNext.fPrevious = this;
+ }
+ }
+
+ /**
+ * Entry with cached element data.
+ */
+ static class ElementDataEntry extends Entry {
+ ElementDataEntry(ElementDataKey key) {
+ super(key);
+ }
+
+ /**
+ * Counter of flush operations performed on this entry. It is used
+ * by caching update operations to make sure that an update which
+ * was issued for a given entry is still valid for that entry when
+ * it is completed by the node.
+ */
+ int fFlushCounter = 0;
+
+ /**
+ * Indicates that the data in this cache entry is out of date with
+ * the data on the target.
+ */
+ Boolean fDirty = false;
+
+ /**
+ * Cached {@link IHasChildrenUpdate} result.
+ */
+ Boolean fHasChildren = null;
+
+ /**
+ * Cached {@link IChildrenCountUpdate} result.
+ */
+ Integer fChildrenCount = null;
+
+ /**
+ * Flag indicating that all the children of the given element are
+ * alredy cached.
+ */
+ boolean fAllChildrenKnown = false;
+
+ /**
+ * Map containing children of this element, keyed by child index.
+ */
+ Map<Integer,Object> fChildren = null;
+
+ /**
+ * Map of IDMData objects, keyed by the DM context.
+ */
+ Map<IDMContext,Object> fDataOrStatus = new HashMap<IDMContext,Object>(1);
+
+ /**
+ * Previous known value of the DM data objects.
+ */
+ Map<IDMContext,IDMData> fArchiveData = new HashMap<IDMContext,IDMData>(1);;
+
+ void ensureChildrenMap() {
+ if (fChildren == null) {
+ Integer childrenCount = fChildrenCount;
+ childrenCount = childrenCount != null ? childrenCount : 0;
+ int capacity = Math.max((childrenCount.intValue() * 4)/3, 32);
+ fChildren = new HashMap<Integer,Object>(capacity);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return fKey.toString() + " = " + //$NON-NLS-1$
+ "[hasChildren=" + fHasChildren + ", " +//$NON-NLS-1$ //$NON-NLS-2$
+ "childrenCount=" + fChildrenCount + //$NON-NLS-1$
+ ", children=" + fChildren + //$NON-NLS-1$
+ ", data/status=" + fDataOrStatus + //$NON-NLS-1$
+ ", oldData=" + fArchiveData + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * A key for a special marker entry in the cache. This marker entry is used
+ * to optimize repeated flushing of the cache.
+ * @see AbstractCachingVMProvider#flush(List)
+ */
+ private static class FlushMarkerKey {
+ private Object fRootElement;
+ private IElementUpdateTester fElementTester;
+
+ FlushMarkerKey(Object rootElement, IElementUpdateTester pathTester) {
+ fRootElement = rootElement;
+ fElementTester = pathTester;
+ }
+
+ boolean includes(FlushMarkerKey key) {
+ return fRootElement.equals(key.fRootElement) &&
+ fElementTester.includes(key.fElementTester);
+ }
+
+ int getUpdateFlags(ElementDataKey key) {
+ if (fRootElement.equals(key.fRootElement)) {
+ return fElementTester.getUpdateFlags(key.fViewerInput, key.fPath);
+ }
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return fElementTester.toString() + " " + fRootElement.toString(); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Marker used to keep track of whether any entries with the given
+ * root element are present in the cache.
+ */
+ private static class RootElementMarkerKey {
+
+ private Object fRootElement;
+
+ RootElementMarkerKey(Object rootElement) {
+ fRootElement = rootElement;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof RootElementMarkerKey && ((RootElementMarkerKey)obj).fRootElement.equals(fRootElement);
+ }
+
+ @Override
+ public int hashCode() {
+ return fRootElement.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return fRootElement.toString();
+ }
+ }
+
+ class RootElementMarkerEntry extends Entry {
+ RootElementMarkerEntry(RootElementMarkerKey key) {
+ super(key);
+ }
+
+ @Override
+ void remove() {
+ super.remove();
+ rootElementRemovedFromCache(((RootElementMarkerKey)fKey).fRootElement);
+ }
+
+ @Override
+ public String toString() {
+ return "ROOT MARKER " + fKey; //$NON-NLS-1$
+ }
+ }
+
+ protected static String SELECTED_UPDATE_MODE = "org.eclipse.cdt.dsf.ui.viewmodel.update.selectedUpdateMode"; //$NON-NLS-1$
+ /**
+ * @since 1.1
+ */
+ protected static String SELECTED_UPDATE_SCOPE = "org.eclipse.cdt.dsf.ui.viewmodel.update.selectedUpdateScope"; //$NON-NLS-1$
+
+ private IVMUpdatePolicy[] fAvailableUpdatePolicies;
+ private IVMUpdateScope[] fAvailableUpdateScopes;
+
+ public Map<Object, RootElementMarkerKey> fRootMarkers = new HashMap<Object, RootElementMarkerKey>();
+
+ /**
+ * Hash map holding cache data. To store the cache information, the cache uses a
+ * combination of this hash map and a double-linked list running through all
+ * the entries in the cache. The linked list is used to organize the cache entries
+ * in least recently used (LRU) order. This ordering is then used to delete least
+ * recently used entries in the cache and keep the cache from growing indefinitely.
+ * Also, the ordering is used to optimize the flushing of the cache data (see
+ * {@link FlushMarkerKey} for more details).
+ */
+ private final Map<Object, Entry> fCacheData = Collections.synchronizedMap(new HashMap<Object, Entry>(200, 0.75f));
+
+ /**
+ * Pointer to the first cache entry in the double-linked list of cache entries.
+ */
+ private final Entry fCacheListHead;
+
+
+ public AbstractCachingVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
+ super(adapter, presentationContext);
+
+ fCacheListHead = new Entry(null) {
+ @Override
+ public String toString() {
+ return "HEAD"; //$NON-NLS-1$
+ }
+ };
+ fCacheListHead.fNext = fCacheListHead;
+ fCacheListHead.fPrevious = fCacheListHead;
+
+ fAvailableUpdatePolicies = createUpdateModes();
+
+ fAvailableUpdateScopes = createUpdateScopes();
+ setActiveUpdateScope(new VisibleUpdateScope());
+ }
+
+ protected IVMUpdatePolicy[] createUpdateModes() {
+ return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy() };
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected IVMUpdateScope[] createUpdateScopes() {
+ return new IVMUpdateScope[] { new VisibleUpdateScope(), new AllUpdateScope() };
+ }
+
+ public IVMUpdatePolicy[] getAvailableUpdatePolicies() {
+ return fAvailableUpdatePolicies;
+ }
+
+ public IVMUpdatePolicy getActiveUpdatePolicy() {
+ String updateModeId = (String)getPresentationContext().getProperty(SELECTED_UPDATE_MODE);
+ if (updateModeId != null) {
+ for (IVMUpdatePolicy updateMode : getAvailableUpdatePolicies()) {
+ if (updateMode.getID().equals(updateModeId)) {
+ return updateMode;
+ }
+ }
+ }
+
+ // Default to the first one.
+ return getAvailableUpdatePolicies()[0];
+ }
+
+ public void setActiveUpdatePolicy(IVMUpdatePolicy updatePolicy) {
+ getPresentationContext().setProperty(SELECTED_UPDATE_MODE, updatePolicy.getID());
+ }
+
+ public void refresh() {
+ IElementUpdateTester elementTester = getActiveUpdatePolicy().getElementUpdateTester(ManualUpdatePolicy.REFRESH_EVENT);
+
+ for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
+ flush(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
+ }
+
+ for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) {
+ if (!proxyStrategy.isDisposed()) {
+ proxyStrategy.fireModelChanged(new ModelDelta(proxyStrategy.getRootElement(), IModelDelta.CONTENT));
+ }
+ }
+ }
+
+ @Override
+ public void updateNode(final IVMNode node, IHasChildrenUpdate[] updates) {
+ LinkedList <IHasChildrenUpdate> missUpdates = new LinkedList<IHasChildrenUpdate>();
+ for(final IHasChildrenUpdate update : updates) {
+ // Find or create the cache entry for the element of this update.
+ ElementDataKey key = makeEntryKey(node, update);
+ final ElementDataEntry entry = getElementDataEntry(key);
+
+ if (entry.fHasChildren != null) {
+ // Cache Hit! Just return the value.
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheHitHasChildren(node = " + node + ", update = " + update + ", " + entry.fHasChildren + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ update.setHasChilren(entry.fHasChildren.booleanValue());
+ update.done();
+ } else {
+ // Cache miss! Save the flush counter of the entry and create a proxy update.
+ final int flushCounter = entry.fFlushCounter;
+ missUpdates.add(
+ new VMHasChildrenUpdate(
+ update,
+ new ViewerDataRequestMonitor<Boolean>(getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ // Update completed. Write value to cache only if update successed
+ // and the cache entry wasn't flushed in the mean time.
+ if(isSuccess()) {
+ if (flushCounter == entry.fFlushCounter) {
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheSavedHasChildren(node = " + node + ", update = " + update + ", " + getData() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ entry.fHasChildren = this.getData();
+ }
+ update.setHasChilren(getData());
+ } else {
+ update.setStatus(getStatus());
+ }
+ update.done();
+ }
+ }));
+ }
+ }
+
+ // Issue all the update proxies with one call.
+ if (!missUpdates.isEmpty()) {
+ super.updateNode(node, missUpdates.toArray(new IHasChildrenUpdate[missUpdates.size()]));
+ }
+ }
+
+ @Override
+ public void updateNode(final IVMNode node, final IChildrenCountUpdate update) {
+ // Find or create the cache entry for the element of this update.
+ ElementDataKey key = makeEntryKey(node, update);
+ final ElementDataEntry entry = getElementDataEntry(key);
+
+ if(entry.fChildrenCount != null) {
+ // Cache Hit! Just return the value.
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheHitChildrenCount(node = " + node + ", update = " + update + ", " + entry.fChildrenCount + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ update.setChildCount(entry.fChildrenCount.intValue());
+ update.done();
+ } else {
+ // Cache miss! Save the flush counter of the entry and create a proxy update.
+ final int flushCounter = entry.fFlushCounter;
+ IChildrenCountUpdate updateProxy = new VMChildrenCountUpdate(
+ update,
+ new ViewerDataRequestMonitor<Integer>(getExecutor(), update) {
+ @Override
+ protected void handleCompleted() {
+ // Update completed. Write value to cache only if update successed
+ // and the cache entry wasn't flushed in the mean time.
+ if(isSuccess()) {
+ if (flushCounter == entry.fFlushCounter) {
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheSavedChildrenCount(node = " + node + ", update = " + update + ", " + getData() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+ entry.fChildrenCount = this.getData();
+ }
+ update.setChildCount(getData());
+ } else {
+ update.setStatus(getStatus());
+ }
+ update.done();
+ }
+ });
+ super.updateNode(node, updateProxy);
+ }
+ }
+
+ @Override
+ public void updateNode(final IVMNode node, final IChildrenUpdate update) {
+ // Find or create the cache entry for the element of this update.
+ ElementDataKey key = makeEntryKey(node, update);
+ final ElementDataEntry entry = getElementDataEntry(key);
+
+ final int flushCounter = entry.fFlushCounter;
+ if (entry.fChildren == null || (update.getOffset() < 0 && !entry.fAllChildrenKnown)) {
+ // Need to retrieve all the children if there is no children information yet.
+ // Or if the client requested all children (offset = -1, length -1) and all
+ // the children are not yet known.
+ IChildrenUpdate updateProxy = new VMChildrenUpdate(
+ update, update.getOffset(), update.getLength(),
+ new ViewerDataRequestMonitor<List<Object>>(getExecutor(), update){
+ @Override
+ protected void handleSuccess() {
+ // Check if the update retrieved all children by specifying "offset = -1, length = -1"
+ int updateOffset = update.getOffset();
+ if (updateOffset < 0)
+ {
+ updateOffset = 0;
+ if (entry.fFlushCounter == flushCounter) {
+ entry.fAllChildrenKnown = true;
+ }
+ }
+
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheSavedChildren(node = " + node + ", update = " + update + ", children = {" + updateOffset + "->" + (updateOffset + getData().size()) + "})"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+
+ if (flushCounter == entry.fFlushCounter) {
+ entry.ensureChildrenMap();
+ }
+
+ // Set the children to map and update.
+ for(int j = 0; j < getData().size(); j++) {
+ int offset = updateOffset + j;
+ Object child = getData().get(j);
+ if (child != null) {
+ if (flushCounter == entry.fFlushCounter) {
+ entry.fChildren.put(offset, child);
+ }
+ update.setChild(child, offset);
+ }
+ }
+ update.done();
+ }
+
+ @Override
+ protected void handleCancel() {
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheCanceledChildren(node = " + node + ", update = " + update + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ super.handleCancel();
+ }
+ });
+ super.updateNode(node, updateProxy);
+ } else if (update.getOffset() < 0 ) {
+ // The update requested all children. Fill in all children assuming that
+ // the children array is complete.
+
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheHitChildren(node = " + node + ", update = " + update + ", children = " + entry.fChildren.keySet() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ // The following assert should never fail given the first if statement.
+ assert entry.fAllChildrenKnown;
+
+ // we have all of the children in cache; return from cache
+ for(int position = 0; position < entry.fChildren.size(); position++) {
+ update.setChild(entry.fChildren.get(position), position);
+ }
+ update.done();
+ } else {
+ // Update for a partial list of children was requested.
+ // Iterate through the known children and make a list of missing
+ // indexes.
+ List<Integer> childrenMissingFromCache = new LinkedList<Integer>();
+ for (int i = update.getOffset(); i < update.getOffset() + update.getLength(); i++) {
+ childrenMissingFromCache.add(i);
+ }
+
+ // Write known children from cache into the update.
+ for(Integer position = update.getOffset(); position < update.getOffset() + update.getLength(); position++) {
+ Object child = entry.fChildren.get(position);
+ if (child != null) {
+ update.setChild(entry.fChildren.get(position), position);
+ childrenMissingFromCache.remove(position);
+ }
+ }
+
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cachePartialHitChildren(node = " + node + ", update = " + update + ", missing = " + childrenMissingFromCache + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ if (childrenMissingFromCache.size() > 0) {
+ // Some children were not found in the cache, create separate
+ // proxy updates for the continuous ranges of missing children.
+ List<IChildrenUpdate> partialUpdates = new ArrayList<IChildrenUpdate>(2);
+ final CountingRequestMonitor multiRm = new ViewerCountingRequestMonitor(getExecutor(), update);
+ while(childrenMissingFromCache.size() > 0)
+ {
+ final int offset = childrenMissingFromCache.get(0);
+ childrenMissingFromCache.remove(0);
+ int length = 1;
+ while(childrenMissingFromCache.size() > 0 && childrenMissingFromCache.get(0) == offset + length)
+ {
+ length++;
+ childrenMissingFromCache.remove(0);
+ }
+
+ partialUpdates.add(new VMChildrenUpdate(
+ update, offset, length,
+ new DataRequestMonitor<List<Object>>(getExecutor(), multiRm) {
+ @Override
+ protected void handleSuccess() {
+ // Only save the children to the cahce if the entry wasn't flushed.
+ if (flushCounter == entry.fFlushCounter) {
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cachePartialSaveChildren(node = " + node + ", update = " + update + ", saved = {" + offset + "->" + (offset + getData().size()) + "})"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
+ }
+ entry.ensureChildrenMap();
+ }
+
+ for (int i = 0; i < getData().size(); i++) {
+ if (getData().get(i) != null) {
+ update.setChild(getData().get(i), offset + i);
+ if (flushCounter == entry.fFlushCounter) {
+ // Only save the children to the cahce if the entry wasn't flushed.
+ entry.fChildren.put(offset + i, getData().get(i));
+ }
+ }
+ }
+ multiRm.done();
+ }
+ }));
+ }
+
+ for (IChildrenUpdate partialUpdate : partialUpdates) {
+ super.updateNode(node, partialUpdate);
+ }
+ multiRm.setDoneCount(partialUpdates.size());
+ } else {
+ // All children were found in cache. Compelte the update.
+ update.done();
+ }
+ }
+
+ }
+
+ /**
+ * Flushes the cache with given DMC as the root element.
+ * @param dmcToFlush DM Context which is the root of the flush operation. Entries
+ * for all DMCs that have this DMC as their ancestor will be flushed. If this
+ * parameter is null, then all entries are flushed.
+ * @param archive
+ */
+ private void flush(FlushMarkerKey flushKey) {
+ if (DEBUG_CACHE && (DEBUG_PRESENTATION_ID == null || getPresentationContext().getId().equals(DEBUG_PRESENTATION_ID))) {
+ DsfUIPlugin.debug("cacheFlushing(" + flushKey + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ // For each entry that has the given context as a parent, perform the flush.
+ // Iterate through the cache entries backwards. This means that we will be
+ // iterating in order of most-recently-used to least-recently-used.
+ Entry entry = fCacheListHead.fPrevious;
+ while (entry != fCacheListHead) {
+ if (entry.fKey instanceof FlushMarkerKey) {
+ FlushMarkerKey entryFlushKey = (FlushMarkerKey)entry.fKey;
+ // If the context currently being flushed includes the flush
+ // context in current entry, remove the current entry since it will
+ // be replaced with one at the end of the list.
+ // Use special handling for null contexts, which we treat like it's an
+ // ancestor of all other contexts.
+ if (flushKey.includes(entryFlushKey)) {
+ fCacheData.remove(entryFlushKey);
+ entry.remove();
+ }
+
+ // If the flush context in current entry includes the current context
+ // being flushed, we can stop iterating through the cache entries
+ // now.
+ if (entryFlushKey.includes(flushKey)) {
+ break;
+
+ }
+ }
+ else if (entry instanceof ElementDataEntry) {
+ ElementDataEntry elementDataEntry = (ElementDataEntry)entry;
+ int updateFlags = flushKey.getUpdateFlags((ElementDataKey)elementDataEntry.fKey);
+ if ((updateFlags & IVMUpdatePolicy.FLUSH) != 0) {
+ if ((updateFlags & IVMUpdatePolicy.ARCHIVE) == IVMUpdatePolicy.ARCHIVE) {
+ // We are saving current data for change history, check if the data is valid.
+ // If it valid, save it for archive, if it's not valid old archive data will be used
+ // if there is any. And if there is no old archive data, just remove the cache entry.
+ for (Iterator<Map.Entry<IDMContext, Object>> itr = elementDataEntry.fDataOrStatus.entrySet().iterator();
+ itr.hasNext();)
+ {
+ Map.Entry<IDMContext, Object> dataOrStatusEntry = itr.next();
+ if (dataOrStatusEntry.getValue() instanceof IDMData) {
+ elementDataEntry.fArchiveData.put(dataOrStatusEntry.getKey(), (IDMData)dataOrStatusEntry.getValue());
+ }
+ }
+ elementDataEntry.fDataOrStatus.clear();
+ if (elementDataEntry.fArchiveData.isEmpty()) {
+ fCacheData.remove(entry.fKey);
+ entry.remove();
+ }
+ } else {
+ // We are not changing the archived data. If archive data exists in the entry, leave it.
+ // Otherwise remove the whole entry.
+ if (!elementDataEntry.fArchiveData.isEmpty()) {
+ elementDataEntry.fDataOrStatus.clear();
+ } else {
+ fCacheData.remove(entry.fKey);
+ entry.remove();
+ }
+ }
+ elementDataEntry.fFlushCounter++;
+ elementDataEntry.fHasChildren = null;
+ elementDataEntry.fChildrenCount = null;
+ elementDataEntry.fChildren = null;
+ elementDataEntry.fAllChildrenKnown = false;
+ elementDataEntry.fDirty = false;
+ } else if ((updateFlags & IVMUpdatePolicy.DIRTY) != 0) {
+ elementDataEntry.fDirty = true;
+ }
+ }
+ entry = entry.fPrevious;
+ }
+
+ // Insert a marker for this flush operation.
+ Entry flushMarkerEntry = new Entry(flushKey);
+ fCacheData.put(flushKey, flushMarkerEntry);
+ flushMarkerEntry.insert(fCacheListHead);
+ }
+
+ @Override
+ protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, final RequestMonitor rm) {
+ IElementUpdateTester elementTester = getActiveUpdatePolicy().getElementUpdateTester(event);
+
+ flush(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester));
+
+ if (proxyStrategy instanceof IVMModelProxyExtension) {
+ IVMModelProxyExtension proxyStrategyExtension = (IVMModelProxyExtension)proxyStrategy;
+
+ CountingRequestMonitor multiRm = new CountingRequestMonitor(getExecutor(), rm);
+ super.handleEvent(proxyStrategy, event, multiRm);
+ int rmCount = 1;
+
+ if(fDelayEventHandleForViewUpdate) {
+ if(this.getActiveUpdateScope().getID().equals(AllUpdateScope.ALL_UPDATE_SCOPE_ID)) {
+ new MultiLevelUpdateHandler(getExecutor(), proxyStrategyExtension, getPresentationContext(), this, multiRm).
+ startUpdate();
+ rmCount++;
+ } else if (!proxyStrategy.isDisposed()) {
+ // block updating only the viewport
+ TreeViewer viewer = (TreeViewer) proxyStrategyExtension.getViewer();
+ Tree tree = viewer.getTree();
+ int count = tree.getSize().y / tree.getItemHeight();
+
+ TreeItem topItem = tree.getTopItem();
+ int index = computeTreeIndex(topItem);
+
+ MultiLevelUpdateHandler handler = new MultiLevelUpdateHandler(
+ getExecutor(), proxyStrategyExtension, getPresentationContext(), this, multiRm);
+ handler.setRange(index, index + count);
+ handler.startUpdate();
+ rmCount++;
+ }
+ } else {
+ if(this.getActiveUpdateScope().getID().equals(AllUpdateScope.ALL_UPDATE_SCOPE_ID)) {
+ MultiLevelUpdateHandler handler = new MultiLevelUpdateHandler(
+ getExecutor(), proxyStrategyExtension, getPresentationContext(), this, multiRm);
+ handler.startUpdate();
+ rmCount++;
+ }
+ }
+ multiRm.setDoneCount(rmCount);
+ } else {
+ super.handleEvent(proxyStrategy, event, rm);
+ }
+ }
+
+ private static int computeTreeIndex(TreeItem child) {
+ if (child != null) {
+ if(child.getParentItem() != null) {
+ int previous = 0;
+ int index = child.getParentItem().indexOf(child);
+ while (--index >= 0) {
+ previous += computeTreeExtent(child.getParentItem().getItem(index));
+ }
+ return computeTreeIndex(child.getParentItem()) + previous;
+ } else {
+ int previous = 0;
+ int index = child.getParent().indexOf(child);
+ while (--index >= 0) {
+ previous += computeTreeExtent(child.getParent().getItem(index));
+ }
+ return previous;
+ }
+ }
+ return 0;
+ }
+
+ private static int computeTreeExtent(TreeItem item) {
+ int extent = 1;
+ if (item.getExpanded()) {
+ for (TreeItem i : item.getItems()) {
+ extent += computeTreeExtent(i);
+ }
+ }
+ return extent;
+ }
+
+ /**
+ * Override default implementation to avoid automatically removing disposed proxies from
+ * list of active proxies. The caching provider only removes a proxy after its root element
+ * is no longer in the cache.
+ */
+ @Override
+ public IModelProxy createModelProxy(Object element, IPresentationContext context) {
+ // Iterate through the current active proxies to try to find a proxy with the same
+ // element and re-use it if found. At the same time purge proxies that are no longer
+ IVMModelProxy proxy = null;
+ for (Iterator<IVMModelProxy> itr = getActiveModelProxies().iterator(); itr.hasNext();) {
+ IVMModelProxy next = itr.next();
+ if (next != null && next.getRootElement().equals(element)) {
+ proxy = next;
+ break;
+ }
+ }
+ if (proxy == null) {
+ proxy = createModelProxyStrategy(element);
+ getActiveModelProxies().add(proxy);
+ } else if (proxy.isDisposed()) {
+ // DSF is capable of re-using old proxies which were previously
+ // disposed. However, the viewer which installs a proxy using
+ // a background job to install the proxy calls
+ // IModelProxy.isDisposed(), to check whether the proxy was disposed
+ // before it could be installed. We need to clear the disposed flag
+ // of the re-used proxy here, otherwise the proxy will never get used.
+ // Calling init here will cause the init() method to be called twice
+ // so the IVMModelProxy needs to be prepared for that.
+ // See bug 241024.
+ proxy.init(context);
+ }
+ return proxy;
+ }
+
+ /**
+ * Called when a given all cache entries for the given root element have
+ * been removed from the cache. In order to property track changed elements,
+ * the caching VM provider does not immediately remove entries for a given root
+ * element, when the viewer root element changes. Instead it keeps this root
+ * element and keeps processing deltas for that root element until the
+ * cache entries for this element are gone.
+ */
+ protected void rootElementRemovedFromCache(Object rootElement) {
+ fRootMarkers.remove(rootElement);
+
+ for (Iterator<IVMModelProxy> proxiesItr = getActiveModelProxies().iterator(); proxiesItr.hasNext();) {
+ IVMModelProxy proxy = proxiesItr.next();
+ if (proxy.isDisposed() && proxy.getRootElement().equals(rootElement) ) {
+ proxiesItr.remove();
+ }
+ }
+ }
+
+ /**
+ * Convenience class that searches for the root element for the given
+ * update and creates an element cache entry key.
+ */
+ private ElementDataKey makeEntryKey(IVMNode node, IViewerUpdate update) {
+ Object rootElement = update.getViewerInput(); // Default
+ outer: for (IVMModelProxy proxy : getActiveModelProxies()) {
+ Object proxyRoot = proxy.getRootElement();
+ if (proxyRoot.equals(update.getViewerInput())) {
+ rootElement = proxyRoot;
+ break;
+ }
+ TreePath path = update.getElementPath();
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ if (proxyRoot.equals(path.getSegment(i))) {
+ rootElement = proxyRoot;
+ break outer;
+ }
+ }
+ }
+
+ return new ElementDataKey(rootElement, node, update.getViewerInput(), update.getElementPath());
+ }
+
+ /**
+ * This is the only method that should be used to access a cache entry.
+ * It creates a new entry if needed and it maintains the ordering in
+ * the least-recently-used linked list.
+ */
+ private ElementDataEntry getElementDataEntry(ElementDataKey key) {
+ assert key != null;
+ ElementDataEntry entry = (ElementDataEntry)fCacheData.get(key);
+ if (entry == null) {
+ // Create a new entry and add it to the end of the list.
+ entry = new ElementDataEntry(key);
+ addEntry(key, entry);
+ } else {
+ // Entry exists, move it to the end of the list.
+ entry.reinsert(fCacheListHead);
+ }
+
+ // Update the root element marker:
+ // - ensure that the root marker is root markers' map,
+ // - ensure that the root marker is in the cache map,
+ // - and ensure that it's at the end of the cache.
+ RootElementMarkerKey rootMarker = fRootMarkers.get(key.fRootElement);
+ if (rootMarker == null) {
+ rootMarker = new RootElementMarkerKey(key.fRootElement);
+ fRootMarkers.put(key.fRootElement, rootMarker);
+ }
+ Entry rootMarkerEntry = fCacheData.get(rootMarker);
+ if (rootMarkerEntry == null) {
+ rootMarkerEntry = new RootElementMarkerEntry(rootMarker);
+ addEntry(rootMarker, rootMarkerEntry);
+ } else if (rootMarkerEntry.fNext != fCacheListHead) {
+ rootMarkerEntry.reinsert(fCacheListHead);
+ }
+
+ return entry;
+ }
+
+ /**
+ * Convenience method used by {@link #getElementDataEntry(ElementDataKey)}
+ */
+ private void addEntry(Object key, Entry entry) {
+ fCacheData.put(key, entry);
+ entry.insert(fCacheListHead);
+ // If we are at capacity in the cache, remove the entry from head.
+ if (fCacheData.size() > MAX_CACHE_SIZE) {
+ fCacheData.remove(fCacheListHead.fNext.fKey);
+ fCacheListHead.fNext.remove();
+ }
+ }
+
+ /**
+ * Retrieves the deprecated IDMData object for the given IDMContext. This
+ * method should be removed once the use of IDMData is replaced with
+ * {@link IElementPropertiesProvider}.
+ */
+ @Deprecated
+ public void getModelData(final IVMNode node, final IViewerUpdate update, final IDMService service, final IDMContext dmc,
+ final DataRequestMonitor rm, final Executor executor)
+ {
+ // Determine if this request is being issues on the a VM executor thread. If so
+ // then we do not need to create a new one to insure data integrity.
+ Executor vmExecutor = getExecutor();
+ if ( vmExecutor instanceof SimpleDisplayExecutor &&
+ Display.getDefault().getThread() == Thread.currentThread() )
+ {
+ getCacheModelData(node, update, service, dmc, rm, executor );
+ } else {
+ vmExecutor.execute(new DsfRunnable() {
+ public void run() {
+ getCacheModelData(node, update, service, dmc, rm, executor );
+ }
+ });
+ }
+ }
+
+ private void getCacheModelData(final IVMNode node, final IViewerUpdate update, final IDMService service, final IDMContext dmc,
+ final DataRequestMonitor rm, final Executor executor)
+ {
+ ElementDataKey key = makeEntryKey(node, update);
+ final ElementDataEntry entry = getElementDataEntry(key);
+ /*if (entry.fDirty) {
+ rm.setStatus(Status.CANCEL_STATUS);
+ rm.done();
+ } else */{
+ Object dataOrStatus = entry.fDataOrStatus.get(dmc);
+ if(dataOrStatus != null) {
+ if (dataOrStatus instanceof IDMData) {
+ rm.setData( dataOrStatus );
+ } else {
+ rm.setStatus((IStatus)dataOrStatus );
+ }
+ rm.done();
+ } else {
+ // Determine if we are already running on a DSF executor thread. if so then
+ // we do not need to create a new one to issue the request to the service.
+ DsfExecutor dsfExecutor = service.getExecutor();
+ if ( dsfExecutor.isInExecutorThread() ) {
+ getModelDataFromService(node, update, service, dmc, rm, executor, entry );
+ }
+ else {
+ try {
+ dsfExecutor.execute(new DsfRunnable() {
+ public void run() {
+ getModelDataFromService(node, update, service, dmc, rm, executor, entry );
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Service session's executor shut down.", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+ }
+ }
+ }
+
+ private void getModelDataFromService(final IVMNode node, final IViewerUpdate update, final IDMService service, final IDMContext dmc,
+ final DataRequestMonitor rm, final Executor executor, final ElementDataEntry entry)
+ {
+ service.getModelData(
+ dmc,
+ new ViewerDataRequestMonitor<IDMData>(executor, update) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ entry.fDataOrStatus.put(dmc, getData());
+ rm.setData(getData());
+ } else {
+ if (!isCanceled()) {
+ entry.fDataOrStatus.put(dmc, getStatus());
+ }
+ rm.setStatus(getStatus());
+ }
+ rm.done();
+ }
+ });
+ }
+
+ /**
+ * Retrieves the deprecated IDMData object for the given IDMContext. This
+ * method should be removed once the use of IDMData is replaced with
+ * {@link IElementPropertiesProvider}.
+ */
+ @Deprecated
+ public IDMData getArchivedModelData(IVMNode node, IViewerUpdate update, IDMContext dmc) {
+ ElementDataKey key = makeEntryKey(node, update);
+ final Entry entry = fCacheData.get(key);
+ if ( entry instanceof ElementDataEntry) {
+ Map<IDMContext,IDMData> archiveData = ((ElementDataEntry)entry).fArchiveData;
+ if (archiveData != null) {
+ return archiveData.get(dmc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IVMUpdateScope[] getAvailableUpdateScopes() {
+ return fAvailableUpdateScopes;
+ }
+
+ /**
+ * @since 1.1
+ */
+ public IVMUpdateScope getActiveUpdateScope() {
+ String updateScopeId = (String)getPresentationContext().getProperty(SELECTED_UPDATE_SCOPE);
+ if (updateScopeId != null) {
+ for (IVMUpdateScope updateScope : getAvailableUpdateScopes()) {
+ if (updateScope.getID().equals(updateScopeId)) {
+ return updateScope;
+ }
+ }
+ }
+
+ // Default to the first one.
+ return getAvailableUpdateScopes()[0];
+ }
+
+ /**
+ * @since 1.1
+ */
+ public void setActiveUpdateScope(IVMUpdateScope updateScope) {
+ getPresentationContext().setProperty(SELECTED_UPDATE_SCOPE, updateScope.getID());
+ }
+
+ @Override
+ public boolean shouldWaitHandleEventToComplete() {
+ return fDelayEventHandleForViewUpdate;
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected void setDelayEventHandleForViewUpdate(boolean on) {
+ fDelayEventHandleForViewUpdate = on;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AllUpdateScope.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AllUpdateScope.java
new file mode 100644
index 00000000000..6d0410643ac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AllUpdateScope.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+
+/**
+ * An "automatic" update policy which causes the view model provider cache to
+ * be flushed whenever an event causes a delta to be generated in the given
+ * model.
+ *
+ * @since 1.1
+ */
+public class AllUpdateScope implements IVMUpdateScope {
+
+ public static String ALL_UPDATE_SCOPE_ID = "org.eclipse.cdt.dsf.ui.viewmodel.update.allUpdateScope"; //$NON-NLS-1$
+
+ public String getID() {
+ return ALL_UPDATE_SCOPE_ID;
+ }
+
+ public String getName() {
+ return ViewModelUpdateMessages.AllUpdateScope_name;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AutomaticUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AutomaticUpdatePolicy.java
new file mode 100644
index 00000000000..db371896070
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/AutomaticUpdatePolicy.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * An "automatic" update policy which causes the view model provider cache to
+ * be flushed whenever an event causes a delta to be generated in the given
+ * model.
+ */
+public class AutomaticUpdatePolicy implements IVMUpdatePolicy {
+
+ public static String AUTOMATIC_UPDATE_POLICY_ID = "org.eclipse.cdt.dsf.ui.viewmodel.update.defaultUpdatePolicy"; //$NON-NLS-1$
+
+ public static IElementUpdateTester fgUpdateTester = new IElementUpdateTester() {
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ return FLUSH | ARCHIVE;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ return tester.equals(this);
+ }
+
+ @Override
+ public String toString() {
+ return "Automatic update tester"; //$NON-NLS-1$
+ }
+ };
+
+ public String getID() {
+ return AUTOMATIC_UPDATE_POLICY_ID;
+ }
+
+ public String getName() {
+ return ViewModelUpdateMessages.AutomaticUpdatePolicy_name;
+ }
+
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ return fgUpdateTester;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProvider.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProvider.java
new file mode 100644
index 00000000000..296c88aa38a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProvider.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+
+/**
+ * A view model provider which supports caching of data returned by view model
+ * nodes. The methods in this interface allow clients to configure how the
+ * cache should be updated in response to different events.
+ */
+public interface ICachingVMProvider extends IVMProvider {
+
+ /**
+ * Returns the update policies that the given provider supports.
+ */
+ public IVMUpdatePolicy[] getAvailableUpdatePolicies();
+
+ /**
+ * Returns the active update policy.
+ */
+ public IVMUpdatePolicy getActiveUpdatePolicy();
+
+ /**
+ * Sets the active update policy. This has to be one of the update
+ * policies supported by the provider.
+ */
+ public void setActiveUpdatePolicy(IVMUpdatePolicy mode);
+
+ /**
+ * Forces the view to flush its cache and re-fetch data from the view
+ * model nodes.
+ */
+ public void refresh();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension.java
new file mode 100644
index 00000000000..ba770ccc28e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ICachingVMProviderExtension.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+
+/**
+ * @since 1.1
+ */
+public interface ICachingVMProviderExtension extends ICachingVMProvider {
+
+ /**
+ * Returns the update policies that the given provider supports.
+ */
+ public IVMUpdateScope[] getAvailableUpdateScopes();
+
+ /**
+ * Returns the active update policy.
+ */
+ public IVMUpdateScope getActiveUpdateScope();
+
+ /**
+ * Sets the active update policy. This has to be one of the update
+ * policies supported by the provider.
+ */
+ public void setActiveUpdateScope(IVMUpdateScope mode);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IElementUpdateTester.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IElementUpdateTester.java
new file mode 100644
index 00000000000..0b9b4dfc474
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IElementUpdateTester.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import org.eclipse.jface.viewers.TreePath;
+
+/**
+ * Tester object used to determine how individual update cache
+ * entries should be updated during a flush operation.
+ *
+ * @see IVMUpdatePolicy
+ */
+public interface IElementUpdateTester {
+
+ /**
+ * Returns the flags indicating what updates should be performed on the
+ * cache entry of the given element.
+ */
+ public int getUpdateFlags(Object viewerInput, TreePath path);
+
+ /**
+ * Returns whether update represented by this tester includes another
+ * update. For example if update A was created as a result of an element X,
+ * and update B was created for an element Y, and element X is a parent of
+ * element Y, then tester A should include tester B. Also a tester should
+ * always include itself.
+ * <p/>
+ * This method is used to optimize the repeated flushing of the cache as
+ * it allows the cache to avoid needlessly updating the same cache entries.
+ */
+ public boolean includes(IElementUpdateTester tester);
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicy.java
new file mode 100644
index 00000000000..96eb81e3a79
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdatePolicy.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+
+/**
+ * Interface for an update policy. The main function of an update policy is
+ * to create an element tester for each given event. The element tester
+ * is then used to update the viewer cache.
+ */
+public interface IVMUpdatePolicy {
+
+ /**
+ * Flag indicating that a given entry in the cache should be cleared.
+ */
+ public static int FLUSH = 0x1;
+
+ /**
+ * Flag indicating that a given entry in the cache should be cleared
+ * and saved for purpose of change tracking.
+ */
+ public static int ARCHIVE = FLUSH | 0x2; // Flush is required when archiving.
+
+ /**
+ * Flag indicating that the a given cache entry should be marked as dirty.
+ * A dirty cache entry is one that is known not to be consistent with
+ * target data.
+ */
+ public static int DIRTY = 0x4;
+
+ /**
+ * Returns unique ID of this update policy.
+ */
+ public String getID();
+
+ /**
+ * Returns the user-presentable name of this update policy.
+ */
+ public String getName();
+
+ /**
+ * Creates an element tester for the given event.
+ */
+ public IElementUpdateTester getElementUpdateTester(Object event);
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdateScope.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdateScope.java
new file mode 100644
index 00000000000..ab0158a2b95
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/IVMUpdateScope.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+
+/**
+ * @since 1.1
+ */
+public interface IVMUpdateScope {
+
+ /**
+ * Returns unique ID of this update policy.
+ */
+ public String getID();
+
+ /**
+ * Returns the user-presentable name of this update policy.
+ */
+ public String getName();
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ManualUpdatePolicy.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ManualUpdatePolicy.java
new file mode 100644
index 00000000000..1d8a93e2e5b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ManualUpdatePolicy.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import java.util.Set;
+
+import org.eclipse.jface.viewers.TreePath;
+
+
+/**
+ * An "manual" update policy which causes the view model provider cache to be
+ * flushed only as a result of an explicit user action.
+ */
+public class ManualUpdatePolicy implements IVMUpdatePolicy {
+
+ public static String MANUAL_UPDATE_POLICY_ID = "org.eclipse.cdt.dsf.ui.viewmodel.update.manualUpdatePolicy"; //$NON-NLS-1$
+
+ public static Object REFRESH_EVENT = new Object();
+
+ private static class UserEditEventUpdateTester implements IElementUpdateTester {
+ private final Set<Object> fElements;
+
+ public UserEditEventUpdateTester(Set<Object> elements) {
+ fElements = elements;
+ }
+
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ if (fElements.contains(viewerInput)) {
+ return FLUSH;
+ }
+ for (int i = 0; i < path.getSegmentCount(); i++) {
+ if (fElements.contains(path.getSegment(i))) {
+ return FLUSH;
+ }
+ }
+ return 0;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ return
+ tester instanceof UserEditEventUpdateTester &&
+ fElements.equals(((UserEditEventUpdateTester)tester).fElements);
+ }
+
+ @Override
+ public String toString() {
+ return "Edit (" + fElements + ") update tester"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ private static IElementUpdateTester fgUpdateTester = new IElementUpdateTester() {
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ return DIRTY;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ return tester.equals(this);
+ }
+
+ @Override
+ public String toString() {
+ return "Manual (refresh = false) update tester"; //$NON-NLS-1$
+ }
+ };
+
+ private static IElementUpdateTester fgRefreshUpdateTester = new IElementUpdateTester() {
+ public int getUpdateFlags(Object viewerInput, TreePath path) {
+ return FLUSH | ARCHIVE;
+ }
+
+ public boolean includes(IElementUpdateTester tester) {
+ return tester.equals(this) || tester.equals(fgUpdateTester) || tester instanceof UserEditEventUpdateTester;
+ }
+
+ @Override
+ public String toString() {
+ return "Manual (refresh = true) update tester"; //$NON-NLS-1$
+ }
+ };
+
+ public String getID() {
+ return MANUAL_UPDATE_POLICY_ID;
+ }
+
+ public String getName() {
+ return ViewModelUpdateMessages.ManualUpdatePolicy_name;
+ }
+
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ if (event.equals(REFRESH_EVENT)) {
+ return fgRefreshUpdateTester;
+ } else if (event instanceof UserEditEvent) {
+ return new UserEditEventUpdateTester(((UserEditEvent)event).getElements());
+ }
+ return fgUpdateTester;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/MultiLevelUpdateHandler.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/MultiLevelUpdateHandler.java
new file mode 100644
index 00000000000..4605629a504
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/MultiLevelUpdateHandler.java
@@ -0,0 +1,233 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.ui.viewmodel.update;
+
+import java.util.List;
+import java.util.Stack;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMModelProxyExtension;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMChildrenUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMHasChildrenUpdate;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.TreePath;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+
+@SuppressWarnings("restriction")
+class MultiLevelUpdateHandler extends DataRequestMonitor<List<Object>> {
+
+ private static final boolean DEBUG = Boolean.parseBoolean(Platform.getDebugOption("org.eclipse.cdt.dsf.ui/debug/vm/atomicUpdate")); //$NON-NLS-1$ //;
+
+ private static final class UpdateLevel {
+ private final List<Object> fChildren;
+ private final TreePath fPath;
+ private int fChildIndex;
+ private UpdateLevel(TreePath path, List<Object> children) {
+ fPath = path;
+ fChildren = children;
+ fChildIndex = 0;
+ assert !isDone();
+ }
+ private boolean isDone() {
+ return fChildIndex == fChildren.size();
+ }
+ private Object nextChild() {
+ if (isDone()) {
+ return null;
+ }
+ return fChildren.get(fChildIndex++);
+ }
+ }
+ private final class DummyLabelUpdate implements ILabelUpdate {
+ private final RequestMonitor fMonitor;
+ private final Object fData;
+ private final TreePath fPath;
+
+ private DummyLabelUpdate(Object data, TreePath path, RequestMonitor rm) {
+ fMonitor= rm;
+ fData= data;
+ fPath= path;
+ }
+ public Object getElement() {
+ return fData;
+ }
+ public TreePath getElementPath() {
+ return fPath.createChildPath(fData);
+ }
+ public IPresentationContext getPresentationContext() {
+ return fPresentationContext;
+ }
+ public Object getViewerInput() {
+ return fViewerInput;
+ }
+ public void cancel() { }
+ public IStatus getStatus() {
+ return null;
+ }
+ public boolean isCanceled() {
+ return false;
+ }
+ public void setStatus(IStatus status) { }
+ public String[] getColumnIds() {
+ return fColumns;
+ }
+ public void setBackground(RGB arg0, int arg1) { }
+ public void setFontData(FontData arg0, int arg1) { }
+ public void setForeground(RGB arg0, int arg1) { }
+ public void setImageDescriptor(ImageDescriptor arg0, int arg1) { }
+ public void setLabel(String arg0, int arg1) {
+ }
+ public void done() {
+ fMonitor.done();
+ }
+ }
+
+ private final Executor fExecutor;
+ private final IElementContentProvider fContentProvider;
+ private final IPresentationContext fPresentationContext;
+ private final String[] fColumns;
+ private final Viewer fViewer;
+ private final Object fViewerInput;
+ private final Stack<UpdateLevel> fStack = new Stack<UpdateLevel>();
+ private final CountingRequestMonitor fRequestMonitor;
+
+ private int fIndex = 0;
+ private TreePath fCurrentPath;
+ private int fLowIndex = 0;
+ private int fHighIndex = Integer.MAX_VALUE - 1;
+ private int fPendingUpdates;
+
+ public MultiLevelUpdateHandler(Executor executor,
+ IVMModelProxyExtension modelProxy,
+ IPresentationContext presentationContext,
+ IElementContentProvider contentProvider,
+ RequestMonitor parentRequestMonitor) {
+ super(executor, null);
+ fExecutor = executor;
+ fViewer = modelProxy.getViewer();
+ fViewerInput = modelProxy.getViewerInput();
+ fCurrentPath = modelProxy.getRootPath();
+ fPresentationContext = presentationContext;
+ fColumns = presentationContext.getColumns();
+ fContentProvider = contentProvider;
+
+ fRequestMonitor = new CountingRequestMonitor(fExecutor, parentRequestMonitor);
+ }
+ void startUpdate() {
+ if (DEBUG) System.out.println("[MultiLevelUpdateHandler] startUpdate " + fLowIndex + '-' + fHighIndex); //$NON-NLS-1$
+ fContentProvider.update(new IChildrenUpdate[] {
+ new VMChildrenUpdate(fCurrentPath, fViewerInput, fPresentationContext, -1, -1, this)
+ });
+ }
+ void setRange(int low, int high) {
+ fLowIndex = low;
+ fHighIndex = high;
+ }
+ boolean isDone() {
+ return fStack.isEmpty();
+ }
+ @Override
+ public synchronized void done() {
+ try {
+ fExecutor.execute(new DsfRunnable() {
+ public void run() {
+ final List<Object> data= getData();
+ if (data != null && !data.isEmpty()) {
+ if (DEBUG) System.out.println("[MultiLevelUpdateHandler] gotChildUpdate " + data.size()); //$NON-NLS-1$
+ fStack.push(new UpdateLevel(fCurrentPath, data));
+ }
+ processNext();
+ }
+ @Override
+ public String toString() {
+ return "Completed: " + MultiLevelUpdateHandler.this.toString(); //$NON-NLS-1$
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ handleRejectedExecutionException();
+ }
+ }
+ protected void processNext() {
+ while (true) {
+ if (fIndex > fHighIndex) {
+ fStack.clear();
+ }
+ if (fStack.isEmpty()) {
+ fRequestMonitor.setDoneCount(fPendingUpdates);
+ super.done();
+ return;
+ }
+ UpdateLevel current = fStack.peek();
+ assert !current.isDone();
+
+ TreePath path = current.fPath;
+ Object data = current.nextChild();
+ if (current.isDone()) {
+ fStack.pop();
+ }
+ if (data == null) {
+ // consider null children - http://bugs.eclipse.org/250309
+ ++fIndex;
+ continue;
+ }
+ path = path.createChildPath(data);
+
+ if (fIndex >= fLowIndex && fIndex <= fHighIndex) {
+ if(data instanceof IAdaptable) {
+ IElementLabelProvider labelProvider = (IElementLabelProvider) ((IAdaptable)data).getAdapter(IElementLabelProvider.class);
+ if (labelProvider != null) {
+ ++fPendingUpdates;
+ if (DEBUG) System.out.println("[MultiLevelUpdateHandler] labelUpdate " + data); //$NON-NLS-1$
+ labelProvider.update(new ILabelUpdate[] {
+ new DummyLabelUpdate(data, path, fRequestMonitor)
+ });
+ }
+ }
+ }
+ fIndex++;
+ if (fViewer instanceof TreeViewer) {
+ TreeViewer treeViewer = (TreeViewer) fViewer;
+ if (treeViewer.getExpandedState(data)) {
+ fCurrentPath = path;
+ if (DEBUG) System.out.println("[MultiLevelUpdateHandler] childrenUpdate " + data); //$NON-NLS-1$
+ fContentProvider.update(new IChildrenUpdate[] {
+ new VMChildrenUpdate(path, fViewerInput, fPresentationContext, -1, -1, this)
+ });
+ return;
+ } else if (fIndex >= fLowIndex) {
+ // update also the hasChildren flag
+ ++fPendingUpdates;
+ if (DEBUG) System.out.println("[MultiLevelUpdateHandler] hasChildUpdate " + data); //$NON-NLS-1$
+ fContentProvider.update(new IHasChildrenUpdate[] {
+ new VMHasChildrenUpdate(path, fViewerInput, fPresentationContext, new DataRequestMonitor<Boolean>(fExecutor, fRequestMonitor))
+ });
+ }
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UpdatePolicyDecorator.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UpdatePolicyDecorator.java
new file mode 100644
index 00000000000..a0e4834f192
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UpdatePolicyDecorator.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+/**
+ * An update policy decorator which can override behaviour of an underlying update policy.
+ *
+ * @since 1.1
+ */
+public abstract class UpdatePolicyDecorator implements IVMUpdatePolicy {
+
+ private final IVMUpdatePolicy fBasePolicy;
+
+ protected UpdatePolicyDecorator(IVMUpdatePolicy base) {
+ fBasePolicy= base;
+ }
+
+ protected final IVMUpdatePolicy getBaseUpdatePolicy() {
+ return fBasePolicy;
+ }
+
+ public final String getID() {
+ return fBasePolicy.getID();
+ }
+
+ public String getName() {
+ return fBasePolicy.getName();
+ }
+
+ public IElementUpdateTester getElementUpdateTester(Object event) {
+ return fBasePolicy.getElementUpdateTester(event);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UserEditEvent.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UserEditEvent.java
new file mode 100644
index 00000000000..c0244fa3c8e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/UserEditEvent.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An event representing a user editing of the data in the viewer. Typically, when
+ * a viewer is configured to be in a manual update mode, if user edits a value, the
+ * viewer should still update at least the value that the user editor. This event
+ * is used to accomplish that behavior.
+ */
+public class UserEditEvent {
+ private final Set<Object> fElements;
+
+ public UserEditEvent(Object element) {
+ fElements = new HashSet<Object>();
+ fElements.add(element);
+ }
+
+ public UserEditEvent(Set<Object> elements) {
+ fElements = elements;
+ }
+
+ public Set<Object> getElements() {
+ return fElements;
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.java
new file mode 100644
index 00000000000..ff6b1b5deef
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+import org.eclipse.osgi.util.NLS;
+
+public class ViewModelUpdateMessages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.cdt.dsf.ui.viewmodel.update.ViewModelUpdateMessages";//$NON-NLS-1$
+
+ public static String AutomaticUpdatePolicy_name;
+ public static String ManualUpdatePolicy_name;
+ /**
+ * @since 1.1
+ */
+ public static String AllUpdateScope_name;
+ /**
+ * @since 1.1
+ */
+ public static String VisibleUpdateScope_name;
+
+ static {
+ // load message values from bundle file
+ NLS.initializeMessages(BUNDLE_NAME, ViewModelUpdateMessages.class);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.properties b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.properties
new file mode 100644
index 00000000000..9de3c47ec66
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/ViewModelUpdateMessages.properties
@@ -0,0 +1,14 @@
+###############################################################################
+# Copyright (c) 2008 Wind River Systems 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
+###############################################################################
+AutomaticUpdatePolicy_name=Automatic
+ManualUpdatePolicy_name=Manual
+AllUpdateScope_name=All Elements
+VisibleUpdateScope_name=Visible Elements \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/VisibleUpdateScope.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/VisibleUpdateScope.java
new file mode 100644
index 00000000000..093a33ba5de
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/ui/viewmodel/update/VisibleUpdateScope.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.ui.viewmodel.update;
+
+
+/**
+ * An "automatic" update policy which causes the view model provider cache to
+ * be flushed whenever an event causes a delta to be generated in the given
+ * model.
+ * @since 1.1
+ */
+public class VisibleUpdateScope implements IVMUpdateScope {
+
+ public static String VISIBLE_UPDATE_SCOPE_ID = "org.eclipse.cdt.dsf.ui.viewmodel.update.visibleUpdateScope"; //$NON-NLS-1$
+
+ public String getID() {
+ return VISIBLE_UPDATE_SCOPE_ID;
+ }
+
+ public String getName() {
+ return ViewModelUpdateMessages.VisibleUpdateScope_name;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/.classpath b/dsf/org.eclipse.cdt.dsf/.classpath
new file mode 100644
index 00000000000..304e86186aa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.dsf/.cvsignore b/dsf/org.eclipse.cdt.dsf/.cvsignore
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.cvsignore
@@ -0,0 +1 @@
+
diff --git a/dsf/org.eclipse.cdt.dsf/.options b/dsf/org.eclipse.cdt.dsf/.options
new file mode 100644
index 00000000000..77f365ef759
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.options
@@ -0,0 +1,3 @@
+org.eclipse.cdt.dsf/debug = false
+org.eclipse.cdt.dsf/debug/executor = false
+org.eclipse.cdt.dsf/debug/executorName =
diff --git a/dsf/org.eclipse.cdt.dsf/.project b/dsf/org.eclipse.cdt.dsf/.project
new file mode 100644
index 00000000000..4dc6a12b637
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.dsf</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>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ </natures>
+</projectDescription>
diff --git a/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..5ca4ed2212c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Tue Jun 24 11:02:22 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=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=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.ui.prefs b/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..087537fe3fb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,3 @@
+#Sun Aug 06 18:10:27 CEST 2006
+eclipse.preferences.version=1
+internal.default.compliance=default
diff --git a/dsf/org.eclipse.cdt.dsf/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.dsf/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..ac497668cd7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Vendor: %providerName
+Bundle-SymbolicName: org.eclipse.cdt.dsf;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.dsf.internal.DsfPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.cdt.dsf,
+ org.eclipse.cdt.core,
+ org.eclipse.cdt.debug.core
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.cdt.dsf.concurrent,
+ org.eclipse.cdt.dsf.datamodel,
+ org.eclipse.cdt.dsf.debug.internal.provisional.model,
+ org.eclipse.cdt.dsf.debug.model,
+ org.eclipse.cdt.dsf.debug.service,
+ org.eclipse.cdt.dsf.debug.service.command,
+ org.eclipse.cdt.dsf.debug.sourcelookup,
+ org.eclipse.cdt.dsf.service
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.dsf/about.html b/dsf/org.eclipse.cdt.dsf/about.html
new file mode 100644
index 00000000000..cb740ae8bc8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/about.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>About</title></head><body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/buckminster.cspex b/dsf/org.eclipse.cdt.dsf/buckminster.cspex
new file mode 100644
index 00000000000..1aaa95e7dfd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/buckminster.cspex
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<cs:cspecExtension xmlns:cs="http://www.eclipse.org/buckminster/CSpec-1.0" name="org.eclipse.cdt.dsf">
+ <cs:artifacts>
+ <cs:public name="source" path="src/"/>
+ </cs:artifacts>
+ <cs:actions>
+ <cs:public name="java.binary.archives" actor="ant">
+ <cs:actorProperties>
+ <cs:property key="buildFile" value="make/build.xml"/>
+ </cs:actorProperties>
+ <cs:prerequisites alias="input">
+ <cs:local attribute="eclipse.build"/>
+ </cs:prerequisites>
+ <cs:products alias="output" base="bin/jars/">
+ <cs:path path="dsf.jar"/>
+ </cs:products>
+ </cs:public>
+ <cs:private name="eclipse.build">
+ <cs:prerequisites>
+ <cs:local attribute="source"/>
+ </cs:prerequisites>
+ <cs:products base="bin/classes/">
+ <cs:path path="."/>
+ </cs:products>
+ </cs:private>
+ </cs:actions>
+ <cs:groups>
+ <cs:public name="java.binaries">
+ <cs:local attribute="eclipse.build"/>
+ </cs:public>
+ </cs:groups>
+</cs:cspecExtension>
diff --git a/dsf/org.eclipse.cdt.dsf/build.properties b/dsf/org.eclipse.cdt.dsf/build.properties
new file mode 100644
index 00000000000..e061b4e53d0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/build.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ about.html
diff --git a/dsf/org.eclipse.cdt.dsf/make/build.xml b/dsf/org.eclipse.cdt.dsf/make/build.xml
new file mode 100644
index 00000000000..51a4fb7a32f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/make/build.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0"?>
+<project name="org.eclipse.cdt.dsf">
+ <target name="java.binary.archives">
+ <dirname property="output.dir" file="${output}"/>
+ <mkdir dir="${output.dir}"/>
+ <jar destfile="${output}">
+ <fileset refid="input.fileset"/>
+ </jar>
+ </target>
+</project>
diff --git a/dsf/org.eclipse.cdt.dsf/make/dsf.jardesc b/dsf/org.eclipse.cdt.dsf/make/dsf.jardesc
new file mode 100644
index 00000000000..76daa653d13
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/make/dsf.jardesc
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jardesc>
+<jar path="bin/jars/worlds.jar"/>
+<options buildIfNeeded="true" compress="true" descriptionLocation="/org.eclipse.cdt.dsf/make/dsf.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/>
+<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
+<selectedProjects/>
+<manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true">
+<sealing sealJar="false">
+<packagesToSeal/>
+<packagesToUnSeal/>
+</sealing>
+</manifest>
+<selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false">
+<javaElement handleIdentifier="=org.eclipse.cdt.dsf"/>
+</selectedElements>
+</jardesc>
diff --git a/dsf/org.eclipse.cdt.dsf/plugin.properties b/dsf/org.eclipse.cdt.dsf/plugin.properties
new file mode 100644
index 00000000000..7c8259ba857
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2006 Wind River Systems 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=Debug Services Framework Core
+providerName=Eclipse.org
+
diff --git a/dsf/org.eclipse.cdt.dsf/plugin.xml b/dsf/org.eclipse.cdt.dsf/plugin.xml
new file mode 100644
index 00000000000..33ca93ceb1b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/plugin.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+</plugin>
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java
new file mode 100644
index 00000000000..27452c25061
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, or field can be
+ * access safely only from a DSF executor thread. If declared on package or type,
+ * a field or method could still be declared with an annotation indicating that it's
+ * thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ *
+ * @param value The value indicates the method to use to obtain the executor.
+ * It should be null if it cannot be determined from the given object.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ConfinedToDsfExecutor {
+ String value();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java
new file mode 100644
index 00000000000..ea9fa9d6c72
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+
+/**
+ * Utility class to collect multiple request monitor results of commands
+ * that are initiated simultaneously. The usage is as follows:
+ * <code><pre>
+ * final CountingRequestMonitor countingRm = new CountingRequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println("All complete, errors=" + !getStatus().isOK());
+ * }
+ * };
+ *
+ * int count = 0;
+ * for (int i : elements) {
+ * service.call(i, countingRm);
+ * count++;
+ * }
+ *
+ * countingRm.setDoneCount(count);
+ * </pre></code>
+ */
+public class CountingRequestMonitor extends RequestMonitor {
+ /**
+ * Counter tracking the remaining number of times that the done() method
+ * needs to be called before this request monitor is actually done.
+ */
+ private int fDoneCounter;
+
+ /**
+ * Flag indicating whether the initial count has been set on this monitor.
+ */
+ private boolean fInitialCountSet = false;
+
+ public CountingRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ super.setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the number of times that this request monitor needs to be called
+ * before this monitor is truly considered done. This method must be called
+ * exactly once in the life cycle of each counting request monitor.
+ * @param count Number of times that done() has to be called to mark the request
+ * monitor as complete. If count is '0', then the counting request monitor is
+ * marked as done immediately.
+ */
+ public synchronized void setDoneCount(int count) {
+ assert !fInitialCountSet;
+ fInitialCountSet = true;
+ fDoneCounter += count;
+ if (fDoneCounter <= 0) {
+ assert fDoneCounter == 0; // Mismatch in the count.
+ super.done();
+ }
+ }
+
+ /**
+ * Called to indicate that one of the calls using this monitor is finished.
+ * Only when <code>done</done> is called the number of times corresponding to the
+ * count, the request monitor will be considered complete. This method can be
+ * called before {@link #setDoneCount(int)}.
+ */
+ @Override
+ public synchronized void done() {
+ fDoneCounter--;
+ if (fInitialCountSet && fDoneCounter <= 0) {
+ assert fDoneCounter == 0; // Mismatch in the count.
+ super.done();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CountingRequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
+ }
+
+ @Override
+ public synchronized void setStatus(IStatus status) {
+ if ((getStatus() instanceof MultiStatus)) {
+ ((MultiStatus)getStatus()).add(status);
+ }
+ };
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java
new file mode 100644
index 00000000000..58daf516459
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+
+/**
+ * Request monitor that allows data to be returned to the request initiator.
+ *
+ * @param V The type of the data object that this monitor handles.
+ */
+public class DataRequestMonitor<V> extends RequestMonitor {
+
+ /** Data object reference */
+ private V fData;
+
+ public DataRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ }
+
+ /**
+ * Sets the data object to specified value. To be called by the
+ * asynchronous method implementor.
+ * @param data Data value to set.
+ */
+ public synchronized void setData(V data) { fData = data; }
+
+ /**
+ * Returns the data value, null if not set.
+ */
+ public synchronized V getData() { return fData; }
+
+ @Override
+ public String toString() {
+ if (getData() != null) {
+ return getData().toString();
+ } else {
+ return super.toString();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java
new file mode 100644
index 00000000000..e2c7efc5642
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Default implementation of a DSF executor interfaces, based on the
+ * standard java.util.concurrent.ThreadPoolExecutor.
+ */
+
+public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
+ implements DsfExecutor
+{
+ /**
+ * Instance counter for DSF executors. Used in the executor's thread name.
+ */
+ private static int fgInstanceCounter = 0;
+
+ /**
+ * Name of the executor, used in the executor's thread name.
+ */
+ private String fName;
+
+ /**
+ * Instance number of this executor, used with the executor name.
+ */
+ private int fInstanceNumber;
+
+ /** Thread factory that creates the single thread to be used for this executor */
+ static class DsfThreadFactory implements ThreadFactory {
+ private String fThreadName;
+ DsfThreadFactory(String name) {
+ fThreadName = name;
+ }
+
+ Thread fThread;
+ public Thread newThread(Runnable r) {
+ assert fThread == null; // Should be called only once.
+ fThread = new Thread(new ThreadGroup(fThreadName), r, fThreadName, 0);
+ return fThread;
+ }
+ }
+
+ public DefaultDsfExecutor() {
+ this("DSF Executor"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a new DSF Executor with the given name.
+ * @param name Name used to create executor's thread.
+ */
+ public DefaultDsfExecutor(String name) {
+ super(1, new DsfThreadFactory(name + " - " + fgInstanceCounter)); //$NON-NLS-1$
+ fName = name;
+ fInstanceNumber = fgInstanceCounter++;
+
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ // If tracing, pre-start the dispatch thread, and add it to the map.
+ prestartAllCoreThreads();
+ fThreadToExecutorMap.put(((DsfThreadFactory)getThreadFactory()).fThread, DefaultDsfExecutor.this);
+ }
+ }
+
+ public boolean isInExecutorThread() {
+ return Thread.currentThread().equals( ((DsfThreadFactory)getThreadFactory()).fThread );
+ }
+
+ protected String getName() {
+ return fName;
+ }
+
+ static void logException(Throwable t) {
+ DsfPlugin plugin = DsfPlugin.getDefault();
+ if (plugin == null) return;
+
+ ILog log = plugin.getLog();
+ if (log != null) {
+ log.log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", t)); //$NON-NLS-1$
+ }
+ // Print out the stack trace to console if assertions are enabled.
+ if(ASSERTIONS_ENABLED) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(512);
+ PrintStream printStream = new PrintStream(outStream);
+ try {
+ printStream.write("Uncaught exception in session executor thread: ".getBytes()); //$NON-NLS-1$
+ } catch (IOException e2) {}
+ t.printStackTrace(new PrintStream(outStream));
+ System.err.println(outStream.toString());
+ }
+ }
+
+ //
+ // Utilities used for tracing.
+ //
+ protected static boolean DEBUG_EXECUTOR = false;
+ protected static String DEBUG_EXECUTOR_NAME = ""; //$NON-NLS-1$
+ protected static boolean ASSERTIONS_ENABLED = false;
+ static {
+ DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
+ DEBUG_EXECUTOR_NAME = DsfPlugin.DEBUG
+ ? Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executorName") : ""; //$NON-NLS-1$ //$NON-NLS-2$
+ assert (ASSERTIONS_ENABLED = true) == true;
+ }
+
+ /**
+ * This map is used by DsfRunnable/Query/DsfCallable to track by which executor
+ * an executable object was created.
+ * <br>Note: Only used when tracing.
+ */
+ static Map<Thread, DefaultDsfExecutor> fThreadToExecutorMap = new HashMap<Thread, DefaultDsfExecutor>();
+
+ /**
+ * Currently executing runnable/callable.
+ * <br>Note: Only used when tracing.
+ */
+ TracingWrapper fCurrentlyExecuting;
+
+ /**
+ * Counter number saved by each tracing runnable when executed
+ * <br>Note: Only used when tracing.
+ */
+ int fSequenceCounter;
+
+ /**
+ * Wrapper for runnables/callables, is used to store tracing information
+ * <br>Note: Only used when tracing.
+ */
+ abstract class TracingWrapper {
+ /** Sequence number of this runnable/callable */
+ int fSequenceNumber = -1;
+
+ /** Trace of where the runnable/callable was submitted to the executor */
+ StackTraceWrapper fSubmittedAt = null;
+
+ /** Reference to the runnable/callable that submitted this runnable/callable to the executor */
+ TracingWrapper fSubmittedBy = null;
+
+ /**
+ * @param offset the number of items in the stack trace not to be printed
+ */
+ TracingWrapper(int offset) {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ // guard against the offset being greater than the stack trace
+ offset = Math.min(offset, stackTrace.length);
+ fSubmittedAt = new StackTraceWrapper(new StackTraceElement[stackTrace.length - offset]);
+ System.arraycopy(stackTrace, offset - 1, fSubmittedAt.fStackTraceElements, 0, fSubmittedAt.fStackTraceElements.length);
+ if (isInExecutorThread() && fCurrentlyExecuting != null) {
+ fSubmittedBy = fCurrentlyExecuting;
+ }
+ }
+
+ void traceExecution() {
+ fSequenceNumber = fSequenceCounter++;
+ fCurrentlyExecuting = this;
+
+ // Write to console only if tracing is enabled (as opposed to tracing or assertions).
+ if (DEBUG_EXECUTOR && ("".equals(DEBUG_EXECUTOR_NAME) || fName.equals(DEBUG_EXECUTOR_NAME))) { //$NON-NLS-1$
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ traceBuilder.append(DsfPlugin.getDebugTime());
+ traceBuilder.append(' ');
+
+ // Record the executor #
+ traceBuilder.append('#');
+ traceBuilder.append(fSequenceNumber);
+
+ // Record the executor name
+ traceBuilder.append('(');
+ traceBuilder.append(fName);
+ traceBuilder.append(" - "); //$NON-NLS-1$
+ traceBuilder.append(fInstanceNumber);
+ traceBuilder.append(')');
+ traceBuilder.append(' ');
+
+ // Append executable class name
+ traceBuilder.append(getExecutable().getClass().getName());
+
+ // Add executable's toString().
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(getExecutable().toString());
+
+ // Append "create by" info.
+ if (getExecutable() instanceof DsfExecutable) {
+ DsfExecutable dsfExecutable = (DsfExecutable)getExecutable();
+ if (dsfExecutable.fCreatedAt != null || dsfExecutable.fCreatedBy != null) {
+ traceBuilder.append("\n created "); //$NON-NLS-1$
+ if (dsfExecutable.fCreatedBy != null) {
+ traceBuilder.append(" by #"); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedBy.fSequenceNumber);
+ }
+ if (dsfExecutable.fCreatedAt != null) {
+ traceBuilder.append("\n at "); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedAt.fStackTraceElements[0].toString());
+ for (int i = 1; i < dsfExecutable.fCreatedAt.fStackTraceElements.length && i < 3; i++) {
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedAt.fStackTraceElements[i].toString());
+ }
+ }
+ }
+ }
+
+ // Submitted info
+ traceBuilder.append("\n submitted"); //$NON-NLS-1$
+ if (fSubmittedBy != null) {
+ traceBuilder.append(" by #"); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedBy.fSequenceNumber);
+ }
+ traceBuilder.append("\n at "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[0].toString());
+ for (int i = 1; i < fSubmittedAt.fStackTraceElements.length && i < 3; i++) {
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[i].toString());
+ }
+ traceBuilder.append(" at "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[0].toString());
+
+ // Finally write out to console
+ DsfPlugin.debug(traceBuilder.toString());
+ }
+ }
+
+ abstract protected Object getExecutable();
+ }
+
+
+ class TracingWrapperRunnable extends TracingWrapper implements Runnable {
+ final Runnable fRunnable;
+ public TracingWrapperRunnable(Runnable runnable, int offset) {
+ super(offset);
+ if (runnable == null) throw new NullPointerException();
+ fRunnable = runnable;
+
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) {
+ assert !((DsfExecutable)fRunnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)fRunnable).setSubmitted();
+ }
+ }
+
+ @Override
+ protected Object getExecutable() { return fRunnable; }
+
+ public void run() {
+ traceExecution();
+
+ // Finally invoke the runnable code.
+ try {
+ fRunnable.run();
+ } catch (RuntimeException e) {
+ // If an exception was thrown in the Runnable, trace it.
+ // Because there is no one else to catch it, it is a
+ // programming error.
+ logException(e);
+ throw e;
+ }
+ }
+ }
+
+ public class TracingWrapperCallable<T> extends TracingWrapper implements Callable<T> {
+ final Callable<T> fCallable;
+ public TracingWrapperCallable(Callable<T> callable, int offset) {
+ super(offset);
+ if (callable == null) throw new NullPointerException();
+ fCallable = callable;
+ }
+
+ @Override
+ protected Object getExecutable() { return fCallable; }
+
+ public T call() throws Exception {
+ traceExecution();
+
+ // Finally invoke the runnable code.
+ // Note that callables can throw exceptions that can be caught
+ // by clients that invoked them using ExecutionException.
+ return fCallable.call();
+ }
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ if ( !(callable instanceof TracingWrapper) ) {
+ callable = new TracingWrapperCallable<V>(callable, 6);
+ }
+ }
+ return super.schedule(callable, delay, unit);
+ }
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ if ( !(command instanceof TracingWrapper) ) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ }
+ return super.schedule(command, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ super.execute(command);
+ }
+
+ @Override
+ public Future<?> submit(Runnable command) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.submit(command);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> callable) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ callable = new TracingWrapperCallable<T>(callable, 6);
+ }
+ return super.submit(callable);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable command, T result) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.submit(command, result);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java
new file mode 100644
index 00000000000..52d1d43dd25
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Base class for DSF-instrumented alternative to the Runnable/Callable interfaces.
+ * <p>
+ * While it is perfectly fine for clients to call the DSF executor with
+ * an object only implementing the Runnable/Callable interface, the DsfExecutable
+ * contains fields and methods that used for debugging and tracing when
+ * tracing is enabled.
+ */
+@Immutable
+public class DsfExecutable {
+ /**
+ * Flag indicating that tracing of the DSF executor is enabled. It enables
+ * storing of the "creator" information as well as tracing of disposed
+ * runnables that have not been submitted to the executor.
+ */
+ static boolean DEBUG_EXECUTOR = false;
+
+ /**
+ * Flag indicating that assertions are enabled. It enables storing of the
+ * "creator" executable for debugging purposes.
+ */
+ static boolean ASSERTIONS_ENABLED = false;
+
+ static {
+ assert (ASSERTIONS_ENABLED = true) == true;
+ DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
+ }
+
+ /**
+ * Field that holds the stack trace of where this executable was created.
+ * Used for tracing and debugging only.
+ */
+ final StackTraceWrapper fCreatedAt;
+
+ /**
+ * Field holding the reference of the executable that created this
+ * executable. Used for tracing only.
+ */
+ final DefaultDsfExecutor.TracingWrapper fCreatedBy;
+
+ /**
+ * Flag indicating whether this executable was ever executed by an
+ * executor. Used for tracing only.
+ */
+ private volatile boolean fSubmitted = false;
+
+ @SuppressWarnings("unchecked")
+ public DsfExecutable() {
+ // Use assertion flag (-ea) to jre to avoid affecting performance when not debugging.
+ if (ASSERTIONS_ENABLED || DEBUG_EXECUTOR) {
+ // Find the runnable/callable that is currently running.
+ DefaultDsfExecutor executor = DefaultDsfExecutor.fThreadToExecutorMap.get(Thread.currentThread());
+ if (executor != null) {
+ fCreatedBy = executor.fCurrentlyExecuting;
+ } else {
+ fCreatedBy = null;
+ }
+
+ // Get the stack trace and find the first method that is not a
+ // constructor of this object.
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ Class thisClass = getClass();
+ Set<String> classNamesSet = new HashSet<String>();
+ while(thisClass != null) {
+ classNamesSet.add(thisClass.getName());
+ thisClass = thisClass.getSuperclass();
+ }
+ int i;
+ for (i = 3; i < stackTrace.length; i++) {
+ if ( !classNamesSet.contains(stackTrace[i].getClassName()) ) break;
+ }
+ fCreatedAt = new StackTraceWrapper(new StackTraceElement[stackTrace.length - i]);
+ System.arraycopy(stackTrace, i, fCreatedAt.fStackTraceElements, 0, fCreatedAt.fStackTraceElements.length);
+ } else {
+ fCreatedAt = null;
+ fCreatedBy = null;
+ }
+ }
+
+ public boolean getSubmitted() {
+ return fSubmitted;
+ }
+
+ /**
+ * Marks this executable to indicate that it has been executed by the
+ * executor. To be invoked only by DsfExecutor.
+ */
+ public void setSubmitted() {
+ fSubmitted = true;
+ }
+
+ /**
+ * Returns whether the runnable/callable is expected to be always executed.
+ * Overriding classes can implement this method and return false, to avoid
+ * unnecessary trace output.
+ * @return true if this runnable is expected to run.
+ */
+ protected boolean isExecutionRequired() {
+ return true;
+ }
+
+ @Override
+ protected void finalize() {
+ if (DEBUG_EXECUTOR && !fSubmitted && isExecutionRequired()) {
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ traceBuilder.append(DsfPlugin.getDebugTime());
+ traceBuilder.append(' ');
+
+ // Record the event
+ traceBuilder.append("DsfExecutable was never executed:\n "); //$NON-NLS-1$
+ traceBuilder.append(this);
+ traceBuilder.append("\nCreated at:"); //$NON-NLS-1$
+ traceBuilder.append(fCreatedAt);
+
+ DsfPlugin.debug(traceBuilder.toString());
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java
new file mode 100644
index 00000000000..8c7cd554bc2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * DSF executor service. Implementations of this executor must ensure
+ * that all runnables and callables are executed in the same thread: the
+ * executor's single dispatch thread.
+ * <br>Note: A DSF executor dispatch thread does not necessarily have
+ * to be exclusive to the executor, it could be shared with
+ * another event dispatch service, such as the SWT display dispatch thread.
+ */
+@ThreadSafe
+public interface DsfExecutor extends ScheduledExecutorService
+{
+ /**
+ * Checks if the thread that this method is called in is the same as the
+ * executor's dispatch thread.
+ * @return true if in DSF executor's dispatch thread
+ */
+ public boolean isInExecutorThread();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java
new file mode 100644
index 00000000000..f315288668a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.concurrent;
+
+
+/**
+ * A DSF-instrumented alternative to the Runnable interface.
+ * <p>
+ * While it is perfectly fine for clients to call the DSF executor with
+ * an object only implementing the Runnable interface, the DsfRunnable
+ * contains fields and methods that used for debugging and tracing when
+ * tracing is enabled.
+ */
+abstract public class DsfRunnable extends DsfExecutable implements Runnable {
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java
new file mode 100644
index 00000000000..d7be9a7ad67
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+/**
+ * Interface that hold the codes used when reporting status using the DSF
+ * Request Monitor.
+ */
+public interface IDsfStatusConstants {
+ /**
+ * Error code indicating that the service is in a state which does not allow the
+ * request to be processed. For example if the client requested target information
+ * after target was disconnected.
+ */
+ final static int INVALID_STATE = 10001;
+
+ /**
+ * Error code indicating that client supplied an invalid handle to the service.
+ * A handle could become invalid after an object it represents is removed from
+ * the system.
+ */
+ final static int INVALID_HANDLE = 10002;
+
+ /**
+ * Error code indicating that the client request is not supported/implemented.
+ */
+ final static int NOT_SUPPORTED = 10003;
+
+ /**
+ * Error code indicating that the request to a sub-service or an external process
+ * failed.
+ */
+ final static int REQUEST_FAILED = 10004;
+
+ /**
+ * Error code indicating an unexpected condition in the service, i.e. programming error.
+ */
+ final static int INTERNAL_ERROR = 10005;
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java
new file mode 100644
index 00000000000..6176514e775
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Executor that executes a runnable immediately as it is submitted. This
+ * executor is useful for clients that need to create <code>RequestMonitor</code>
+ * objects, but which do not have their own executor.
+ * @see RequestMonitor
+ */
+public class ImmediateExecutor implements Executor {
+
+ /**
+ * Debug flag used for tracking runnables that were never executed,
+ * or executed multiple times.
+ */
+ protected static boolean DEBUG_EXECUTOR = false;
+ static {
+ DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
+ }
+
+ private static ImmediateExecutor fInstance = new ImmediateExecutor();
+
+ /**
+ * The default constructor is hidden. {@link #getInstance()} should be
+ * used instead.
+ */
+ private ImmediateExecutor() {}
+
+ /**
+ * Returns the singleton instance of ImmediateExecutor.
+ */
+ public static Executor getInstance() {
+ return fInstance;
+ }
+
+ public void execute(Runnable command) {
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && command instanceof DsfExecutable) {
+ assert !((DsfExecutable)command).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)command).setSubmitted();
+ }
+ command.run();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java
new file mode 100644
index 00000000000..a336b893792
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given class is immutable and thus thread-safe.
+ * This annotation is not automatically inherited by sub-classes, since
+ * sub-classes need to make sure that they are immutable as well.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface Immutable {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java
new file mode 100644
index 00000000000..ba127835243
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.MultiStatus;
+
+/**
+ * Utility class to collect multiple request monitor results of commands
+ * that are initiated simultaneously. The usage is as follows:
+ * <pre>
+ * final MultiRequestMonitor multiRequestMon = new MultiRequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println("All complete, errors=" + !getStatus().isOK());
+ * }
+ * };
+ *
+ * for (int i = 0; i < 10; i++) {
+ * service.call(i, multiRequestMon.addRequestMonitor(
+ * new RequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println(Integer.toString(i) + " complete");
+ * multiRequestMon.requestMonitorDone(this);
+ * }
+ * }));
+ * }
+ * </pre>
+ */
+public class MultiRequestMonitor<V extends RequestMonitor> extends RequestMonitor {
+ private List<V> fRequestMonitorList = new LinkedList<V>();
+ private Map<V,Boolean> fStatusMap = new HashMap<V,Boolean>();
+ private int fDoneCounter;
+
+ public MultiRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Adds a new RequestMonitor callback to this tracker's list.
+ * @param <T> Client-specific class of the RequestMonitor callback, it's used here to avoid an
+ * unnecessary cast by the client.
+ * @param rm Request monitor object to add to the tracker
+ * @return The request monitor that was just added, it allows this method to be used
+ * inlined in service method calls
+ */
+ public <T extends V> T add(T rm) {
+ assert !fStatusMap.containsKey(rm);
+ fRequestMonitorList.add(rm);
+ fStatusMap.put(rm, false);
+ fDoneCounter++;
+ return rm;
+ }
+
+ /**
+ * Marks the given RequestMonitor callback as completed. Client implementations of
+ * the RequestMonitor callback have to call this method in order for the tracker
+ * to complete.
+ * <br>
+ * @param requestMonitor
+ */
+ public synchronized void requestMonitorDone(V requestMonitor) {
+ if (getStatus() instanceof MultiStatus) {
+ ((MultiStatus)getStatus()).merge(requestMonitor.getStatus());
+ }
+ assert fStatusMap.containsKey(requestMonitor);
+ fStatusMap.put(requestMonitor, true);
+ assert fDoneCounter > 0;
+ fDoneCounter--;
+ if (fDoneCounter == 0) {
+ assert !fStatusMap.containsValue(false);
+ super.done();
+ }
+ }
+
+ /**
+ * Returns the list of requested monitors, sorted in order as they were added.
+ */
+ public List<V> getRequestMonitors() {
+ return fRequestMonitorList;
+ }
+
+ /**
+ * Returns true if given monitor is finished.
+ */
+ public boolean isRequestMonitorDone(V rm) {
+ return fStatusMap.get(rm);
+ }
+
+ @Override
+ public String toString() {
+ return "Multi-RequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java
new file mode 100644
index 00000000000..eff2c70c5b4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+import org.eclipse.core.runtime.CoreException;
+
+
+/**
+ * A convenience class that allows a client to retrieve data from services
+ * synchronously from a non-dispatch thread. This class is different from
+ * a Callable<V> in that it allows the implementation code to calculate
+ * the result in several dispatches, rather than requiring it to return the
+ * data at end of Callable#call method.
+ * <p>
+ * Usage:<br/>
+ * <pre>
+ * class DataQuery extends Query<Data> {
+ * protected void execute(DataRequestMonitor<Data> rm) {
+ * rm.setData(fSlowService.getData());
+ * rm.done();
+ * }
+ * }
+ *
+ * DsfExecutor executor = getExecutor();
+ * DataQuery query = new DataQuery();
+ * executor.submit(query);
+ *
+ * try {
+ * Data data = query.get();
+ * }
+ *
+ * </pre>
+ * <p>
+ * @see java.util.concurrent.Callable
+ */
+@ThreadSafe
+abstract public class Query<V> extends DsfRunnable
+ implements Future<V>
+{
+ /** The synchronization object for this query */
+ private final Sync fSync = new Sync();
+
+ /**
+ * The Query constructor no longer requires an executor to be specified.
+ * This executor was used to contruct the DataRequestMonitor argument to the
+ * {@link #execute(DataRequestMonitor)} method. But a simplification in the
+ * RequestMonitor object, made this unnecessary.
+ * @param executor
+ */
+ @Deprecated
+ public Query(DsfExecutor executor) {
+ }
+
+ /**
+ * The no-argument constructor
+ */
+ public Query() {}
+
+ public V get() throws InterruptedException, ExecutionException { return fSync.doGet(); }
+
+ public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return fSync.doGet(unit.toNanos(timeout));
+ }
+
+ /**
+ * Don't try to interrupt the DSF executor thread, just ignore the request
+ * if set.
+ */
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return fSync.doCancel();
+ }
+
+ public boolean isCancelled() { return fSync.doIsCancelled(); }
+
+ public boolean isDone() { return fSync.doIsDone(); }
+
+
+ protected void doneException(Throwable t) {
+ fSync.doSetException(t);
+ }
+
+ abstract protected void execute(DataRequestMonitor<V> rm);
+
+ public void run() {
+ if (fSync.doRun()) {
+ try {
+ /*
+ * Create the executor which is going to handle the completion of the
+ * request monitor. Normally a DSF executor is supplied here which
+ * causes the request monitor to be invoked in a new dispatch loop.
+ * But since the query is a synchronization object, it can handle
+ * the completion of the request in any thread.
+ * Avoiding the use of a DSF executor is very useful because queries are
+ * meant to be used by clients calling from non-dispatch thread, and there
+ * is a chance that a client may execute a query just as a session is being
+ * shut down. In that case, the DSF executor may throw a
+ * RejectedExecutionException which would have to be handled by the query.
+ */
+ execute(new DataRequestMonitor<V>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ public void handleCompleted() {
+ if (isSuccess()) fSync.doSet(getData());
+ else fSync.doSetException(new CoreException(getStatus()));
+ }
+ });
+ } catch(Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute. It will not work in cases when
+ * the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ fSync.doSetException(t);
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ final class Sync extends AbstractQueuedSynchronizer {
+ private static final int STATE_RUNNING = 1;
+ private static final int STATE_DONE = 2;
+ private static final int STATE_CANCELLED = 4;
+
+ private V fResult;
+ private Throwable fException;
+
+ private boolean ranOrCancelled(int state) {
+ return (state & (STATE_DONE | STATE_CANCELLED)) != 0;
+ }
+
+ @Override
+ protected int tryAcquireShared(int ignore) {
+ return doIsDone()? 1 : -1;
+ }
+
+ @Override
+ protected boolean tryReleaseShared(int ignore) {
+ return true;
+ }
+
+ boolean doIsCancelled() {
+ return getState() == STATE_CANCELLED;
+ }
+
+ boolean doIsDone() {
+ return ranOrCancelled(getState());
+ }
+
+ V doGet() throws InterruptedException, ExecutionException {
+ acquireSharedInterruptibly(0);
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ return fResult;
+ }
+
+ V doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ return fResult;
+ }
+
+ void doSet(V v) {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return;
+ if (compareAndSetState(s, STATE_DONE)) break;
+ }
+ fResult = v;
+ releaseShared(0);
+ }
+
+ void doSetException(Throwable t) {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return;
+ if (compareAndSetState(s, STATE_DONE)) break;
+ }
+ fException = t;
+ fResult = null;
+ releaseShared(0);
+ }
+
+ boolean doCancel() {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return false;
+ if (compareAndSetState(s, STATE_CANCELLED)) break;
+ }
+ releaseShared(0);
+ return true;
+ }
+
+ boolean doRun() {
+ return compareAndSetState(0, STATE_RUNNING);
+ }
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java
new file mode 100644
index 00000000000..ac5b466e94e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Used to monitor the result of an asynchronous request. Because of the
+ * asynchronous nature of DSF code, a very large number of methods needs to
+ * signal the result of an operation through a call-back. This class is the base
+ * class for such call backs.
+ * <p>
+ * The intended use of this class, is that a client who is calling an asynchronous
+ * method, will sub-class RequestMonitor, and implement the method {@link #handleCompleted()},
+ * or any of the other <code>handle...</code> methods, in order to interpret the
+ * results of the request. The object implementing the asynchronous method is required
+ * to call the {@link #done()} method on the request monitor object that it received
+ * as an argument.
+ * </p>
+ * <p>
+ * The severity of the {@link IStatus> returned by #getStatus() can be used to
+ * determine the success or failure of the asynchronous operation. By convention
+ * the error codes returned by asynchronous method should be interpreted as follows:
+ * <ul>
+ * <li>OK and INFO - Result is a success. In DataRequestMonitor, getData() should
+ * return a value.</li>
+ * <li>WARNING - Acceptable error condition (getData() may return null). Where for
+ * example user tried to retrieve variable data, but the program resumed in the
+ * mean time and an event will be generated shortly which will clear the variables
+ * view.</li>
+ * <li>ERROR - An error condition that should probably be reported to the user.</li>
+ * <li>CANCEL - The request was canceled, and the asynchronous method was not
+ * completed.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The RequestMonitor constructor accepts an optional "parent" request monitor. If a
+ * parent monitor is specified, it will automatically be invoked by this monitor when
+ * the request is completed. The parent option is useful when implementing a method
+ * which is asynchronous (and accepts a request monitor as an argument) and which itself
+ * calls another asynchronous method to complete its operation. For example, in the
+ * request monitor implementation below, the implementation only needs to override
+ * <code>handleOK()</code>, because the base implementation will handle notifying the
+ * parent <code>rm</code> in case the <code>getIngredients()</code> call fails.
+ * <pre>
+ * public void createCupCakes(final DataRequestMonitor<CupCake[]> rm) {
+ * getIngredients(new DataRequestMonitor<Ingredients>(fExecutor, rm) {
+ * public void handleOK() {
+ * rm.setData( new CupCake(getData().getFlour(), getData().getSugar(),
+ * getData().getBakingPowder()));
+ * rm.done();
+ * }
+ * });
+ * }
+ * </pre>
+ * </p>
+ */
+@ThreadSafe
+public class RequestMonitor {
+
+ /**
+ * Interface used by RequestMonitor to notify when a given request monitor
+ * is canceled.
+ *
+ * @see RequestMonitor
+ */
+ public static interface ICanceledListener {
+
+ /**
+ * Called when the given request monitor is canceled.
+ */
+ public void requestCanceled(RequestMonitor rm);
+ }
+
+ /**
+ * The executor that will be used in order to invoke the handler of the results
+ * of the request.
+ */
+ private final Executor fExecutor;
+
+ /**
+ * The request monitor which was used to call into the method that created this
+ * monitor.
+ */
+ private final RequestMonitor fParentRequestMonitor;
+
+ private ListenerList fCancelListeners;
+
+ /**
+ * Status
+ */
+ private IStatus fStatus = Status.OK_STATUS;
+ private boolean fCanceled = false;
+ private boolean fDone = false;
+
+ /**
+ * Constructor with an optional parent monitor.
+ * @param executor This executor will be used to invoke the runnable that
+ * will allow processing the completion code of this request monitor.
+ * @param parentRequestMonitor The optional parent request monitor to be invoked by
+ * default when this request completes. Parameter may be null.
+ */
+ public RequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ fExecutor = executor;
+ fParentRequestMonitor = parentRequestMonitor;
+
+ // If the parent rm is not null, add ourselves as a listener so that
+ // this request monitor will automatically be canceled when the parent
+ // is canceled.
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.addCancelListener(
+ new ICanceledListener() {
+ public void requestCanceled(RequestMonitor rm) {
+ cancel();
+ }
+ });
+ }
+ }
+
+ /**
+ * Sets the status of the result of the request. If status is OK, this
+ * method does not need to be called.
+ */
+ public synchronized void setStatus(IStatus status) {
+ assert isCanceled() || status.getSeverity() != IStatus.CANCEL;
+ fStatus = status;
+ }
+
+ /** Returns the status of the completed method. */
+ public synchronized IStatus getStatus() {
+ if (isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ return fStatus;
+ }
+
+ /**
+ * Sets this request monitor as canceled and calls the cancel listeners if any.
+ * <p>
+ * Note: Calling cancel() does not automatically complete the RequestMonitor.
+ * The asynchronous call still has to call done().
+ * </p>
+ * <p>
+ * Note: logically a request should only be canceled by the client that issued
+ * the request in the first place. After a request is canceled, the method
+ * that is fulfilling the request may call {@link #setStatus(IStatus)} with
+ * severity of <code>IStatus.CANCEL</code> to indicate that it recognized that
+ * the given request was canceled and it did not perform the given operation.
+ * </p>
+ */
+ public void cancel() {
+ Object[] listeners = null;
+ synchronized (this) {
+ // Check to make sure the request monitor wasn't previously canceled.
+ if (!fCanceled) {
+ fCanceled = true;
+ if (fCancelListeners != null) {
+ listeners = fCancelListeners.getListeners();
+ }
+ }
+ }
+
+ // Call the listeners outside of a synchronized section to reduce the
+ // risk of deadlocks.
+ if (listeners != null) {
+ for (Object listener : listeners) {
+ ((ICanceledListener)listener).requestCanceled(this);
+ }
+ }
+ }
+
+ /**
+ * Returns whether the request was canceled. Even if the request is
+ * canceled by the client, the implementor handling the request should
+ * still call {@link #done()} in order to complete handling
+ * of the request monitor.
+ */
+ public synchronized boolean isCanceled() {
+ return fCanceled || (fParentRequestMonitor != null && fParentRequestMonitor.isCanceled());
+ }
+
+ /**
+ * Adds the given listener to list of listeners that are notified when this
+ * request monitor is canceled.
+ */
+ public synchronized void addCancelListener(ICanceledListener listener) {
+ if (fCancelListeners == null) {
+ fCancelListeners = new ListenerList();
+ }
+ fCancelListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners that are notified
+ * when this request monitor is canceled.
+ */
+ public synchronized void removeCancelListener(ICanceledListener listener) {
+ if (fCancelListeners != null) {
+ fCancelListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Marks this request as completed. Once this method is called, the
+ * monitor submits a runnable to the DSF Executor to call the
+ * <code>handle...</code> methods.
+ * <p>
+ * Note: This method should be called once and only once, for every request
+ * issued. Even if the request was canceled.
+ * </p>
+ */
+ public synchronized void done() {
+ if (fDone) {
+ throw new IllegalStateException("RequestMonitor: " + this + ", done() method called more than once"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ fDone = true;
+ try {
+ fExecutor.execute(new DsfRunnable() {
+ public void run() {
+ RequestMonitor.this.handleCompleted();
+ }
+ @Override
+ public String toString() {
+ return "Completed: " + RequestMonitor.this.toString(); //$NON-NLS-1$
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ handleRejectedExecutionException();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RequestMonitor (" + super.toString() + "): " + getStatus().toString(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Checks whether the given request monitor completed with success or
+ * failure result. If the request monitor was canceled it is considered
+ * that it failed, regardless of the status.
+ */
+ public boolean isSuccess() {
+ return !isCanceled() && getStatus().getSeverity() <= IStatus.INFO;
+ }
+
+ /**
+ * Default handler for the completion of a request. The implementation
+ * calls {@link #handleSuccess()} if the request succeeded, and calls
+ * {@link #handleFailure()} or cancel otherwise.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ handleSuccess();
+ } else {
+ handleFailure();
+ }
+ }
+
+ /**
+ * Default handler for a successful the completion of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is notified. Otherwise this method does nothing.
+ * {@link #handleFailure()} or cancel otherwise.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleSuccess() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * The default implementation of a cancellation or an error result of a
+ * request. The implementation delegates to {@link #handleCancel()} and
+ * {@link #handleErrorOrWarning()} as needed.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleFailure() {
+ assert !isSuccess();
+
+ if (isCanceled()) {
+ handleCancel();
+ } else {
+ if (getStatus().getSeverity() == IStatus.CANCEL) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request monitor: '" + this + "' resulted in a cancel status: " + getStatus() + ", even though the request is not set to cancel.", null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ handleErrorOrWarning();
+ }
+ }
+
+ /**
+ * The default implementation of an error or warning result of a request.
+ * The implementation delegates to {@link #handleError()} and
+ * {@link #handleWarning()} as needed.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleErrorOrWarning() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ handleError();
+ } else {
+ handleWarning();
+ }
+ }
+
+ /**
+ * The default implementation of an error result of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is configured with a new status containing this error.
+ * Otherwise the error is logged.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleError() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(getStatus());
+ fParentRequestMonitor.done();
+ } else {
+ MultiStatus logStatus = new MultiStatus(DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in an error.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ logStatus.merge(getStatus());
+ DsfPlugin.getDefault().getLog().log(logStatus);
+ }
+ }
+
+ /**
+ * The default implementation of an error result of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is configured with a new status containing this warning.
+ * Otherwise the warning is logged.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleWarning() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(getStatus());
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * Default handler for a canceled the completion of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is notified. Otherwise this method does nothing.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleCancel() {
+ if (fParentRequestMonitor != null) {
+ if (getStatus().getSeverity() == IStatus.CANCEL && !fParentRequestMonitor.isCanceled()) {
+ fParentRequestMonitor.setStatus(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Sub-request " + toString() + " was canceled and not handled.'", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ fParentRequestMonitor.setStatus(getStatus());
+ }
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * Default handler for when the executor supplied in the constructor
+ * rejects the runnable that is submitted invoke this request monitor.
+ * This usually happens only when the executor is shutting down.
+ */
+ protected void handleRejectedExecutionException() {
+ MultiStatus logStatus = new MultiStatus(DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ logStatus.merge(getStatus());
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(logStatus);
+ fParentRequestMonitor.done();
+ } else {
+ DsfPlugin.getDefault().getLog().log(logStatus);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java
new file mode 100644
index 00000000000..7cdd2719799
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A request monitor which uses a progress monitor as a parent. When the parent
+ * progress monitor is canceled, the request monitor will also be canceled,
+ * although the cancellation listeners will not be called.
+ *
+ * @since 1.1
+ */
+public class RequestMonitorWithProgress extends RequestMonitor {
+
+ private final IProgressMonitor fProgressMonitor;
+
+ public RequestMonitorWithProgress(Executor executor, IProgressMonitor progressMonitor) {
+ super(executor, null);
+ fProgressMonitor = progressMonitor;
+ }
+
+ public IProgressMonitor getProgressMonitor() {
+ return fProgressMonitor;
+ }
+
+ @Override
+ public synchronized boolean isCanceled() {
+ return super.isCanceled() || fProgressMonitor.isCanceled();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java
new file mode 100644
index 00000000000..334a7c69e4e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Nokia - added StepWithProgress. Oct, 2008
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor.ICanceledListener;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * Convenience class for implementing a series of commands that need to be
+ * executed asynchronously.
+ * <p>
+ * Certain complex tasks require multiple commands to be executed in a chain,
+ * because for example result of one command is used as input into another
+ * command. The typical DSF pattern of solving this problem is the following:
+ * <li>
+ * <br> 1. original caller passes a RequestMonitor callback to a method and invokes it
+ * <br> 2. the method is executed by a subsystem
+ * <br> 3. when the method is finished it calls another method and passes
+ * the original callback to it
+ * <br> 4. steps 2-3 are repeated number of times
+ * <br> 5. when the last method in a chain is executed, it submits the original
+ * RequestMonitor callback
+ * </li>
+ * <p>
+ * This pattern is very useful in itself, but it proves very difficult to follow
+ * because the methods can be scattered accross many classes and systems. Also
+ * if progress reporting, cancellability, and roll-back ability is required, it
+ * has to be re-implemented every time. The Sequence class tries to address
+ * this problem by containing this pattern in a single class.
+ */
+@ThreadSafe
+abstract public class Sequence extends DsfRunnable implements Future<Object> {
+
+ /**
+ * The abstract class that each step has to implement.
+ */
+ abstract public static class Step {
+ private Sequence fSequence;
+
+ /**
+ * Sets the sequence that this step belongs to. It is only accessible
+ * by the sequence itself, and is not meant to be called by sequence
+ * sub-classes.
+ */
+ void setSequence(Sequence sequence) { fSequence = sequence; }
+
+ /** Returns the sequence that this step is running in. */
+ public Sequence getSequence() { return fSequence; }
+
+ /**
+ * Executes the step. Overriding classes should perform the
+ * work in this method.
+ * @param rm Result token to submit to executor when step is finished.
+ */
+ public void execute(RequestMonitor rm) {
+ rm.done();
+ }
+
+ /**
+ * Roll back gives the step implementation a chance to undo the
+ * operation that was performed by execute().
+ * <br>
+ * Note if the {@link #execute(RequestMonitor)} call completes with a
+ * non-OK status, then rollBack will not be called for that step.
+ * Instead it will be called for the previous step.
+ * @param rm Result token to submit to executor when rolling back the step is finished.
+ */
+ public void rollBack(RequestMonitor rm) {
+ rm.done();
+ }
+
+ /**
+ * Returns the number of progress monitor ticks corresponding to this
+ * step.
+ */
+ public int getTicks() { return 1; }
+
+ /**
+ * Task name for this step. This will be displayed in the label of the
+ * progress monitor of the owner sequence.
+ *
+ * @return name of the task carried out by the step, can be
+ * <code>null</code>, in which case the overall task name will be used.
+ *
+ * @since 1.1
+ */
+ public String getTaskName() {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * A step that will report execution progress by itself on the progress
+ * monitor of the owner sequence.<br>
+ * <br>
+ * Note we don't offer a rollBack(RequestMonitor, IProgressMonitor) as we
+ * don't want end user to be able to cancel the rollback.
+ *
+ * @since 1.1
+ */
+ abstract public static class StepWithProgress extends Step {
+
+ @Override
+ // don't allow subclass to implement this by "final" it.
+ final public void execute(RequestMonitor rm) {
+ assert false : "execute(RequestMonitor rm, IProgressMonitor pm) should be called instead"; //$NON-NLS-1$
+ }
+
+ /**
+ * Execute the step with a progress monitor. Note the given progress
+ * monitor is a sub progress monitor of the owner sequence which is
+ * supposed to be fully controlled by the step. Namely the step should
+ * call beginTask() and done() of the monitor.
+ *
+ * @param rm
+ * @param pm
+ */
+ public void execute(RequestMonitor rm, IProgressMonitor pm) {
+ rm.done();
+ pm.done();
+ }
+ }
+
+ /** The synchronization object for this future */
+ final Sync fSync = new Sync();
+
+ /**
+ * Executor that this sequence is running in. It is used by the sequence
+ * to submit the runnables for steps, and for submitting the result.
+ */
+ final private DsfExecutor fExecutor;
+
+ /**
+ * Result callback to invoke when the sequence is finished. Intended to
+ * be used when the sequence is created and invoked from the executor
+ * thread. Otherwise, the {@link Future#get()} method is the appropriate
+ * method of retrieving the result.
+ */
+ final private RequestMonitor fRequestMonitor;
+
+ /** Status indicating the success/failure of the test. Used internally only. */
+ @ConfinedToDsfExecutor("getExecutor")
+ private IStatus fStatus = Status.OK_STATUS;
+
+ @ConfinedToDsfExecutor("getExecutor")
+ private int fCurrentStepIdx = 0;
+
+ /** Task name for this sequence used with the progress monitor */
+ final private String fTaskName;
+
+ /** Task name used when the sequence is being rolled back. */
+ final private String fRollbackTaskName;
+
+ final private IProgressMonitor fProgressMonitor;
+
+ /** Convenience constructor with limited arguments. */
+ public Sequence(DsfExecutor executor) {
+ this(executor, new NullProgressMonitor(), "", "", null); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Creates a sequence with a request monitor. If the client cancels the
+ * request monitor, then the request monitors in the
+ * {@link Step#execute(RequestMonitor)}
+ * implementations will immediately call the cancel listeners to notify.
+ *
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param rm The request monitor which will be invoked when the sequence
+ * is completed.
+ */
+ public Sequence(DsfExecutor executor, RequestMonitor rm) {
+ this(executor, new NullProgressMonitor(), "", "", rm); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Creates a sequence with a progress monitor. If the progress monitor is
+ * canceled, then request monitors in the
+ * {@link Step#execute(RequestMonitor)} implementations will need to call
+ * rm.isCanceled() to discover the cancellation.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param pm Progress monitor for monitoring this sequence.
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ *
+ * @since 1.1
+ */
+ public Sequence(DsfExecutor executor, IProgressMonitor pm, String taskName, String rollbackTaskName) {
+ this(executor, pm, taskName, rollbackTaskName, new RequestMonitorWithProgress(ImmediateExecutor.getInstance(), pm));
+ }
+
+ /**
+ * Creates a sequence with a request monitor that includes a progress
+ * monitor.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param rm The request monitor containing the progress monitor
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ *
+ * @since 1.1
+ */
+ public Sequence(DsfExecutor executor, RequestMonitorWithProgress rm, String taskName, String rollbackTaskName) {
+ this(executor, rm.getProgressMonitor(), taskName, rollbackTaskName, rm);
+ }
+
+ /**
+ * Constructor that initialized the steps and the result callback.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param pm Progress monitor for monitoring this sequence. This
+ * parameter cannot be null.
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ * @param Result that will be submitted to executor when sequence is
+ * finished. Can be null if calling from non-executor thread and using
+ * {@link Future#get()} method to wait for the sequence result.
+ *
+ * @deprecated This constructor should not be used because it creates a
+ * potential ambiguity when one of the two monitors is canceled.
+ */
+ @Deprecated
+ public Sequence(DsfExecutor executor, IProgressMonitor pm, String taskName, String rollbackTaskName, RequestMonitor rm) {
+ fExecutor = executor;
+ fProgressMonitor = pm;
+ fTaskName = taskName;
+ fRollbackTaskName = rollbackTaskName;
+ fRequestMonitor = rm;
+
+ if (fRequestMonitor != null) {
+ fRequestMonitor.addCancelListener(new ICanceledListener() {
+ public void requestCanceled(RequestMonitor rm) {
+ fSync.doCancel();
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns the steps to be executed. It is up to the deriving class to
+ * supply the steps and to ensure that the list of steps will not be
+ * modified after the sequence is constructed.
+ * <p>
+ * Steps are purposely not accepted as part of the DsfConstructor, in
+ * order to allow deriving classes to create the steps as a field. And a
+ * setSteps() method is not provided, to guarantee that the steps will not
+ * be modified once set (perhaps this is a bit paranoid, but oh well).
+ */
+ abstract public Step[] getSteps();
+
+
+ /** Returns the DSF executor for this sequence */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Returns the RequestMonitor callback that is registered with the Sequence
+ */
+ public RequestMonitor getRequestMonitor() { return fRequestMonitor; }
+
+ /**
+ * The get method blocks until sequence is complete, but always returns null.
+ * @see java.concurrent.Future#get
+ */
+ public Object get() throws InterruptedException, ExecutionException {
+ fSync.doGet();
+ return null;
+ }
+
+ /**
+ * The get method blocks until sequence is complete or until timeout is
+ * reached, but always returns null.
+ * @see java.concurrent.Future#get
+ */
+ public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ fSync.doGet();
+ return null;
+ }
+
+ /**
+ * Don't try to interrupt the DSF executor thread, just ignore the request
+ * if set.
+ * <p>If a request monitor was specified when creating a sequence, that
+ * request monitor will be canceled by this method as well. The client
+ * can also use the request monitor's cancel method to cancel the sequence.
+ *
+ * @see RequestMonitor#cancel()
+ */
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ // Cancel the request monitor first, to avoid a situation where
+ // the request monitor is not canceled but the status is set
+ // to canceled.
+ if (fRequestMonitor != null) {
+ fRequestMonitor.cancel();
+ }
+ return fSync.doCancel();
+ }
+
+ public boolean isCancelled() { return fSync.doIsCancelled(); }
+
+ public boolean isDone() { return fSync.doIsDone(); }
+
+
+ public void run() {
+ // Change the state to running.
+ if (fSync.doRun()) {
+ // Set the reference to this sequence in each step.
+ int totalTicks = 0;
+ for (Step step : getSteps()) {
+ step.setSequence(this);
+ totalTicks += step.getTicks();
+ }
+
+ // Set the task name
+ if (fTaskName != null) {
+ fProgressMonitor.beginTask(fTaskName, totalTicks);
+ }
+
+ // Call the first step
+ executeStep(0);
+ } else {
+ fSync.doFinish();
+ }
+ }
+
+ /**
+ * To be called only by the step implementation, Tells the sequence to
+ * submit the next step.
+ */
+ private void executeStep(int nextStepIndex) {
+ /*
+ * At end of each step check progress monitor to see if it's cancelled.
+ * If progress monitor is cancelled, mark the whole sequence as
+ * cancelled.
+ */
+ if (fProgressMonitor.isCanceled()) {
+ cancel(false);
+ }
+
+ /*
+ * If sequence was cencelled during last step (or before the sequence
+ * was ever executed), start rolling back the execution.
+ */
+ if (isCancelled()) {
+ cancelExecution();
+ return;
+ }
+
+ /*
+ * Check if we've reached the last step. Note that if execution was
+ * cancelled during the last step (and thus the sequence is
+ * technically finished, since it was cancelled it will be rolled
+ * back.
+ */
+ if (nextStepIndex >= getSteps().length) {
+ finish();
+ return;
+ }
+
+ // Proceed with executing next step.
+ fCurrentStepIdx = nextStepIndex;
+ try {
+ Step currentStep = getSteps()[fCurrentStepIdx];
+ final boolean stepControlsProgress = (currentStep instanceof StepWithProgress);
+
+ RequestMonitor rm = new RequestMonitor(fExecutor, fRequestMonitor) {
+ final private int fStepIdx = fCurrentStepIdx;
+
+ @Override
+ public void handleSuccess() {
+ // Check if we're still the correct step.
+ assert fStepIdx == fCurrentStepIdx;
+ if (!stepControlsProgress) {
+ // then sequence handles the progress report.
+ fProgressMonitor.worked(getSteps()[fStepIdx].getTicks());
+ }
+ executeStep(fStepIdx + 1);
+ }
+
+ @Override
+ protected void handleCancel() {
+ Sequence.this.cancel(false);
+ cancelExecution();
+ };
+
+ @Override
+ protected void handleErrorOrWarning() {
+ abortExecution(getStatus());
+ };
+
+ @Override
+ public String toString() {
+ return "Sequence \"" + fTaskName + "\", result for executing step #" + fStepIdx + " = " + getStatus(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ };
+
+ fProgressMonitor.subTask(currentStep.getTaskName());
+
+ if (stepControlsProgress) {
+
+ // Create a sub-monitor that will be controlled by the step.
+ SubProgressMonitor subMon = new SubProgressMonitor(fProgressMonitor, currentStep.getTicks(),
+ SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+
+ ((StepWithProgress) currentStep).execute(rm, subMon);
+ } else { // regular Step
+ currentStep.execute(rm);
+ }
+
+ } catch (Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute method. It will not work in cases
+ * when the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ abortExecution(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
+ "Unhandled exception when executing Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
+ t));
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+
+ /**
+ * To be called only by the step implementation. Tells the sequence to
+ * roll back next step.
+ */
+ private void rollBackStep(int stepIdx) {
+ // If we reach before step 0, finish roll back.
+ if (stepIdx < 0) {
+ finish();
+ return;
+ }
+
+ // Proceed with rolling back given step.
+ fCurrentStepIdx = stepIdx;
+ try {
+ getSteps()[fCurrentStepIdx].rollBack(new RequestMonitor(fExecutor, null) {
+ final private int fStepIdx = fCurrentStepIdx;
+ @Override
+ public void handleCompleted() {
+ // Check if we're still the correct step.
+ assert fStepIdx == fCurrentStepIdx;
+
+ // Proceed to the next step.
+ if (isSuccess()) {
+ // NOTE: The getTicks() is ticks for executing the step,
+ // not for rollBack,
+ // though it does not really hurt to use it here.
+ fProgressMonitor.worked(getSteps()[fStepIdx].getTicks());
+
+ rollBackStep(fStepIdx - 1);
+ } else {
+ abortRollBack(getStatus());
+ }
+ }
+ @Override
+ public String toString() {
+ return "Sequence \"" + fTaskName + "\", result for rolling back step #" + fStepIdx + " = " + getStatus(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ });
+ } catch(Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute method. It will not work in cases
+ * when the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ abortRollBack(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
+ "Unhandled exception when rolling back Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
+ t));
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+
+ /**
+ * Tells the sequence that its execution is to be aborted and it
+ * should start rolling back the sequence as if it was cancelled by user.
+ */
+ private void cancelExecution() {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+ fStatus = new Status(IStatus.CANCEL, DsfPlugin.PLUGIN_ID, -1, "Sequence \"" + fTaskName + "\" cancelled.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(fStatus);
+ }
+
+ /*
+ * No need to call fSync, it should have been taken care of by
+ * Future#cancel method.
+ *
+ * Note that we're rolling back starting with the current step,
+ * because the current step was fully executed. This is unlike
+ * abortExecution() where the current step caused the roll-back.
+ */
+ rollBackStep(fCurrentStepIdx);
+ }
+
+ /**
+ * Tells the sequence that its execution is to be aborted and it
+ * should start rolling back the sequence as if it was cancelled by user.
+ */
+ private void abortExecution(final IStatus error) {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+ fStatus = error;
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(error);
+ }
+ fSync.doAbort(new CoreException(error));
+
+ // Roll back starting with previous step, since current step failed.
+ rollBackStep(fCurrentStepIdx - 1);
+ }
+
+ /**
+ * Tells the sequence that that is rolling back, to abort roll back, and
+ * notify the clients.
+ */
+ private void abortRollBack(final IStatus error) {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+
+ /*
+ * Compose new status based on previous status information and new
+ * error information.
+ */
+ MultiStatus newStatus =
+ new MultiStatus(DsfPlugin.PLUGIN_ID, error.getCode(),
+ "Sequence \"" + fTaskName + "\" failed while rolling back.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ newStatus.merge(error);
+ newStatus.merge(fStatus);
+ fStatus = newStatus;
+
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(newStatus);
+ }
+
+ finish();
+ }
+
+ private void finish() {
+ if (fRequestMonitor != null) fRequestMonitor.done();
+ fSync.doFinish();
+ }
+
+ @SuppressWarnings("serial")
+ final class Sync extends AbstractQueuedSynchronizer {
+ private static final int STATE_RUNNING = 1;
+ private static final int STATE_FINISHED = 2;
+ private static final int STATE_ABORTING = 4;
+ private static final int STATE_ABORTED = 8;
+ private static final int STATE_CANCELLING = 16;
+ private static final int STATE_CANCELLED = 32;
+
+ private Throwable fException;
+
+ private boolean isFinished(int state) {
+ return (state & (STATE_FINISHED | STATE_CANCELLED | STATE_ABORTED)) != 0;
+ }
+
+ @Override
+ protected int tryAcquireShared(int ignore) {
+ return doIsDone()? 1 : -1;
+ }
+
+ @Override
+ protected boolean tryReleaseShared(int ignore) {
+ return true;
+ }
+
+ boolean doIsCancelled() {
+ int state = getState();
+ return (state & (STATE_CANCELLING | STATE_CANCELLED)) != 0;
+ }
+
+ boolean doIsDone() {
+ return isFinished(getState());
+ }
+
+ void doGet() throws InterruptedException, ExecutionException {
+ acquireSharedInterruptibly(0);
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ }
+
+ void doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ }
+
+ void doAbort(Throwable t) {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return;
+ if (compareAndSetState(s, STATE_ABORTING)) break;
+ }
+ fException = t;
+ }
+
+ boolean doCancel() {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return false;
+ if (s == STATE_ABORTING) return false;
+ if (compareAndSetState(s, STATE_CANCELLING)) break;
+ }
+ return true;
+ }
+
+ void doFinish() {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return;
+ if (s == STATE_ABORTING) {
+ if (compareAndSetState(s, STATE_ABORTED)) break;
+ } else if (s == STATE_CANCELLING) {
+ if (compareAndSetState(s, STATE_CANCELLED)) break;
+ } else {
+ if (compareAndSetState(s, STATE_FINISHED)) break;
+ }
+ }
+ releaseShared(0);
+ }
+
+ boolean doRun() {
+ return compareAndSetState(0, STATE_RUNNING);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java
new file mode 100644
index 00000000000..b48d69afa7b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.concurrent;
+
+/**
+ * Untility class for easy pretty-printing stack traces. Local to the
+ * concurrent package.
+ */
+@Immutable
+class StackTraceWrapper {
+ final StackTraceElement[] fStackTraceElements;
+
+ StackTraceWrapper(StackTraceElement[] elements) { fStackTraceElements = elements; }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(fStackTraceElements.length * 30);
+ for (int i = 0; i < fStackTraceElements.length && i < 10; i++) {
+ builder.append(fStackTraceElements[i]);
+ if (i < fStackTraceElements.length && i < 10) builder.append("\n at "); //$NON-NLS-1$
+ }
+ return builder.toString();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java
new file mode 100644
index 00000000000..5ebcdec963a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, or field can be
+ * access safely from any thread. If declared on package or type, a field
+ * or method could still be declared with an annotation indicating that it's
+ * not thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ThreadSafe {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java
new file mode 100644
index 00000000000..4f3188b468d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, can be accessed on
+ * any thread, except on the dispatch thread of given DsfExecutor.
+ * <br> This restriction is desirable if it is expected that the implementation
+ * behavior is to block the calling thread and execute a transaction using an
+ * executor. In this situation, if the call is made on the executor's dispach
+ * thread, the execution would dead-lock.
+ * <br>
+ * If declared on package or type, a field or method could still be declared
+ * with an annotation indicating that it's thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ *
+ * @param value The value indicates the method to use to obtain the executor.
+ * It should be null if it cannot be determined from the given object.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ThreadSafeAndProhibitedFromDsfExecutor {
+ String value();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java
new file mode 100644
index 00000000000..fd96e0d99f3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Base implementation of the IDMContext interface. There are two pieces of
+ * functionality here: <br>
+ * 1) The {@link #getAdapter(Class)} implementation which retrieves model
+ * adapters registered with the session. <br>
+ * 2) Methods to help compare DM Contexts. <br>
+ * <p>
+ * Note: The {@link #equals(Object)} and {@link #hashCode()} methods are
+ * made abstract to force the deriving classes to provide a proper
+ * implementation. Data Model Context objects are meant to be used as handles,
+ * therefore a proper equals implementation is critical.
+ * </p>
+ * @param <V> Data Model data type that this context is for.
+ */
+@Immutable
+abstract public class AbstractDMContext extends PlatformObject
+ implements IDMContext
+{
+ private final String fSessionId;
+ private final IDMContext[] fParents;
+
+ /**
+ * Main constructor provides all data needed to implement the IModelContext
+ * interface.
+ */
+ public AbstractDMContext(String sessionId, IDMContext[] parents) {
+ fSessionId = sessionId;
+ fParents = parents;
+ for (IDMContext parent : parents) {
+ assert(parent != null);
+ }
+ }
+
+ /** Convenience constructor */
+ public AbstractDMContext(IDsfService service, IDMContext[] parents) {
+ this(service.getSession().getId(), parents);
+ }
+
+ /**
+ * Should be used by the deriving class to compare the basic context object
+ * information.
+ * @param other the other service to compare to
+ * @return true if contexts are equal
+ */
+ protected boolean baseEquals(Object other) {
+ if (other == null) return false;
+ if ( !(other.getClass().equals(getClass()))) return false;
+ IDMContext otherCtx = (IDMContext)other;
+ return getSessionId().equals(otherCtx.getSessionId()) &&
+ areParentsEqual(otherCtx.getParents());
+ }
+
+ private boolean areParentsEqual(IDMContext[] otherParents) {
+ if ( !(fParents.length == otherParents.length) ) return false;
+ for (int i = 0; i < fParents.length; i++) {
+ if (!fParents[i].equals(otherParents[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected int baseHashCode() {
+ int parentsHash = 0;
+ for (Object parent : getParents()) {
+ parentsHash += parent.hashCode();
+ }
+ return getSessionId().hashCode() + parentsHash;
+ }
+
+ protected String baseToString() {
+ StringBuffer retVal = new StringBuffer();
+ for (IDMContext parent : fParents) {
+ retVal.append(parent);
+ }
+ return retVal.toString();
+ }
+
+ public String getSessionId() { return fSessionId; }
+ public IDMContext[] getParents() { return fParents; }
+
+ /**
+ * Overrides the standard platform getAdapter to provide session-specific
+ * adapters.
+ * <p>
+ * ModelContext is intended to be used in views, which call the
+ * contexts.getAdapter() method to retrieve model-specific content and
+ * label providers. But since many different sessions could be active
+ * at the same time, each requiring different content providers, the
+ * standard platform <code>IAdapterManager</code> is not sufficient in
+ * handling adapters for the model context object. This is because
+ * <code>IAdapterManager</code> uses only the class of the adaptable to
+ * select the correct adapter factoru, while for model context, the
+ * session is equally important.
+ * @see org.eclipse.runtime.IAdapterManager
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapterType) {
+ Object retVal = null;
+ DsfSession session = DsfSession.getSession(fSessionId);
+ if (session != null) {
+ retVal = session.getModelAdapter(adapterType);
+ }
+ if (retVal == null) {
+ retVal = super.getAdapter(adapterType);
+ }
+ return retVal;
+ }
+
+ /**
+ * Deriving classes must implement proper equals and hashCode operations
+ * based on context data.
+ */
+ @Override
+ abstract public boolean equals(Object obj);
+
+ /**
+ * Deriving classes must implement proper equals and hashCode operations
+ * based on context data.
+ */
+ @Override
+ abstract public int hashCode();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java
new file mode 100644
index 00000000000..296433e85fd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Base implementation of the IDMEvent interface. It only handles the
+ * required DM-Context reference.
+ */
+@Immutable
+abstract public class AbstractDMEvent<V extends IDMContext> implements IDMEvent<V> {
+
+ private final V fModelContext;
+ public AbstractDMEvent(V context) {
+ fModelContext = context;
+ }
+
+ public V getDMContext() {
+ return fModelContext;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java
new file mode 100644
index 00000000000..8f114e2dd44
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.datamodel;
+
+import java.util.Arrays;
+
+/**
+ * Generic DM context used to combine several DM Contexts. This object allows
+ * clients and other services to combine several contexts into one in order to
+ * pass them as an argument to a method which takes a generic context as an
+ * argument.
+ */
+public class CompositeDMContext implements IDMContext {
+
+ public static String INVALID_SESSION_ID = ""; //$NON-NLS-1$
+
+ /**
+ * The list of parent contexts that this composite context is made up of.
+ */
+ private final IDMContext[] fParents;
+
+ /**
+ * Main constructor provides all data needed to implement the IModelContext
+ * interface.
+ * @param parents Array of parent contexts that this composite context is
+ * made up of. It can be an empty array, but it cannot be null.
+ */
+ public CompositeDMContext(IDMContext[] parents) {
+ fParents = parents;
+ }
+
+ /**
+ * Returns the session ID of the first element in the array of parents of this
+ * context. May return an empty string if the parents array has no elements.
+ * <p>
+ * Note: The session ID is primarily used by UI components to get access to the
+ * correct session and executor for the given context. The composite context is
+ * intended to be created by clients which already know the session ID so
+ * the fact that this method may not return a reliable result is acceptable.
+ * </p>
+ */
+ public String getSessionId() {
+ IDMContext[] parents = getParents();
+ if (parents.length > 0) {
+ return parents[0].getSessionId();
+ } else {
+ return INVALID_SESSION_ID;
+ }
+ }
+
+ /**
+ * Returns the list of parents that this composite context is based on. Subclasses
+ * may override this method to calculate their own set of parents.
+ */
+ public IDMContext[] getParents() {
+ return fParents;
+ }
+
+ /**
+ * Returns the given adapter of the last DMVMContext element found in the tree
+ * path of this composite context. Will return null if no DMVMContext is found
+ * in path.
+ * @see #getSessionId()
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapterType) {
+ IDMContext[] parents = getParents();
+ if (parents.length > 0) {
+ return parents[0].getAdapter(adapterType);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof CompositeDMContext && Arrays.equals(((CompositeDMContext)obj).getParents(), getParents());
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(getParents());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java
new file mode 100644
index 00000000000..bf0c7102c5c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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
+ * Ericsson - Modified for additional features in DSF Reference implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+
+
+/**
+ * Holder for utility static methods for manipulating IDMContext objects.
+ */
+public class DMContexts {
+
+ /**
+ * Convenience constant.
+ */
+ public static final IDMContext[] EMPTY_CONTEXTS_ARRAY = new IDMContext[0];
+
+ /**
+ * Finds a data model context of given type among ancestors of the
+ * specified context. The returned ancestor is the one closest to the
+ * specified context, in terms of depth.
+ *
+ * Note that for efficiency, this method does not re-use getAllAncestorsOfType()
+ * to avoid the unnecessary creation of an array.
+ *
+ * @param ctx DMC to search.
+ * @param ancestorType Class type of the desired DMC ancestor.
+ * @return Returns the ancestor if found, null otherwise.
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public static <V extends IDMContext> V getAncestorOfType(IDMContext ctx, Class<V> ancestorType) {
+ if(ctx == null)
+ return null;
+ // Check the first context here for efficiency
+ if (ancestorType.isAssignableFrom(ctx.getClass())) {
+ return (V)ctx;
+ }
+
+ // Use a LinkedHashSet to avoid duplicates and preserver insertion-order
+ Set<IDMContext> nodes = new LinkedHashSet<IDMContext>();
+ nodes.addAll(Arrays.asList(ctx.getParents()));
+ while (nodes.isEmpty() == false) {
+ Set<IDMContext> parents = nodes;
+ nodes = new LinkedHashSet<IDMContext>();
+ for (IDMContext parent : parents) {
+ if (ancestorType.isAssignableFrom(parent.getClass())) {
+ return (V)parent;
+ }
+
+ nodes.addAll(Arrays.asList(parent.getParents()));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds all data model contexts of given type among ancestors of the
+ * specified context. Ancestors are returned in order of closest to farthest,
+ * in terms of depth.
+ * @param ctx DMC to search.
+ * @param ancestorType Class type of the desired DMC ancestor.
+ * @return Returns all ancestors found, null if none.
+ * @since 1.1
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public static <V extends IDMContext> V[] getAllAncestorsOfType(IDMContext ctx, Class<V> ancestorType) {
+ if(ctx == null)
+ return null;
+
+ // Use a LinkedHashSet to avoid duplicates and preserver insertion-order
+ Set<V> requestedAncestors = new LinkedHashSet<V>();
+ Set<IDMContext> nodes = new LinkedHashSet<IDMContext>();
+ nodes.add(ctx);
+ while (nodes.isEmpty() == false) {
+ Set<IDMContext> parents = nodes;
+ nodes = new LinkedHashSet<IDMContext>();
+ for (IDMContext parent : parents) {
+ if (ancestorType.isAssignableFrom(parent.getClass())) {
+ requestedAncestors.add((V)parent);
+ }
+
+ nodes.addAll(Arrays.asList(parent.getParents()));
+ }
+ }
+
+ if (requestedAncestors.isEmpty()) return null;
+ else {
+ V[] v = (V[])Array.newInstance(ancestorType, 0);
+ return requestedAncestors.toArray(v);
+ }
+ }
+
+ /**
+ * Checks all ancestors for a given context to see if the given
+ * potentialAncestor is in fact an ancestor.
+ * @param dmc DM Contexts who's ancestors to check.
+ * @param potentialAncestor Ancestor context to look for.
+ * @return true if a match is found.
+ */
+ @ThreadSafe
+ public static boolean isAncestorOf(IDMContext dmc, IDMContext potentialAncestor) {
+ // Check the direct parents for a match.
+ for (IDMContext parentDmc : dmc.getParents()) {
+ if (potentialAncestor.equals(parentDmc)) {
+ return true;
+ }
+ }
+
+ // Recursively check the parents' parents for a match.
+ for (IDMContext parentDmc : dmc.getParents()) {
+ if (isAncestorOf(parentDmc, potentialAncestor)) {
+ return true;
+ }
+ }
+
+ // No match.
+ return false;
+ }
+
+ /**
+ * Traverses all the parents of a context and converts the whole
+ * into a list.
+ */
+ @ThreadSafe
+ public static List<IDMContext> toList(IDMContext dmc) {
+ /*
+ * This method is implemented recursively, which is not necessarily
+ * the most efficient way to do this.
+ */
+ List<IDMContext> list = new ArrayList<IDMContext>();
+ list.add(dmc);
+
+ for (IDMContext parentDmc : dmc.getParents()) {
+ list.addAll(toList(parentDmc));
+ }
+ return list;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java
new file mode 100644
index 00000000000..2d8292ba17d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * The base class for data model objects.
+ * <p>
+ * DSF services need to return objects to clients which can be used as
+ * handles to track data stored in the service. Clients such as lazy-loading
+ * tree and table views retrieve a list of handles, then as needed, they
+ * retrieve the children and label information for these handles. Because of
+ * this pattern, services need to be able to return a set of handle objects,
+ * then as needed clients can retrieve data corresponding to these handles.
+ * The Data Model Context object is the interface that DSF services should use
+ * to represent the handle objects that are to be referenced by view model.
+ * <p>
+ * <i>Note: DM contexts are meant to be immutable and thus accessible from
+ * any thread instead of just the services dispatch thread. This is because
+ * clients may need to call context objects' methods on non-dispatch thread,
+ * especially equals and hashCode.</i>
+ * <p>
+ * <i>Note #2: DM Contexts should also avoid holding references to service
+ * instances or other large chunks of data, because some of the clients may
+ * hold onto these objects for longer time than the life of the service.
+ * This may prevent the service from being garbage collected, possibly keeping
+ * a lot of resources tied up.
+ *
+ */
+@Immutable
+public interface IDMContext extends IAdaptable
+{
+ /**
+ * Each model context object needs to track the session from which it
+ * originated. The session ID allows clients to choose the correct
+ * dispatch thread with which to access the service, and it allows the
+ * service to be uniquely identified among other sessions.
+ * @return Session ID of the service that originated the context.
+ */
+ public String getSessionId();
+
+ /**
+ * Returns the parent context of this context. ModelContext objects can be
+ * chained this way to allow methods that require context from multiple
+ * services to retrieve this context from a single handle that comes from
+ * the client.
+ * @return parent context of this context.
+ */
+ public IDMContext[] getParents();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java
new file mode 100644
index 00000000000..045f8c92013
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Marker interface for data corresponding to IDMContext, retrieved from a
+ * service. These data objects are meant to be processed by clients on
+ * different threads, therefore they should be immutable.
+ */
+@Immutable
+public interface IDMData {
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java
new file mode 100644
index 00000000000..40edf672e51
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.datamodel;
+
+/**
+ * Common interface for events that signify changes in the data model.
+ * The sub-classes should contain specific information about the event, while
+ * this base class only identifies the DM Context that is affected.
+ * @param <V> Data Model context type that is affected by this event.
+ */
+public interface IDMEvent <V extends IDMContext> {
+ V getDMContext();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java
new file mode 100644
index 00000000000..f0071711a62
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Interface for DSF services that provide model data to clients.
+ * <p>
+ * For completeness this service interface derives from <code>IDMData</data>
+ * and has a method which allows clients to retrieve the DM Context that
+ * represents the service data.
+ *
+ * @deprecated Without getModelData method this service has no function.
+ * There's also no need for it as a marker interface so we may as well
+ * get rid of it.
+ */
+public interface IDMService extends IDsfService {
+ /**
+ * Retrieves model data object for given context. This method makes it
+ * un-necessary for every model service to declare a separate method
+ * for retrieving model data of specific type.
+ *
+ * @param <V> The Data Model Data type that is to be retrieved.
+ * @param dmc Data Model Context for the data model data object to be retrieved.
+ * @param rm Request completion monitor to be filled in with the Data Model Data.
+ *
+ * @deprecated This method is now deprecated as there is no compile-time linking
+ * between IDMContext and IDMData objects (see bug 205132)
+ */
+ @Deprecated
+ void getModelData(IDMContext dmc, DataRequestMonitor<?> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html
new file mode 100644
index 00000000000..2ea664a1ee4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Eclipse Device Debug - Debugger Services Framework - Data Model</title>
+</head>
+<body>
+Provides a base API and utilities for expoding data model through DSF
+services.<br>
+<br>
+<h2>Package Specification</h2>
+Practically speaking, all state data held by the DSF services makes up
+the "data mode" of the service session.&nbsp; However, to make it easy
+to present this data in standard debug views, as well as customizable
+views, it is useful to present the data using a consisten pattern and
+with a set of published APIs and utilities.&nbsp; This package aims to
+provide these APIs and utilities.<br>
+<h3>Development Plans</h3>
+This package is a work in progress and it is missing a major
+feature.&nbsp; This feature is being able to automatically parametrize
+the contents of the data model in order to generically traverse it, and
+to write data-driven framework for populating views with model data.<br>
+<br>
+</body>
+</html>
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java
new file mode 100644
index 00000000000..7f57a6c812c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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 - Ted Williams - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.provisional.model;
+
+/*
+ * This interface is EXPERIMENTAL.
+*/
+
+public interface IMemoryBlockUpdatePolicyProvider
+{
+ public String[] getUpdatePolicies();
+
+ public String getUpdatePolicyDescription(String id);
+
+ public String getUpdatePolicy();
+
+ public void setUpdatePolicy(String id);
+
+ public void clearCache();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java
new file mode 100644
index 00000000000..88c8a119eb1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java
@@ -0,0 +1,634 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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
+ * Ericsson Communication - upgrade IF to IMemoryBlockExtension
+ * Ericsson Communication - added support for 64 bit processors
+ * Ericsson Communication - added support for changed bytes
+ * Ericsson Communication - better management of exceptions
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.model;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockUpdatePolicyProvider;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * This class manages the memory block retrieved from the target as a result
+ * of a getBytesFromAddress() call from the platform.
+ *
+ * It performs its read/write functions using the MemoryService.
+ */
+public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtension, IMemoryBlockUpdatePolicyProvider
+{
+ private final static String UPDATE_POLICY_AUTOMATIC = "Automatic"; //$NON-NLS-1$
+ private final static String UPDATE_POLICY_MANUAL = "Manual"; //$NON-NLS-1$
+ private final static String UPDATE_POLICY_BREAKPOINT = "On Breakpoint"; //$NON-NLS-1$
+
+ private final IMemoryDMContext fContext;
+ private final ILaunch fLaunch;
+ private final IDebugTarget fDebugTarget;
+ private final DsfMemoryBlockRetrieval fRetrieval;
+ private final String fModelId;
+ private final String fExpression;
+ private final BigInteger fBaseAddress;
+
+ private BigInteger fBlockAddress;
+ private int fLength;
+ private int fWordSize;
+ private MemoryByte[] fBlock;
+
+ private String fUpdatePolicy = UPDATE_POLICY_AUTOMATIC;
+
+ private ArrayList<Object> fConnections = new ArrayList<Object>();
+
+ @SuppressWarnings("unused")
+ private boolean isEnabled;
+
+ /**
+ * Constructor.
+ *
+ * @param retrieval - the MemoryBlockRetrieval (session context)
+ * @param modelId -
+ * @param expression - the displayed expression in the UI
+ * @param address - the actual memory block start address
+ * @param word_size - the number of bytes per address
+ * @param length - the requested block length (could be 0)
+ */
+ DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, IMemoryDMContext context, String modelId, String expression, BigInteger address, int word_size, long length) {
+ fLaunch = retrieval.getLaunch();
+ fDebugTarget = retrieval.getDebugTarget();
+ fRetrieval = retrieval;
+ fContext = context;
+ fModelId = modelId;
+ fExpression = expression;
+ fBaseAddress = address;
+
+ // Current block information
+ fBlockAddress = address;
+ fWordSize = word_size;
+ fLength = (int) length;
+ fBlock = null;
+
+ try {
+ fRetrieval.getExecutor().execute(new Runnable() {
+ public void run() {
+ fRetrieval.getSession().addServiceEventListener(DsfMemoryBlock.this, null);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session is shut down.
+ }
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IAdaptable
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (adapter.isAssignableFrom(DsfMemoryBlockRetrieval.class)) {
+ return fRetrieval;
+ }
+ return super.getAdapter(adapter);
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IDebugElement
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
+ */
+ public IDebugTarget getDebugTarget() {
+ return fDebugTarget;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier()
+ */
+ public String getModelIdentifier() {
+ return fModelId;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
+ */
+ public ILaunch getLaunch() {
+ return fLaunch;
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IMemoryBock interface - obsoleted by IMemoryBlockExtension
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getStartAddress()
+ */
+ public long getStartAddress() {
+ // Not implemented (obsolete)
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getLength()
+ */
+ public long getLength() {
+ // Not implemented (obsolete)
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getBytes()
+ */
+ public byte[] getBytes() throws DebugException {
+ // Not implemented (obsolete)
+ return new byte[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#supportsValueModification()
+ */
+ public boolean supportsValueModification() {
+ return fRetrieval.supportsValueModification();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#setValue(long, byte[])
+ */
+ public void setValue(long offset, byte[] bytes) throws DebugException {
+ // Not implemented (obsolete)
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockExtension interface
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getExpression()
+ */
+ public String getExpression() {
+ return fExpression;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigBaseAddress()
+ */
+ public BigInteger getBigBaseAddress() throws DebugException {
+ return fBaseAddress;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockStartAddress()
+ */
+ public BigInteger getMemoryBlockStartAddress() throws DebugException {
+ // Null indicates that memory can be retrieved at addresses lower than the block base address
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockEndAddress()
+ */
+ public BigInteger getMemoryBlockEndAddress() throws DebugException {
+ // Null indicates that memory can be retrieved at addresses higher the block base address
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigLength()
+ */
+ public BigInteger getBigLength() throws DebugException {
+ // -1 indicates that memory block is unbounded
+ return BigInteger.valueOf(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressSize()
+ */
+ public int getAddressSize() throws DebugException {
+ return fRetrieval.getAddressSize();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportBaseAddressModification()
+ */
+ public boolean supportBaseAddressModification() throws DebugException {
+ return fRetrieval.supportBaseAddressModification();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportsChangeManagement()
+ */
+ public boolean supportsChangeManagement() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setBaseAddress(java.math.BigInteger)
+ */
+ public void setBaseAddress(BigInteger address) throws DebugException {
+ fBlockAddress = address;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromOffset(java.math.BigInteger, long)
+ */
+ public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException {
+ return getBytesFromAddress(fBlockAddress.add(offset), units);
+ }
+
+ private boolean fUseCachedData = false;
+
+ public void clearCache() {
+ fUseCachedData = false;
+ }
+
+ @DsfServiceEventHandler
+ public void handleCacheSuspendEvent(IRunControl.ISuspendedDMEvent e) {
+ if (e.getReason() == StateChangeReason.BREAKPOINT)
+ fUseCachedData = false;
+ }
+
+ private boolean isUseCacheData()
+ {
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_BREAKPOINT))
+ return fUseCachedData;
+
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_MANUAL))
+ return fUseCachedData;
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromAddress(java.math.BigInteger, long)
+ */
+ public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException {
+
+ if (isUseCacheData() && fBlockAddress.compareTo(address) == 0 && units * getAddressableSize() <= fBlock.length)
+ return fBlock;
+
+ MemoryByte[] newBlock = fetchMemoryBlock(address, units);
+ int newLength = (newBlock != null) ? newBlock.length : 0;
+
+ // If the retrieved block overlaps with the cached block, flag the changed bytes
+ // so they can be properly highlighted in the platform Memory view.
+ // Note: In the standard Memory view, the values are displayed in cells of 4 bytes
+ // (on 4-bytes address boundaries) and all 4 bytes have to be flagged so the
+ // cell is highlighted (and the delta sigh is shown).
+ if (fBlock != null && newLength > 0) {
+ switch (fBlockAddress.compareTo(address)) {
+ // Cached block begins before the retrieved block location
+ // If there is no overlap, there are no bytes to flag
+ case -1:
+ {
+ // Determine the distance between the cached and the
+ // requested block addresses
+ BigInteger bigDistance = address.subtract(fBlockAddress);
+
+ // If the distance does not exceed the length of the cached block,
+ // then there is some overlap between the blocks and we have to
+ // mark the changed bytes (if applicable)
+ if (bigDistance.compareTo(BigInteger.valueOf(fLength)) == -1) {
+ // Here we can reasonably assume that java integers are OK
+ int distance = bigDistance.intValue();
+ int length = fLength - distance;
+
+ // Work by cells of 4 bytes
+ for (int i = 0; i < length; i += 4) {
+ // Determine if any byte within the cell was modified
+ boolean changed = false;
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[j].setFlags(fBlock[distance + j].getFlags());
+ if (newBlock[j].getValue() != fBlock[distance + j].getValue())
+ changed = true;
+ }
+ // If so, flag the whole cell as modified
+ if (changed)
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[j].setHistoryKnown(true);
+ newBlock[j].setChanged(true);
+ }
+ }
+
+ }
+ break;
+ }
+
+ // Cached block begins before the retrieved block location
+ // If there is no overlap, there are no bytes to flag
+ // (this block of code is symmetric with the previous one)
+ case 0:
+ case 1:
+ {
+ // Determine the distance between the cached and the
+ // requested block addresses
+ BigInteger bigDistance = fBlockAddress.subtract(address);
+
+ // If the distance does not exceed the length of the new block,
+ // then there is some overlap between the blocks and we have to
+ // mark the changed bytes (if applicable)
+ if (bigDistance.compareTo(BigInteger.valueOf(newLength)) == -1) {
+ // Here we can reasonably assume that java integers are OK
+ int distance = bigDistance.intValue();
+ int length = newLength - distance;
+
+ // Work by cells of 4 bytes
+ for (int i = 0; i < length; i += 4) {
+ // Determine if any byte within the cell was modified
+ boolean changed = false;
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[distance + j].setFlags(fBlock[j].getFlags());
+ if (newBlock[distance + j].getValue() != fBlock[j].getValue())
+ changed = true;
+ }
+ // If so, flag the whole cell as modified
+ if (changed)
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[distance + j].setHistoryKnown(true);
+ newBlock[distance + j].setChanged(true);
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ // Update the internal state
+ fBlock = newBlock;
+ fBlockAddress = address;
+ fLength = newLength;
+
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_BREAKPOINT))
+ fUseCachedData = true;
+ else if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_MANUAL))
+ fUseCachedData = true;
+
+ return fBlock;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setValue(java.math.BigInteger, byte[])
+ */
+ public void setValue(BigInteger offset, byte[] bytes) throws DebugException {
+ writeMemoryBlock(offset.longValue(), bytes);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#connect(java.lang.Object)
+ */
+ public void connect(Object client) {
+ if (!fConnections.contains(client))
+ fConnections.add(client);
+ if (fConnections.size() == 1)
+ enable();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#disconnect(java.lang.Object)
+ */
+ public void disconnect(Object client) {
+ if (fConnections.contains(client))
+ fConnections.remove(client);
+ if (fConnections.size() == 0)
+ disable();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getConnections()
+ */
+ public Object[] getConnections() {
+ return fConnections.toArray();
+ }
+
+ private void enable() {
+ isEnabled = true;
+ }
+
+ private void disable() {
+ isEnabled = false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#dispose()
+ */
+ public void dispose() throws DebugException {
+ try {
+ fRetrieval.getExecutor().execute(new Runnable() {
+ public void run() {
+ fRetrieval.getSession().removeServiceEventListener(DsfMemoryBlock.this);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session is down.
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockRetrieval()
+ */
+ public IMemoryBlockRetrieval getMemoryBlockRetrieval() {
+ return fRetrieval;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressableSize()
+ */
+ public int getAddressableSize() throws DebugException {
+ return fRetrieval.getAddressableSize();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Helper functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * The real thing. Since the original call is synchronous (from a platform
+ * Job), we use a Query that will patiently wait for the underlying
+ * asynchronous calls to complete before returning.
+ *
+ * @param bigAddress
+ * @param length
+ * @return MemoryByte[]
+ * @throws DebugException
+ */
+ private MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long length) throws DebugException {
+
+ // For the IAddress interface
+ final Addr64 address = new Addr64(bigAddress);
+
+ // Use a Query to synchronize the downstream calls
+ Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
+ @Override
+ protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
+ IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService();
+ if (memoryService != null) {
+ // Go for it
+ memoryService.getMemory(
+ fContext, address, 0, fWordSize, (int) length,
+ new DataRequestMonitor<MemoryByte[]>(fRetrieval.getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ drm.setData(getData());
+ drm.done();
+ }
+ });
+ }
+
+ }
+ };
+ fRetrieval.getExecutor().execute(query);
+
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error reading memory block (InterruptedException)", e)); //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error reading memory block (ExecutionException)", e)); //$NON-NLS-1$
+ }
+ }
+
+ /* Writes an array of bytes to memory.
+ *
+ * @param offset
+ * @param bytes
+ * @throws DebugException
+ */
+ private void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException {
+
+ // For the IAddress interface
+ final Addr64 address = new Addr64(fBaseAddress);
+
+ // Use a Query to synchronize the downstream calls
+ Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
+ @Override
+ protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
+ IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService();
+ if (memoryService != null) {
+ // Go for it
+ memoryService.setMemory(
+ fContext, address, offset, fWordSize, bytes.length, bytes,
+ new RequestMonitor(fRetrieval.getExecutor(), null));
+ }
+
+ }
+ };
+ fRetrieval.getExecutor().execute(query);
+
+ try {
+ query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error writing memory block (InterruptedException)", e)); //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error writing memory block (ExecutionException)", e)); //$NON-NLS-1$
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Event Handlers
+ ///////////////////////////////////////////////////////////////////////////
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.ISuspendedDMEvent e) {
+
+ // Clear the "Changed" flags after each run/resume/step
+ for (int i = 0; i < fLength; i++)
+ fBlock[i].setChanged(false);
+
+ // Generate the MemoryChangedEvents
+ handleMemoryChange(BigInteger.ZERO);
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IMemoryChangedEvent e) {
+
+ // Check if we are in the same address space
+ if (e.getDMContext().equals(fContext)) {
+ IAddress[] addresses = e.getAddresses();
+ for (int i = 0; i < addresses.length; i++)
+ handleMemoryChange(addresses[i].getValue());
+ }
+ }
+
+ /**
+ * @param address
+ * @param length
+ */
+ public void handleMemoryChange(BigInteger address) {
+
+ // Check if the change affects this particular block (0 is universal)
+ BigInteger fEndAddress = fBlockAddress.add(BigInteger.valueOf(fLength));
+ if (address.equals(BigInteger.ZERO) ||
+ ((fBlockAddress.compareTo(address) != 1) && (fEndAddress.compareTo(address) == 1)))
+ {
+ // Notify the event listeners
+ DebugEvent debugEvent = new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT);
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { debugEvent });
+ }
+ }
+
+ public String[] getUpdatePolicies() {
+ return new String[] {UPDATE_POLICY_AUTOMATIC, UPDATE_POLICY_MANUAL, UPDATE_POLICY_BREAKPOINT};
+ }
+
+ public String getUpdatePolicy()
+ {
+ return fUpdatePolicy;
+ }
+
+ public void setUpdatePolicy(String policy)
+ {
+ fUpdatePolicy = policy;
+ }
+
+ public String getUpdatePolicyDescription(String id) {
+ return id;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
new file mode 100644
index 00000000000..6c224b78c11
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
@@ -0,0 +1,505 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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
+ * Ericsson Communication - upgrade IF to IMemoryBlockRetrievalExtension
+ * Ericsson Communication - added Expression evaluation
+ * Ericsson Communication - added support for 64 bit processors
+ * Ericsson Communication - added support for event handling
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.model;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Implementation of memory access API of the Eclipse standard debug model.
+ *
+ * The DsfMemoryBlockRetrieval is not an actual memory block but rather a
+ * reference to the memory address space for an execution context (e.g. a
+ * process) within a debug session. From this debug 'context', memory blocks
+ * can then be read/written.
+ *
+ * Note: For the reference application, The IMemoryBlockRetrievalExtension
+ * is implemented. This will result in getExtendedMemoryBlock() being called
+ * when a memory block is selected from the platform memory pane.
+ *
+ * However, if the 'simpler' IMemoryBlockRetrieval is to be implemented, the
+ * code will still be functional after some trivial adjustments.
+ *
+ */
+public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension
+{
+ private final String fModelId;
+ private final DsfSession fSession;
+ private final DsfExecutor fExecutor;
+ private final String fContextString;
+ private final ServiceTracker fMemoryServiceTracker;
+ private final ServiceTracker fExpressionServiceTracker;
+
+ private final ILaunchConfiguration fLaunchConfig;
+ private final ILaunch fLaunch;
+ private final IDebugTarget fDebugTarget;
+ private final boolean fSupportsValueModification;
+ private final boolean fSupportBaseAddressModification;
+ private final int fAddressSize;
+ private final int fWordSize; // Number of bytes per address
+
+ /**
+ * Constructor
+ *
+ * @param modelId
+ * @param dmc
+ * @throws DebugException
+ */
+ public DsfMemoryBlockRetrieval(String modelId, ILaunchConfiguration config, DsfSession session) throws DebugException {
+
+ // DSF stuff
+ fModelId = modelId;
+
+ // FIXME: (Bug228573) Currently memory contexts are differentiated by
+ // sessionID so there is no way to guarantee the memory blocks will be
+ // reinstated in the correct memory space.
+ // Need a way to create deterministically the context ID from a unique
+ // target, ideally from the launch configuration (or derived from it).
+ // For the time being, just put some constant. This will work until we
+ // support multiple targets in the same launch.
+ // fContextString = fContext.toString();
+ fContextString = "Context string"; //$NON-NLS-1$
+
+ fSession = session;
+ if (fSession == null) {
+ throw new IllegalArgumentException(
+ "Session " + session + " is not active"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ fExecutor = fSession.getExecutor();
+ BundleContext bundle = DsfPlugin.getBundleContext();
+
+ // Here we chose to use 2 distinct service trackers instead of an
+ // amalgamated one because it is less error prone (and we are lazy).
+
+ // Create a tracker for the MemoryService
+ String memoryServiceFilter = DsfServices.createServiceFilter(IMemory.class, session.getId());
+
+ try {
+ fMemoryServiceTracker = new ServiceTracker(
+ bundle, bundle.createFilter(memoryServiceFilter), null);
+ } catch (InvalidSyntaxException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error creating service filter.", e)); //$NON-NLS-1$
+ }
+ fMemoryServiceTracker.open();
+
+ // Create a tracker for the ExpressionService
+ String expressionServiceFilter = "(&" + //$NON-NLS-1$
+ "(OBJECTCLASS=" //$NON-NLS-1$
+ + IExpressions.class.getName()
+ + ")" + //$NON-NLS-1$
+ "(" + IDsfService.PROP_SESSION_ID //$NON-NLS-1$
+ + "=" + session.getId() + ")" + //$NON-NLS-1$//$NON-NLS-2$
+ ")"; //$NON-NLS-1$
+
+ try {
+ fExpressionServiceTracker = new ServiceTracker(
+ bundle, bundle.createFilter(expressionServiceFilter), null);
+ } catch (InvalidSyntaxException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error creating service filter.", e)); //$NON-NLS-1$
+ }
+ fExpressionServiceTracker.open();
+
+ // Launch configuration information
+ fLaunchConfig = config;
+ fLaunch = null;
+ fDebugTarget = null;
+ fAddressSize = 4; // Get this from the launch configuration
+ fWordSize = 1; // Get this from the launch configuration
+ fSupportsValueModification = true; // Get this from the launch configuration
+ fSupportBaseAddressModification = false; // Get this from the launch configuration
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Memory monitors persistence
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * In the launch configuration file, the memory block entry is structured
+ * as follows (note: this differs from CDI):
+ *
+ * <stringAttribute
+ * key="org.eclipse.dsf.launch.MEMORY_BLOCKS"
+ * value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ * <memoryBlockExpressionList context=[memory context ID]>
+ * <memoryBlockExpression label=[monitor label] address=[base address]/>
+ * <memoryBlockExpression ...>
+ * ...
+ * </memoryBlockExpressionList>
+ * ...
+ * <memoryBlockExpressionList context=...>
+ * ...
+ * </memoryBlockExpressionList>"
+ * />
+ */
+
+ //-------------------------------------------------------------------------
+ // Memory blocks memento tags
+ //-------------------------------------------------------------------------
+
+ // These 2 really belong in the DSF launch configuration class...
+ private static final String DSF_LAUNCH_ID = "org.eclipse.dsf.launch"; //$NON-NLS-1$
+ private static final String ATTR_DEBUGGER_MEMORY_BLOCKS = DSF_LAUNCH_ID + ".MEMORY_BLOCKS"; //$NON-NLS-1$
+
+ private static final String MEMORY_BLOCK_EXPRESSION_LIST = "memoryBlockExpressionList"; //$NON-NLS-1$
+ private static final String ATTR_EXPRESSION_LIST_CONTEXT = "context"; //$NON-NLS-1$
+ private static final String MEMORY_BLOCK_EXPRESSION = "memoryBlockExpression"; //$NON-NLS-1$
+ private static final String ATTR_MEMORY_BLOCK_EXPR_LABEL = "label"; //$NON-NLS-1$
+ private static final String ATTR_MEMORY_BLOCK_EXPR_ADDRESS = "address"; //$NON-NLS-1$
+
+ //-------------------------------------------------------------------------
+ // Install persisted memory monitors
+ //-------------------------------------------------------------------------
+
+ /**
+ * Restore the memory monitors from the memento in the launch configuration
+ */
+ public void initialize(final IMemoryDMContext memoryCtx) {
+ try {
+ final String memento = fLaunchConfig.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, ""); //$NON-NLS-1$
+ if (memento != null && memento.trim().length() != 0) {
+ // Submit the runnable to install the monitors on dispatch thread.
+ getExecutor().submit(new Runnable() {
+ public void run() {
+ try {
+ createBlocksFromConfiguration(memoryCtx, memento);
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+ });
+ }
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ private void createBlocksFromConfiguration(IMemoryDMContext memoryCtx, String memento) throws CoreException {
+
+ // Parse the memento and validate its type
+ Element root = DebugPlugin.parseDocument(memento);
+ if (!root.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION_LIST)) {
+ IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, DebugPlugin.INTERNAL_ERROR,
+ "Memory monitor initialization: invalid memento", null);//$NON-NLS-1$
+ throw new CoreException(status);
+ }
+
+ // Process the block list specific to this memory context
+ // FIXME: (Bug228573) We only process the first entry...
+ if (root.getAttribute(ATTR_EXPRESSION_LIST_CONTEXT).equals(fContextString)) {
+ List<IMemoryBlock> blocks = new ArrayList<IMemoryBlock>();
+ NodeList expressionList = root.getChildNodes();
+ int length = expressionList.getLength();
+ for (int i = 0; i < length; ++i) {
+ Node node = expressionList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element entry = (Element) node;
+ if (entry.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION)) {
+ String label = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL);
+ String address = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS);
+ BigInteger blockAddress = new BigInteger(address);
+ DsfMemoryBlock block = new DsfMemoryBlock(this, memoryCtx, fModelId, label, blockAddress, fWordSize, 0);
+ blocks.add(block);
+ }
+ }
+ }
+ DebugPlugin.getDefault().getMemoryBlockManager().addMemoryBlocks( blocks.toArray(new IMemoryBlock[blocks.size()]));
+ }
+ }
+
+ // FIXME: (Bug228573) Each retrieval overwrites the previous one :-(
+
+ // In theory, we should make this a Job since we are writing to the file system.
+ // However, this would cause the same racing condition as Bug228308. Finally, we
+ // don't care too much about the UI responsiveness since we are in the process of
+ // shutting down :-)
+ public void saveMemoryBlocks() {
+ try {
+ ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy();
+ wc.setAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, getMemento());
+ wc.doSave();
+ }
+ catch( CoreException e ) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ public String getMemento() throws CoreException {
+ IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(this);
+ Document document = DebugPlugin.newDocument();
+ Element expressionList = document.createElement(MEMORY_BLOCK_EXPRESSION_LIST);
+ expressionList.setAttribute(ATTR_EXPRESSION_LIST_CONTEXT, fContextString);
+ for (IMemoryBlock block : blocks) {
+ if (block instanceof IMemoryBlockExtension) {
+ IMemoryBlockExtension memoryBlock = (IMemoryBlockExtension) block;
+ Element expression = document.createElement(MEMORY_BLOCK_EXPRESSION);
+ expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, memoryBlock.getExpression());
+ expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS, memoryBlock.getBigBaseAddress().toString());
+ expressionList.appendChild(expression);
+ }
+ }
+ document.appendChild(expressionList);
+ return DebugPlugin.serializeDocument(document);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Accessors
+ ///////////////////////////////////////////////////////////////////////////
+
+ public DsfSession getSession() {
+ return fSession;
+ }
+
+ public DsfExecutor getExecutor() {
+ return fExecutor;
+ }
+
+ public ServiceTracker getServiceTracker() {
+ return fMemoryServiceTracker;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Launch/Target specific information
+ ///////////////////////////////////////////////////////////////////////////
+
+ public ILaunch getLaunch() {
+ return fLaunch;
+ }
+
+ public IDebugTarget getDebugTarget() {
+ return fDebugTarget;
+ }
+
+ public int getAddressSize() {
+ return fAddressSize;
+ }
+
+ public int getAddressableSize() {
+ return fWordSize;
+ }
+
+ public boolean supportsValueModification() {
+ return fSupportsValueModification;
+ }
+
+ public boolean supportBaseAddressModification() {
+ return fSupportBaseAddressModification;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
+ */
+ public boolean supportsStorageRetrieval() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long,
+ * long)
+ */
+ public IMemoryBlock getMemoryBlock(final long startAddress, final long length) throws DebugException {
+ throw new DebugException(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, DebugException.NOT_SUPPORTED,
+ "getMemoryBlock() not supported, use getExtendedMemoryBlock()", null)); //$NON-NLS-1$
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockRetrievalExtension
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension#getExtendedMemoryBlock(java.lang.String,
+ * java.lang.Object)
+ */
+ public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException {
+ // Drill for the actual DMC
+ IMemoryDMContext memoryDmc = null;
+ IDMContext dmc = null;
+ if (context instanceof IAdaptable) {
+ dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class);
+ if (dmc != null) {
+ memoryDmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class);
+ }
+ }
+
+ if (memoryDmc == null) {
+ return null;
+ }
+
+ // The block start address (supports 64-bit processors)
+ BigInteger blockAddress;
+
+ /*
+ * See if the expression is a simple numeric value; if it is, we can
+ * avoid some costly processing (calling the back-end to resolve the
+ * expression and obtain an address)
+ */
+ try {
+ // First, assume a decimal address
+ int base = 10;
+ int offset = 0;
+
+ // Check for "hexadecimality"
+ if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$
+ base = 16;
+ offset = 2;
+ }
+ // Check for "binarity"
+ else if (expression.startsWith("0b")) { //$NON-NLS-1$
+ base = 2;
+ offset = 2;
+ }
+ // Check for "octality"
+ else if (expression.startsWith("0")) { //$NON-NLS-1$
+ base = 8;
+ offset = 1;
+ }
+ // Now, try to parse the expression. If a NumberFormatException is
+ // thrown, then it wasn't a simple numerical expression and we go
+ // to plan B (attempt an expression evaluation)
+ blockAddress = new BigInteger(expression.substring(offset), base);
+
+ } catch (NumberFormatException nfexc) {
+ // OK, expression is not a simple, absolute numeric value;
+ // try to resolve as an expression.
+ // In case of failure, simply return 'null'
+
+ // Resolve the expression
+ blockAddress = resolveMemoryAddress(dmc, expression);
+ if (blockAddress == null) {
+ return null;
+ }
+ }
+
+ /*
+ * At this point, we only resolved the requested memory block
+ * start address and we have no idea of the block's length.
+ *
+ * The renderer will provide this information when it calls
+ * getBytesFromAddress() i.e. after the memory block holder has
+ * been instantiated.
+ *
+ * The down side is that every time we switch renderer, for the
+ * same memory block, a trip to the target could result. However,
+ * the memory request cache should save the day.
+ */
+
+ return new DsfMemoryBlock(this, memoryDmc, fModelId, expression, blockAddress, fWordSize, 0);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Helper functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ private BigInteger resolveMemoryAddress(final IDMContext dmc, final String expression) throws DebugException {
+
+ // Use a Query to "synchronize" the downstream calls
+ Query<BigInteger> query = new Query<BigInteger>() {
+ @Override
+ protected void execute(final DataRequestMonitor<BigInteger> drm) {
+ // Lookup for the ExpressionService
+ final IExpressions expressionService = (IExpressions) fExpressionServiceTracker.getService();
+ if (expressionService != null) {
+ // Create the expression
+ final IExpressionDMContext expressionDMC = expressionService.createExpression(dmc, expression);
+ String formatId = IFormattedValues.HEX_FORMAT;
+ FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(expressionDMC, formatId);
+ expressionService.getFormattedExpressionValue(
+ valueDmc,
+ new DataRequestMonitor<FormattedValueDMData>(getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ // Store the result
+ FormattedValueDMData data = getData();
+ String value = data.getFormattedValue().substring(2); // Strip the "0x"
+ drm.setData(new BigInteger(value, 16));
+ drm.done();
+ }
+ }
+ );
+ }
+ }
+ };
+ fExecutor.execute(query);
+
+ try {
+ // The happy case
+ return query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error evaluating memory address (InterruptedException).", e)); //$NON-NLS-1$
+
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error evaluating memory address (ExecutionException).", e)); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java
new file mode 100644
index 00000000000..f93655ba9d2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * Convenience base class for {@link IDsfDebugServicesFactory}
+ * @since 1.1
+ */
+public abstract class AbstractDsfDebugServicesFactory implements IDsfDebugServicesFactory {
+
+ @SuppressWarnings("unchecked")
+ public <V> V createService(Class<V> clazz, DsfSession session, Object ... optionalArguments) {
+ if (IBreakpoints.class.isAssignableFrom(clazz)) {
+ return (V)createBreakpointService(session);
+ } else if (ICommandControl.class.isAssignableFrom(clazz)) {
+ return (V)createCommandControl(session);
+ } else if (IDisassembly.class.isAssignableFrom(clazz)) {
+ return (V)createDisassemblyService(session);
+ } else if (IExpressions.class.isAssignableFrom(clazz)) {
+ return (V)createExpressionService(session);
+ } else if (IMemory.class.isAssignableFrom(clazz)) {
+ return (V)createMemoryService(session);
+ } else if (IModules.class.isAssignableFrom(clazz)) {
+ return (V)createModulesService(session);
+ } else if (IProcesses.class.isAssignableFrom(clazz)) {
+ return (V)createProcessesService(session);
+ } else if (IRegisters.class.isAssignableFrom(clazz)) {
+ return (V)createRegistersService(session);
+ } else if (IRunControl.class.isAssignableFrom(clazz)) {
+ return (V)createRunControlService(session);
+ } else if (ISourceLookup.class.isAssignableFrom(clazz)) {
+ return (V)createSourceLookupService(session);
+ } else if (ISignals.class.isAssignableFrom(clazz)) {
+ return (V)createSignalsService(session);
+ } else if (IStack.class.isAssignableFrom(clazz)) {
+ return (V)createStackService(session);
+ } else if (ISymbols.class.isAssignableFrom(clazz)) {
+ return (V)createSymbolsService(session);
+ }
+
+ return null;
+ }
+
+ protected IBreakpoints createBreakpointService(DsfSession session) { return null; }
+ protected ICommandControl createCommandControl(DsfSession session) { return null; }
+ protected IDisassembly createDisassemblyService(DsfSession session) { return null; }
+ protected IExpressions createExpressionService(DsfSession session) { return null; }
+ protected IMemory createMemoryService(DsfSession session) { return null; }
+ protected IModules createModulesService(DsfSession session) { return null; }
+ protected IProcesses createProcessesService(DsfSession session) { return null; }
+ protected IRegisters createRegistersService(DsfSession session) { return null; }
+ protected IRunControl createRunControlService(DsfSession session) { return null; }
+ protected ISourceLookup createSourceLookupService(DsfSession session) { return null; }
+ protected ISignals createSignalsService(DsfSession session) { return null; }
+ protected IStack createStackService(DsfSession session) { return null; }
+ protected ISymbols createSymbolsService(DsfSession session) { return null; }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java
new file mode 100644
index 00000000000..864c3400f20
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java
@@ -0,0 +1,886 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River 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 - Initial API and implementation
+ * Ericsson - Low-level breakpoints integration
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.resources.IMarkerDelta;
+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.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointListener;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.IBreakpointManagerListener;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener
+{
+
+ /**
+ * The attribute translator that this service will use to map the platform
+ * breakpiont attributes to the corresponding target attributes, and vice
+ * versa.
+ */
+ private IBreakpointAttributeTranslator fAttributeTranslator;
+
+ /**
+ * DSF Debug service for creating breakpoints.
+ */
+ IBreakpoints fBreakpoints;
+
+ /**
+ * Platform breakpoint manager
+ */
+ IBreakpointManager fBreakpointManager;
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Breakpoints tracking
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Holds the set of platform breakpoints with their corresponding back-end
+ * breakpoint attributes, per context (i.e. each platform breakpoint is
+ * replicated for each execution context).
+ * - Context entry added/removed on start/stopTrackingBreakpoints()
+ * - Augmented on breakpointAdded()
+ * - Modified on breakpointChanged()
+ * - Diminished on breakpointRemoved()
+ */
+ private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>> fPlatformBPs =
+ new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>>();
+
+ /**
+ * Holds the mapping from platform breakpoint to the corresponding target
+ * breakpoint(s), per context. There can be multiple back-end BPs for a
+ * single platform BP in the case of [1] multiple target contexts, and/or
+ * [2] thread filtering.
+ * Updated when:
+ * - We start/stop tracking an execution context
+ * - A platform breakpoint is added/removed
+ * - A thread filter is applied/removed
+ */
+ private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>> fBreakpointDMContexts =
+ new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>>();
+
+ /**
+ * Due to the very asynchronous nature of DSF, a new breakpoint request can
+ * pop up at any time before an ongoing one is completed. The following set
+ * is used to store requests until the ongoing operation completes.
+ */
+ private Set<IBreakpoint> fPendingRequests = new HashSet<IBreakpoint>();
+
+ /**
+ * @see fPendingRequests
+ */
+ private Set<IBreakpoint> fPendingBreakpoints = new HashSet<IBreakpoint>();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // AbstractDsfService
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * The service constructor
+ *
+ * @param session
+ * @param debugModelId
+ */
+ public BreakpointsMediator(DsfSession session, IBreakpointAttributeTranslator attributeTranslator) {
+ super(session);
+ fAttributeTranslator = attributeTranslator;
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ // - Collect references for the services we interact with
+ // - Register to interesting events
+ // - Obtain the list of platform breakpoints
+ // - Register the service for interested parties
+ super.initialize(
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }});
+ }
+
+ /**
+ * Asynchronous service initialization
+ *
+ * @param requestMonitor
+ */
+ private void doInitialize(RequestMonitor rm) {
+
+ // Get the services references
+ fBreakpoints = getServicesTracker().getService(IBreakpoints.class);
+ fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager();
+ fAttributeTranslator.initialize(this);
+
+ // Register to the useful events
+ fBreakpointManager.addBreakpointListener(this);
+ fBreakpointManager.addBreakpointManagerListener( this );
+
+ // Register this service
+ register(new String[] { BreakpointsMediator.class.getName() },
+ new Hashtable<String, String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ // - Un-register the service
+ // - Stop listening to events
+ // - Remove the breakpoints installed by this service
+ //
+ // Since we are shutting down, there is no overwhelming need
+ // to keep the maps coherent...
+
+ // Stop accepting requests and events
+ unregister();
+ fBreakpointManager.removeBreakpointListener(this);
+ fBreakpointManager.removeBreakpointManagerListener( this );
+ fAttributeTranslator.dispose();
+
+ // Cleanup the breakpoints that are still installed by the service.
+ // Use a counting monitor which will call mom to complete the shutdown
+ // after the breakpoints are un-installed (successfully or not).
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ BreakpointsMediator.super.shutdown(rm);
+ }
+ };
+
+ // We have to make a copy of the fPlatformBPs keys because uninstallBreakpoints()
+ // modifies the map as it walks through it.
+ List<IBreakpointsTargetDMContext> platformBPKeysCopy = new ArrayList<IBreakpointsTargetDMContext>(fPlatformBPs.size());
+ platformBPKeysCopy.addAll(0, fPlatformBPs.keySet());
+ for (IBreakpointsTargetDMContext dmc : platformBPKeysCopy) {
+ stopTrackingBreakpoints(dmc, countingRm);
+ }
+ countingRm.setDoneCount(platformBPKeysCopy.size());
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfPlugin.getBundleContext();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointsManager
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Install and begin tracking breakpoints for given context. The service
+ * will keep installing new breakpoints that appear in the IDE for this
+ * context until {@link #uninstallBreakpoints(IDMContext)} is called for that
+ * context.
+ * @param dmc Context to start tracking breakpoints for.
+ * @param rm Completion callback.
+ */
+ public void startTrackingBreakpoints(IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
+ // - Augment the maps with the new execution context
+ // - Install the platform breakpoints on the selected target
+
+ // Validate the context
+ final IBreakpointsTargetDMContext breakpointsDmc = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
+ if (breakpointsDmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context type", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Make sure a mapping for this execution context does not already exist
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs != null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Context already initialized", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Create entries in the breakpoint tables for the new context. These entries should only
+ // be removed when this service stops tracking breakpoints for the given context.
+ fPlatformBPs.put(breakpointsDmc, new HashMap<IBreakpoint, List<Map<String, Object>>>());
+ fBreakpointDMContexts.put(breakpointsDmc, new HashMap<IBreakpoint, List<IBreakpointDMContext>>());
+
+ // Install the platform breakpoints (stored in fPlatformBPs) on the target.
+ // We need to use a background thread for this operation because we are
+ // accessing the resources system to retrieve the breakpoint attributes.
+ // Accessing the resources system potentially requires using global locks.
+ // Also we will be calling IBreakpointAttributeTranslator which is prohibited
+ // from being called on the session executor thread.
+ new Job("MI Debugger: Install initial breakpoint list.") { //$NON-NLS-1$
+ { setSystem(true); }
+
+ // Get the stored breakpoints from the platform BreakpointManager
+ // and install them on the target
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ // Read initial breakpoints from platform. Copy the breakpoint attributes into a local map.
+ // Note that we cannot write data into fPlatformBPs table here directly because we are not
+ // executing on the dispatch thread.
+ final Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs =
+ new HashMap<IBreakpoint, List<Map<String, Object>>>();
+ try {
+ // Get the stored breakpoint list from the platform BreakpointManager
+ IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+ // Single out the installable breakpoints...
+ for (IBreakpoint bp : bps) {
+ if (fAttributeTranslator.supportsBreakpoint(bp)) {
+ // Retrieve the breakpoint attributes
+ List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled());
+ // Store it for now (will be installed on the dispatcher thread)
+ initialPlatformBPs.put(bp, attrsArray);
+ }
+ }
+ } catch (CoreException e) {
+ IStatus status = new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to read initial breakpoint attributes", e); //$NON-NLS-1$
+ rm.setStatus(status);
+ rm.done();
+ return status;
+ }
+
+ // Submit the runnable to plant the breakpoints on dispatch thread.
+ getExecutor().submit(new Runnable() {
+ public void run() {
+ installInitialBreakpoints(breakpointsDmc, initialPlatformBPs, rm);
+ }
+ });
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /**
+ * Installs the breakpoints that existed prior to the activation of this
+ * breakpoints context.
+ */
+ private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc,
+ Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs,
+ RequestMonitor rm)
+ {
+ // Retrieve the set of platform breakpoints for this context
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Install the individual breakpoints on the executor thread
+ // Requires a counting monitor to know when we're done
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
+ countingRm.setDoneCount(initialPlatformBPs.size());
+
+ for (final IBreakpoint bp : initialPlatformBPs.keySet()) {
+ final List<Map<String, Object>> attrs = initialPlatformBPs.get(bp);
+ // Upon determining the debuggerPath, the breakpoint is installed
+ installBreakpoint(dmc, bp, attrs, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+
+
+ public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
+ // - Remove the target breakpoints for the given execution context
+ // - Update the maps
+
+ // Remove the breakpoints for given DMC from the internal maps.
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Uninstall the individual breakpoints on the executor thread
+ // Requires a counting monitor to know when we're done
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
+ countingRm.setDoneCount(platformBPs.size());
+
+ for (final IBreakpoint bp : platformBPs.keySet()) {
+ uninstallBreakpoint(dmc, bp,
+ new RequestMonitor(getExecutor(), countingRm) {
+ @Override
+ protected void handleCompleted() {
+ // After the breakpoint is removed from target. Call the attribute
+ // translator to refresh breakpoint status based on the new target
+ // breakpoint status.
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(bp);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ countingRm.done();
+ }
+ });
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Back-end interface functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Install a new platform breakpoint on the back-end. A platform breakpoint
+ * can resolve into multiple back-end breakpoints when threads are taken
+ * into account.
+ *
+ * @param dmc
+ * @param breakpoint
+ * @param attrsList
+ * @param rm
+ */
+ private void installBreakpoint(IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
+ final List<Map<String, Object>> attrsList, final RequestMonitor rm)
+ {
+ // Retrieve the set of breakpoints for this context
+ final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ assert platformBPs != null;
+
+ final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ assert breakpointIDs != null; // fBreakpointIds should be updated in parallel with fPlatformBPs
+
+ // Ensure the breakpoint is not already installed
+ if (platformBPs.containsKey(breakpoint)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_STATE, "Breakpoint already installed", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Update the breakpoint status when all back-end breakpoints have been installed
+ final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Store the platform breakpoint
+ platformBPs.put(breakpoint, attrsList);
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+ rm.done();
+ }
+ };
+
+ // A back-end breakpoint needs to be installed for each specified attributes map.
+ installRM.setDoneCount(attrsList.size());
+
+ // Install the back-end breakpoint(s)
+ for (Map<String, Object> attrs : attrsList) {
+ fBreakpoints.insertBreakpoint(
+ dmc, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) {
+ @Override
+ protected void handleCompleted() {
+ List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
+ if (list == null) {
+ list = new LinkedList<IBreakpointDMContext>();
+ breakpointIDs.put(breakpoint, list);
+ }
+
+ if (isSuccess()) {
+ // Add the breakpoint back-end mapping
+ list.add(getData());
+ } else {
+ // TODO (bug 219841): need to add breakpoint error status tracking
+ // in addition to fBreakpointDMContexts.
+ }
+ installRM.done();
+ }
+ });
+ }
+ }
+
+ /**
+ * Un-install an individual breakpoint on the back-end. For one platform
+ * breakpoint, there could be multiple corresponding back-end breakpoints.
+ *
+ * @param dmc
+ * @param breakpoint
+ * @param rm
+ */
+ private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
+ final RequestMonitor rm)
+ {
+ // Remove completion monitor
+ CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Remove the attributes mapping
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ platformBPs.remove(breakpoint);
+
+ // Remove the back-end mapping
+ Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ if (breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ breakpointIDs.get(breakpoint).clear();
+ breakpointIDs.remove(breakpoint);
+
+ // Update breakpoint status
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ rm.done();
+ }
+ };
+
+ // Remove the back-end breakpoints
+ Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ if (breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
+ int count = 0;
+ if (list != null) {
+ for (IBreakpointDMContext bp : list) {
+ fBreakpoints.removeBreakpoint(bp, removeRM);
+ }
+ count = list.size();
+ }
+ removeRM.setDoneCount(count);
+ }
+
+ /**
+ * Modify an individual breakpoint
+ *
+ * @param context
+ * @param breakpoint
+ * @param attributes
+ * @param rm
+ * @throws CoreException
+ */
+ private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint,
+ final List<Map<String, Object>> newAttrsList0, final IMarkerDelta oldValues, final RequestMonitor rm)
+ {
+ // This method uses several lists to track the changed breakpoints:
+ // commonAttrsList - attributes which have not changed
+ // oldAttrsList - attributes for the breakpoint before the change
+ // newAttrsList - attributes for the breakpoint after the change
+ // oldBpContexts - target-side breakpoints from before the change
+ // newBpContexts - target-side breakpoints after the change
+ // attrDeltasList - changes in the attributes for each attribute map in
+ // oldAttrsList and newAttrsList
+
+ // Get the maps
+ final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(context);
+ final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(context);
+ if (platformBPs == null || breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Get the original breakpoint attributes
+ final List<Map<String, Object>> oldAttrsList0 = platformBPs.get(breakpoint);
+ if (oldAttrsList0 == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Get the list of corresponding back-end breakpoints
+ final List<IBreakpointDMContext> oldBpContexts = new ArrayList<IBreakpointDMContext>(breakpointIDs.get(breakpoint));
+ if (oldBpContexts == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Calculate the list of attributes maps that have not changed.
+ // Immediately add these to the list of new breakpoint contexts,
+ // and remove them from further breakpoint attribute comparisons.
+ final List<Map<String, Object>> commonAttrsList = getCommonAttributeMaps(newAttrsList0, oldAttrsList0);
+ final List<IBreakpointDMContext> newBpContexts = new ArrayList<IBreakpointDMContext>(commonAttrsList.size());
+
+ final List<Map<String, Object>> newAttrsList = new ArrayList<Map<String, Object>>(newAttrsList0);
+ newAttrsList.removeAll(commonAttrsList);
+
+ List<Map<String, Object>> oldAttrsList = new ArrayList<Map<String, Object>>(oldAttrsList0);
+ for (int i = 0; i < oldAttrsList.size(); i++) {
+ if (commonAttrsList.contains(oldAttrsList.get(i))) {
+ if (oldBpContexts.size() > i) {
+ newBpContexts.add(oldBpContexts.remove(i));
+ }
+ }
+ }
+ oldAttrsList.removeAll(commonAttrsList);
+
+ // Create a list of attribute changes. The lenghth of this list will
+ // always be max(oldAttrList.size(), newAttrsList.size()), padded with
+ // null's if oldAttrsList was longer.
+ final List<Map<String, Object>> attrDeltasList = getAttributesDeltas(oldAttrsList, newAttrsList);
+
+ // Create the request monitor that will be called when all
+ // modifying/inserting/removing is complete.
+ final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Save the new list of breakpoint contexts and attributes
+ breakpointIDs.put(breakpoint, newBpContexts);
+ newAttrsList.addAll(commonAttrsList);
+ platformBPs.put(breakpoint, newAttrsList);
+
+ // Update breakpoint status. updateBreakpointStatus() cannot
+ // be called on the executor thread, so we need to
+ // use a Job.
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ super.handleCompleted();
+ }
+ };
+
+ // Set the count, if could be zero if no breakpoints have actually changed.
+ countingRM.setDoneCount(attrDeltasList.size());
+
+ // Process the changed breakpoints.
+ for (int i = 0; i < attrDeltasList.size(); i++) {
+ if (attrDeltasList.get(i) == null) {
+ // The list of new attribute maps was shorter than the old.
+ // Remove the corresponding target-side bp.
+ fBreakpoints.removeBreakpoint(oldBpContexts.get(i), countingRM);
+ } else if ( i >= oldBpContexts.size()) {
+ // The list of new attribute maps was longer, just insert
+ // the new breakpoint
+ final Map<String, Object> attrs = newAttrsList.get(i);
+ fBreakpoints.insertBreakpoint(
+ context, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
+ @Override
+ protected void handleSuccess() {
+ newBpContexts.add(getData());
+ countingRM.done();
+ }
+ });
+ } else if ( !fAttributeTranslator.canUpdateAttributes(oldBpContexts.get(i), attrDeltasList.get(i)) ) {
+ // The attribute translator tells us that the debugger cannot modify the
+ // breakpoint to change the given attributes. Remove the breakpoint
+ // and insert a new one.
+ final Map<String, Object> attrs = newAttrsList.get(i);
+ fBreakpoints.removeBreakpoint(
+ oldBpContexts.get(i),
+ new RequestMonitor(getExecutor(), countingRM) {
+ @Override
+ protected void handleCompleted() {
+ fBreakpoints.insertBreakpoint(
+ context, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ newBpContexts.add(getData());
+ } else {
+ // TODO (bug 219841): need to add breakpoint error status tracking
+ // in addition to fBreakpointDMContexts.
+ }
+ countingRM.done();
+ }
+ });
+ }
+ });
+ } else {
+ // The back end can modify the breakpoint. Update the breakpoint with the
+ // new attributes.
+ final IBreakpointDMContext bpCtx = oldBpContexts.get(i);
+ fBreakpoints.updateBreakpoint(
+ oldBpContexts.get(i), newAttrsList.get(i),
+ new RequestMonitor(getExecutor(), countingRM) {
+ @Override
+ protected void handleSuccess() {
+ newBpContexts.add(bpCtx);
+ countingRM.done();
+ }
+ });
+ }
+ }
+ }
+
+ private List<Map<String, Object>> getCommonAttributeMaps(List<Map<String, Object>> array1, List<Map<String, Object>> array2)
+ {
+ List<Map<String, Object>> intersection = new LinkedList<Map<String, Object>>();
+ List<Map<String, Object>> list2 = new ArrayList<Map<String, Object>>(array2);
+ for (Map<String, Object> array1Map : array1) {
+ if (list2.remove(array1Map)) {
+ intersection.add(array1Map);
+ }
+ }
+ return intersection;
+ }
+
+ /**
+ * Determine the set of modified attributes
+ *
+ * @param oldAttributes
+ * @param newAttributes
+ * @return
+ */
+ private List<Map<String, Object>> getAttributesDeltas(List<Map<String, Object>> oldAttributesList, List<Map<String, Object>> newAttributesList) {
+ List<Map<String, Object>> deltas = new ArrayList<Map<String, Object>>(oldAttributesList.size());
+
+ // Go through the bp attributes common to the old and the new lists and calculate
+ // their deltas.
+ for (int i = 0; i < oldAttributesList.size() && i < newAttributesList.size(); i++) {
+ Map<String, Object> oldAttributes = oldAttributesList.get(i);
+ Map<String, Object> newAttributes = newAttributesList.get(i);
+
+ Map<String, Object> delta = new HashMap<String, Object>();
+
+ Set<String> oldKeySet = oldAttributes.keySet();
+ Set<String> newKeySet = newAttributes.keySet();
+
+ Set<String> commonKeys = new HashSet<String>(newKeySet); commonKeys.retainAll(oldKeySet);
+ Set<String> addedKeys = new HashSet<String>(newKeySet); addedKeys.removeAll(oldKeySet);
+ Set<String> removedKeys = new HashSet<String>(oldKeySet); removedKeys.removeAll(newKeySet);
+
+ // Add the modified attributes
+ for (String key : commonKeys) {
+ if (!(oldAttributes.get(key).equals(newAttributes.get(key))))
+ delta.put(key, newAttributes.get(key));
+ }
+
+ // Add the new attributes
+ for (String key : addedKeys) {
+ delta.put(key, newAttributes.get(key));
+ }
+
+ // Remove the deleted attributes
+ for (String key : removedKeys) {
+ delta.put(key, null);
+ }
+ deltas.add(delta);
+ }
+
+ // Add all the new attributes as deltas
+ for (int i = deltas.size(); i < newAttributesList.size(); i++) {
+ deltas.add(newAttributesList.get(i));
+ }
+
+ // For any old attribute Maps that were removed, insert a null value in the deltas list.
+ for (int i = deltas.size(); i < oldAttributesList.size(); i++) {
+ deltas.add(null);
+ }
+
+ return deltas;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointManagerListener implementation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void breakpointManagerEnablementChanged(boolean enabled) {
+ for (IBreakpoint breakpoint : fBreakpointManager.getBreakpoints()) {
+ breakpointChanged(breakpoint, null);
+ }
+ }
+
+ @ThreadSafe
+ public void breakpointAdded(final IBreakpoint breakpoint) {
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ // Retrieve the breakpoint attributes
+ final List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
+
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ //TODO pp: need to track pending requests
+
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleError() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Install the breakpoint in all the execution contexts
+ for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ installBreakpoint(dmc, breakpoint, attrsArray, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+ });
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointListener implementation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) {
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ // Retrieve the breakpoint attributes
+ final List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
+
+ // Modify the breakpoint in all the target contexts
+ getExecutor().execute( new DsfRunnable() {
+ public void run() {
+
+ // If the breakpoint is currently being updated, queue the request and exit
+ if (fPendingRequests.contains(breakpoint)) {
+ fPendingBreakpoints.add(breakpoint);
+ return;
+ }
+
+ // Keep track of the updates
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+
+ if (!isSuccess()) {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+
+ // Indicate that the pending request has completed
+ fPendingRequests.remove(breakpoint);
+
+ // Process the next pending update for this breakpoint
+ if (fPendingBreakpoints.contains(breakpoint)) {
+ fPendingBreakpoints.remove(breakpoint);
+ new Job("Deferred breakpoint changed job") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ breakpointChanged(breakpoint, delta);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Mark the breakpoint as being updated and go
+ fPendingRequests.add(breakpoint);
+
+ // Modify the breakpoint in all the execution contexts
+ for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ modifyBreakpoint(dmc, breakpoint, attrsArray, delta, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+ });
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+
+ public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) {
+
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ //TODO pp: need to track pending requests
+
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleError() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Remove the breakpoint in all the execution contexts
+ for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ if (fPlatformBPs.get(dmc).remove(breakpoint) != null) {
+ uninstallBreakpoint(dmc, breakpoint, countingRm);
+ } else {
+ // Breakpoint not installed for given context, do nothing.
+ }
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java
new file mode 100644
index 00000000000..fe158fb3073
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+
+@ThreadSafeAndProhibitedFromDsfExecutor("")
+public interface IBreakpointAttributeTranslator {
+
+ public void initialize(BreakpointsMediator mediator);
+
+ public void dispose();
+
+ public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint breakpoint, boolean bpManagerEnabled) throws CoreException;
+
+ public boolean canUpdateAttributes(IBreakpointDMContext bp, Map<String, Object> delta);
+
+ public boolean supportsBreakpoint(IBreakpoint bp);
+
+ public void updateBreakpointStatus(IBreakpoint bp);
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java
new file mode 100644
index 00000000000..1fca358fa57
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Revisited the API
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Breakpoint service interface
+ */
+public interface IBreakpoints extends IDsfService {
+
+
+ /**
+ * Marker interface for a context for which breakpoints can be installed
+ */
+ public interface IBreakpointsTargetDMContext extends IDMContext {}
+
+ /**
+ * Specific breakpoint context
+ */
+ @Immutable
+ public interface IBreakpointDMContext extends IDMContext {}
+
+ /**
+ * Breakpoint events
+ */
+ public interface IBreakpointsChangedEvent extends IDMEvent<IBreakpointsTargetDMContext> {
+ public IBreakpointDMContext[] getBreakpoints();
+ }
+
+ public interface IBreakpointsAddedEvent extends IBreakpointsChangedEvent {}
+ public interface IBreakpointsUpdatedEvent extends IBreakpointsChangedEvent {}
+ public interface IBreakpointsRemovedEvent extends IBreakpointsChangedEvent {}
+
+ /**
+ * Effective breakpoint data as held by the back-end.
+ */
+ public interface IBreakpointDMData {
+
+ public String getBreakpointType();
+ public String getFileName();
+ public int getLineNumber();
+ public String getFunctionName();
+ public IAddress[] getAddresses();
+ public String getCondition();
+ public int getIgnoreCount();
+ public boolean isEnabled();
+ public String getExpression();
+ }
+
+ /**
+ * Retrieves the list of breakpoints installed in the context.
+ *
+ * Use getBreakpointDMData() to retrieve individual breakpoints.
+ *
+ * @param context the execution context of the breakpoint
+ * @param drm the list of breakpoints in the execution context
+ */
+ public void getBreakpoints(IBreakpointsTargetDMContext context,
+ DataRequestMonitor<IBreakpointDMContext[]> drm);
+
+ /**
+ * Retrieves a specific breakpoint from the service.
+ *
+ * @param dmc the breakpoint reference
+ * @param drm the DRM returning the breakpoint data
+ */
+ public void getBreakpointDMData(IBreakpointDMContext dmc,
+ DataRequestMonitor<IBreakpointDMData> drm);
+
+ /**
+ * Adds a breakpoint on the target.
+ *
+ * The breakpoint context is returned in the DRM. The actual breakpoint
+ * object can be later be retrieved using getBreakpoint(bp_context).
+ *
+ * E.g.:
+ * IBreakpointDMContext ref = insertBreakpoint(...);
+ * IBreakpointDMData bp = getBreakpointDMData(ref);
+ *
+ * If the breakpoint is a duplicate (already set previously), then it is up to
+ * the back-end to decide if it is an error or not.
+ *
+ * @param context the execution context of the breakpoint
+ * @param attributes the breakpoint attributes
+ * @param drm the DRM returning the breakpoint reference
+ */
+ public void insertBreakpoint(IBreakpointsTargetDMContext context,
+ Map<String,Object> attributes,
+ DataRequestMonitor<IBreakpointDMContext> drm);
+
+ /**
+ * Removes the breakpoint on the target.
+ *
+ * If the breakpoint doesn't exist, silently ignore it.
+ *
+ * @param dmc the context of the breakpoints to remove
+ * @param rm the asynchronous request monitor
+ */
+ public void removeBreakpoint(IBreakpointDMContext dmc,
+ RequestMonitor rm);
+
+ /**
+ * Updates the breakpoint properties on the target.
+ *
+ * To add/update/remove a property, simply create a map with
+ * the desired value(s) for the given key(s).
+ *
+ * Properties that affect the breakpoint nature or location
+ * should not be updated. Instead, the breakpoint should be
+ * removed then re-inserted.
+ *
+ * A null value is used for removal of a property e.g.:
+ * delta.set(some_key, null);
+ *
+ * @param delta the delta properties
+ * @param dmc the context of the breakpoints to modify
+ * @param rm the asynchronous request monitor
+ */
+ public void updateBreakpoint(IBreakpointDMContext dmc,
+ Map<String,Object> delta, RequestMonitor drm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java
new file mode 100644
index 00000000000..35d61287299
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * Interface for services which use an internal cache for data.
+ * @since 1.1
+ */
+public interface ICachingService {
+
+ /**
+ * Clears the service cache entries which have the given context in their
+ * hierarchy.
+ * @param context Root context to flush. May be <code>null</code> to flush
+ * the entire cache.
+ */
+ public void flushCache(IDMContext context);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java
new file mode 100644
index 00000000000..0f751e32aac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Disassembly service interface
+ */
+public interface IDisassembly extends IDsfService {
+
+ public interface IDisassemblyDMContext extends IDMContext {}
+
+ /**
+ * Gets the disassembled code from an address range.
+ * If [startAddress] == null, disassemble from the instruction pointer.
+ *
+ * @param context Context of the disassembly code
+ * @param startAddress Beginning address
+ * @param endAddress End address
+ * @param drm Disassembled code
+ */
+ public void getInstructions(
+ IDisassemblyDMContext context,
+ BigInteger startAddress,
+ BigInteger endAddress,
+ DataRequestMonitor<IInstruction[]> drm);
+
+ /**
+ * Gets the disassembled code from a file location.
+ * If [lines] == -1, the whole function is disassembled.
+ *
+ * @param context Context of the disassembly code
+ * @param filename File to disassemble
+ * @param linenum Line number within the file
+ * @param lines Number of lines of disassembled code to produce
+ * @param drm Disassembled code
+ */
+ public void getInstructions(
+ IDisassemblyDMContext context,
+ String filename,
+ int linenum,
+ int lines,
+ DataRequestMonitor<IInstruction[]> drm);
+
+ /**
+ * Gets the mixed disassembled code from an address range.
+ * If [startAddress] == null, disassemble from the instruction pointer.
+ *
+ * @param context Context of the disassembly code
+ * @param startAddress Beginning address
+ * @param endAddress End address
+ * @param drm Disassembled code
+ */
+ public void getMixedInstructions(
+ IDisassemblyDMContext context,
+ BigInteger startAddress,
+ BigInteger endAddress,
+ DataRequestMonitor<IMixedInstruction[]> drm);
+
+ /**
+ * Gets the mixed disassembled code from a file location.
+ * If [lines] == -1, the whole function is disassembled.
+ *
+ * @param context Context of the disassembly code
+ * @param filename File to disassemble
+ * @param linenum Line number within the file
+ * @param lines Number of lines of disassembled code to produce
+ * @param drm Disassembled code
+ */
+ public void getMixedInstructions(
+ IDisassemblyDMContext context,
+ String filename,
+ int linenum,
+ int lines,
+ DataRequestMonitor<IMixedInstruction[]> drm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java
new file mode 100644
index 00000000000..e71d8091b2c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.debug.core.model.ICBreakpointExtension;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * An extension to {@link ICBreakpoint} with model-specific breakpoint
+ * attributes. Different debug models can use the standard C breakpoints that
+ * extend the basic <code>ICBreakpoint</code>. The can use this extension
+ * mechanism to edit and store model-specific data in the original breakpoint
+ * object.
+ *
+ * A breakpoint extension is defined by an extension of kind
+ * <code>"org.eclipse.cdt.debug.core.BreakpointExtension"</code></li>.
+ * The <code>ICBreakpoint</code> implementation instantiates breakpoint
+ * extensions registered for its specific marker type when a client requests
+ * extensions for a given debug model type. Thus the extension classes and
+ * plugins that declare them are not loaded unless requested by a client.
+ *
+ * @see ICBreakpoint#getExtension(String, Class)
+ */
+public interface IDsfBreakpointExtension extends ICBreakpointExtension {
+
+ public void setTargetFilter( IContainerDMContext target ) throws CoreException;
+ public void removeTargetFilter( IContainerDMContext target ) throws CoreException;
+ public IContainerDMContext[] getTargetFilters() throws CoreException;
+
+ public void setThreadFilters( IExecutionDMContext[] threads ) throws CoreException;
+ public void removeThreadFilters( IExecutionDMContext[] threads ) throws CoreException;
+ public IExecutionDMContext[] getThreadFilters( IContainerDMContext target ) throws CoreException;
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java
new file mode 100644
index 00000000000..5b3aab48852
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * A factory to create DSF services. Using this interface allows
+ * to easily have different service implementation for different backends.
+ * @since 1.1
+ */
+public interface IDsfDebugServicesFactory {
+ <V> V createService(Class<V> clazz, DsfSession session, Object ... optionalArguments);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
new file mode 100644
index 00000000000..adedef76125
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Update for GDB/MI
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+
+/**
+ * Expressions service provides access to the debugger's expression evaluator. This service has
+ * dependencies on the Stack service, as it is be used to provide context for an
+ * expression to be evaluated.
+ */
+@SuppressWarnings("nls")
+public interface IExpressions extends IFormattedValues {
+
+ /**
+ * Expression context.
+ */
+ public interface IExpressionDMContext extends IFormattedDataDMContext {
+ /**
+ * Returns a fully qualified expression string represented by this context. This
+ * expression string is the same as the string that is sent to the debug engine to be
+ * evaluated in context of a stack frame, thread, or a symbol context.
+ */
+ String getExpression();
+ }
+
+ /**
+ * The address and size of an expression.
+ */
+ public interface IExpressionDMAddress {
+ IAddress getAddress();
+ int getSize();
+ }
+
+ /**
+ * This is the model data interface that corresponds to IExpressionDMContext.
+ */
+ public interface IExpressionDMData extends IDMData {
+ // These static fields define the possible return values of method getTypeId().
+
+ final static String TYPEID_UNKNOWN = "TYPEID_UNKNOWN";
+ final static String TYPEID_INTEGER = "TYPEID_INTEGER";
+ final static String TYPEID_CHAR = "TYPEID_CHAR";
+ final static String TYPEID_FLOAT = "TYPEID_FLOAT";
+ final static String TYPEID_DOUBLE = "TYPEID_DOUBLE";
+ final static String TYPEID_OPAQUE = "TYPEID_OPAQUE";
+
+ /**
+ * This enumerates the possible basic types that an expression can have.
+ *
+ * @see getBasicType().
+ */
+ enum BasicType {
+ unknown, // Unknown type.
+ basic, // Scalar type (e.g., int, short, float).
+ pointer, // Pointer to anything.
+ array, // Array of anything.
+ composite, // Struct, union, or class.
+ enumeration, // Enumeration.
+ function // Function.
+ }
+
+ /**
+ * If this expression is a sub-expression of another expression, this method returns
+ * the expression relative to the parent of this expression. Otherwise this method
+ * will return the same string as {@link #getExpression()}.
+ */
+ String getName();
+
+ /**
+ * @return A BasicType enumerator describing the basic type of an expression.
+ */
+ BasicType getBasicType();
+
+ /**
+ * @return The source code type of this expression. This is a string such as "struct Foo", "short",
+ * "int *", "mytypedef", "(int *)[]", "enum Bar". If the debugger backend cannot supply
+ * this information, this method returns "<UNKNOWN>" (the angle brackets are there just in
+ * case there is a type named "UNKNOWN" in the application).
+ */
+ String getTypeName();
+
+ /**
+ * This method needs to be defined. For now, this returns the empty string.
+ */
+ String getEncoding();
+
+ /**
+ * @return One of the TYPEID_* static field values defined by this interface.
+ */
+ String getTypeId();
+
+ /**
+ * @return A Map in which the keys are strings that are the names of enumerators in the enumeration
+ * that is the value of this expression and the values are the integer values of the
+ * enumerators. If the expression type is not an enumeration, this returns an empty Map.
+ */
+ Map<String, Integer> getEnumerations();
+
+ /**
+ * This method needs to be defined.
+ */
+ IRegisters.IRegisterDMContext getRegister();
+ }
+
+ /**
+ * Event indicating that a given expression is changed. If an expression is changed, it's implied that all
+ * the children of that expression are changed too.
+ */
+ public interface IExpressionChangedDMEvent extends IDMEvent<IExpressionDMContext> {}
+
+ /**
+ * Retrieves the expression DM data object for the given expression context(<tt>dmc</tt>).
+ *
+ * @param dmc
+ * The ExpressionDMC for the expression to be evaluated.
+ * @param rm
+ * The data request monitor that will contain the requested data
+ */
+ void getExpressionData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMData> rm);
+
+ /**
+ * Retrieves the address and size of an expression given by the expression context(<tt>dmc</tt>).
+ * Non-lvalues do not have an addresses (e.g., "x + 5"). When the expression
+- * has no address, the data request monitor will contain null.
+ *
+ * @param dmc
+ * The ExpressionDMC for the expression
+ * @param rm
+ * The data request monitor that will contain the requested data
+ */
+ void getExpressionAddressData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMAddress> rm);
+
+ /**
+ * Returns the data model context object for the specified expression in the context
+ * specified by <b>ctx</b>.
+ *
+ * @param ctx: Context in which to evaluate the expression. This context could include the
+ * PC location, stack frame, thread, or just a symbol context.
+ *
+ * @param expression: The expression to evaluate.
+ *
+ * @return An expression data model context object that must be passed to
+ * getModelData() to obtain the value of the expression.
+ */
+ IExpressionDMContext createExpression(IDMContext ctx, String expression);
+
+ /**
+ * Retrieves the sub-expressions of the given expression. Sub-expressions are fields of a struct, union,
+ * or class, the enumerators of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor containing an array of all sub-expressions
+ */
+ void getSubExpressions(IExpressionDMContext exprCtx, DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * Retrieves a particular range of sub-expressions of the given expression.
+ * Sub-expressions are fields of a struct, union, or class, the enumerators
+ * of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ * startIndex: Index of the first sub-expression to retrieve
+ * length: Total number of sub-expressions to retrieve
+ *
+ * @param rm: Request completion monitor containing an array of the requested
+ * range of sub-expressions
+ */
+ void getSubExpressions(IExpressionDMContext exprCtx, int startIndex, int length,
+ DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * Retrieves the number of sub-expressions of the given expression. Sub-expressions are fields of a struct, union,
+ * or class, the enumerators of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor containing the number of sub-expressions
+ * of the specified expression
+ */
+ void getSubExpressionCount(IExpressionDMContext exprCtx, DataRequestMonitor<Integer> rm);
+
+ /**
+ * For object oriented languages, this method returns the expressions representing base types of
+ * the given expression type.
+ *
+ * @param exprContext: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor.
+ */
+ void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * This method indicates if an expression can be written to.
+ *
+ * @param expressionContext: The data model context representing an expression.
+ *
+ * @param rm: Data Request monitor containing True if this expression's value can be edited. False otherwise.
+ */
+ void canWriteExpression(IExpressionDMContext expressionContext, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * This method supports the writing/modifying the value of the expression.
+ *
+ * @param expressionContext: The data model context representing an expression.
+ *
+ * @param expressionValue: The new value of the expression as a String.
+ *
+ * @param formatId: The format ID specifying the format of parameter <b>expressionValue</b>.
+ *
+ * @param rm: Request completion monitor.
+ */
+ void writeExpression(IExpressionDMContext expressionContext, String expressionValue, String formatId, RequestMonitor rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java
new file mode 100644
index 00000000000..5cc665aebb3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+public interface IFormattedValues extends IDMService {
+
+ /** Marker interface for a DMC that has a formatted value. */
+ public interface IFormattedDataDMContext extends IDMContext {}
+
+ /**
+ * These strings represent the standard known formats for any bit stream
+ * which needs to be formatted. These ID's as well as others which may be
+ * specifically available from the backend are what is returned from the
+ * getID() method.
+ */
+ public final static String HEX_FORMAT = "HEX.Format" ; //$NON-NLS-1$
+ public final static String OCTAL_FORMAT = "OCTAL.Format" ; //$NON-NLS-1$
+ public final static String NATURAL_FORMAT = "NATURAL.Format" ; //$NON-NLS-1$
+ public final static String BINARY_FORMAT = "BINARY.Format" ; //$NON-NLS-1$
+ public final static String DECIMAL_FORMAT = "DECIMAL.Format" ; //$NON-NLS-1$
+ public final static String STRING_FORMAT = "STRING.Format" ; //$NON-NLS-1$
+
+ /**
+ * Retrieves the formats that the given data is available in.
+ * This method is asynchronous because the service may need to retrieve
+ * information from the backend in order to determine what formats are
+ * available for the given data context.
+ *
+ * @param dmc Context for which to retrieve available formats.
+ * @param rm Completion monitor returns an array of support formatIds.
+ */
+ public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm);
+
+ /**
+ * Creates a FormattedValueDMContext representing the given formatId.
+ *
+ * @param dmc Parent context for the context that is being created
+ * @param formatId Defines format to be used for the returned context.
+ */
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId);
+
+ /**
+ * Retrieves the DM data associated with given formatted value context.
+ * @param dmc Context to retrieve the value for.
+ * @param rm Completion monitor returns the formatted value.
+ */
+ public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm);
+
+
+ /**
+ * DMC that represents a value with specific format. The format ID can be
+ * persisted and used for comparison.
+ */
+
+ public static class FormattedValueDMContext extends AbstractDMContext
+ {
+ private final String fFormatID;
+
+ public FormattedValueDMContext(IDMService service, IDMContext parent, String formatId) {
+ super(service, new IDMContext[] { parent });
+ fFormatID = formatId;
+ }
+
+ public FormattedValueDMContext(String sessionId, IDMContext parent, String formatId) {
+ super(sessionId, new IDMContext[] { parent });
+ fFormatID = formatId;
+ }
+
+ public String getFormatID() {
+ return fFormatID;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return baseEquals(obj) && ((FormattedValueDMContext)obj).getFormatID().equals(getFormatID());
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + getFormatID().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".format(" + getFormatID() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ public static class FormattedValueDMData implements IDMData {
+
+ private final String fValue;
+
+ public FormattedValueDMData(String value) {
+ fValue = value;
+ }
+
+ public String getFormattedValue() {
+ return fValue;
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java
new file mode 100644
index 00000000000..dd547ff5746
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.math.BigInteger;
+
+/**
+ * Represents an assembly instruction
+ */
+public interface IInstruction {
+
+ /**
+ * @return the instruction address.
+ */
+ BigInteger getAdress();
+
+ /**
+ * @return the function name.
+ */
+ String getFuntionName();
+
+ /**
+ * @return the offset of this machine instruction
+ */
+ long getOffset();
+
+ /**
+ * @return the instruction.
+ */
+ String getInstruction();
+
+ /**
+ * @return the opcode
+ */
+ String getOpcode();
+
+ /**
+ * @return any arguments to the instruction
+ */
+ String getArgs();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java
new file mode 100644
index 00000000000..a8444301527
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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
+ * Ericsson AB - extended the API for IMemoryBlockExtension
+ * Ericsson AB - added support for 64 bit processors
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * Service for accessing memory. Memory contexts are not meant to be
+ * represented in tree or table views, so it doesn't need to implement
+ * IDMService interface.
+ */
+public interface IMemory extends IDsfService {
+
+ public interface IMemoryDMContext extends IDMContext {}
+
+ /**
+ * Event generated every time a range of bytes is modified.
+ *
+ * A client wishing to receive such events has to register as a service
+ * event listener and implement the corresponding eventDispatched method.
+ *
+ * E.g.:
+ *
+ * MyMemoryBlock(MIRunControl fRunControl)
+ * {
+ * ...
+ * fRunControl.getSession().addServiceEventListener(MyMemoryBlock.this, null);
+ * ...
+ * }
+ *
+ * @DsfServiceEventHandler
+ * public void eventDispatched(MemoryChangedEvent e) {
+ * IDMContext<?> context = e.getContext();
+ * IAddress[] addresses = e.getAddresses();
+ * // do whatever...
+ * }
+ */
+ public interface IMemoryChangedEvent extends IDMEvent<IMemoryDMContext> {
+ IAddress[] getAddresses();
+ }
+
+ /**
+ * Reads a memory block from the target.
+ *
+ * An asynchronous memory read request at [address] + [offset] for
+ * [count] memory items, each of size [word_size] bytes, will be
+ * issued to the target. The result will be stored in [drm] upon
+ * completion of the call.
+ *
+ * The [drm] result buffer will be of size [word_size] * [count]. The
+ * successfully read bytes will have their MemoryByte.READABLE flag
+ * set while the bytes in error (unreachable/bad memory) will have their
+ * flag byte set to 0. The bytes will respect the target "endianness".
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of data elements to read
+ * @param drm the asynchronous data request monitor
+ */
+ public void getMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, DataRequestMonitor<MemoryByte[]> drm);
+
+ /**
+ * Writes a memory block on the target.
+ *
+ * An asynchronous memory write request at [address] + [offset] for
+ * [count] * [word_size] bytes will be issued to the target.
+ *
+ * The [buffer] must hold at least [count] * [word_size] bytes.
+ *
+ * A MemoryChangedEvent will be generated for the range of addresses.
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of data elements to write
+ * @param buffer the source buffer
+ * @param rm the asynchronous data request monitor
+ */
+ public void setMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, byte[] buffer, RequestMonitor rm);
+
+ /**
+ * Writes [pattern] at memory [address] + [offset], [count] times.
+ *
+ * A MemoryChangedEvent will be generated for the range of addresses.
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of times [pattern] will be written
+ * @param pattern the source buffer
+ * @param rm the asynchronous data request monitor
+ */
+ public void fillMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, byte[] pattern, RequestMonitor rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java
new file mode 100644
index 00000000000..511f81f1785
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+/**
+ * Represents the assembly instruction(s) corresponding to a source line
+ */
+public interface IMixedInstruction {
+
+ /**
+ * @return the file name
+ */
+ String getFileName();
+
+ /**
+ * @return the line Number.
+ */
+ int getLineNumber();
+
+ /**
+ * @return the array of instruction.
+ */
+ IInstruction[] getInstructions();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java
new file mode 100644
index 00000000000..c01ea5db89a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Debugger service representing module handling logic of a debugger.
+ */
+public interface IModules extends IDsfService {
+
+ /**
+ * Symbol context represents the space into which module symbols are loaded.
+ * Traditionally symbols are loaded in context of a process, but for other
+ * types of debugging, like kernel or no-OS debugging, it's useful to
+ * separate the concept of a symbol context from a process.
+ */
+ public interface ISymbolDMContext extends IDMContext {}
+
+ /**
+ * Module context represents a single module that is loaded.
+ */
+ public interface IModuleDMContext extends IDMContext {}
+
+ /**
+ * Event indicating a change in the symbol information for given context.
+ */
+ public interface ModulesChangedDMEvent extends IDMEvent<ISymbolDMContext> {}
+
+ /**
+ * Specific event identifying that a new module was loaded into a
+ * symbol context.
+ */
+ public interface ModuleLoadedDMEvent extends ModulesChangedDMEvent {
+ /** Returns context of the module that was loaded */
+ IModuleDMContext getLoadedModuleContext();
+ }
+
+ public interface ModuleUnloadedDMEvent extends ModulesChangedDMEvent {
+ /** Returns context of the module that was un-loaded */
+ IModuleDMContext getUnloadedModuleContext();
+ }
+
+ /** Module information. */
+ public interface IModuleDMData {
+ String getName();
+ String getFile();
+ long getTimeStamp();
+ String getBaseAddress();
+ String getToAddress();
+ boolean isSymbolsLoaded();
+ long getSize();
+ }
+
+ /** Line information about a particular address */
+ public interface LineInfo {
+ IAddress getAddress();
+ String getSourceFile();
+ int getStartLine();
+ int getStartColumn();
+ int getEndLine();
+ int getEndColumn();
+ }
+
+ /** Address information about a particular file/line */
+ public interface AddressRange {
+ IAddress getStartAddress();
+ IAddress getEndAddress();
+ }
+
+ void getModuleData(IModuleDMContext dmc, DataRequestMonitor<IModuleDMData> rm);
+
+ /**
+ * Retreives the list of modules loaded in given symbol context.
+ */
+ void getModules(ISymbolDMContext symCtx, DataRequestMonitor<IModuleDMContext[]> rm);
+
+ /**
+ * Calculates the line numbers corresponding to the given address.
+ */
+ void calcLineInfo(ISymbolDMContext symCtx, IAddress address, DataRequestMonitor<LineInfo[]> rm);
+
+ /**
+ * Calculates the addresses corresponding to the given source file location.
+ */
+ void calcAddressInfo(ISymbolDMContext symCtx, String file, int line, int col, DataRequestMonitor<AddressRange[]> rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java
new file mode 100644
index 00000000000..db65c2c89ed
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Updated for latest DSF version
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * This interface provides access to the OS's process
+ * information, manipulation methods, and debugging methods.
+ * This service provides a relatively simple interface for
+ * manipulating processes as compared with a full-blown
+ * remote target debugger.
+ * @since 1.1
+ */
+public interface IProcesses extends IDMService {
+
+ /**
+ * A thread as known by the OS.
+ * This context is kept different than {@link IRunControl.IExecutionDMContext}
+ * because the OS id of a thread may not be the same as the thread id used by
+ * the debugger when doing run control operations.
+ */
+ public interface IThreadDMContext extends IDMContext {}
+
+ /**
+ * A process as known by the OS.
+ * This context is kept different than {@link IRunControl.IContainerDMContext}
+ * because the OS id of a process may not be the same as the process id used by
+ * the debugger when doing run control operations.
+ */
+ public interface IProcessDMContext extends IThreadDMContext {}
+
+ /**
+ * Interface for thread and process object data. This data provides a link
+ * to the lower level debugger services, in form of execution contexts.
+ */
+ public interface IThreadDMData extends IDMData {
+ String getName();
+ String getId();
+ boolean isDebuggerAttached();
+ }
+
+ /**
+ * Event indicating that process data has changed.
+ */
+ public interface ProcessChangedDMEvent extends IDMEvent<IProcessDMContext> {}
+
+ /**
+ * Retrieves thread or process data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm);
+
+ /**
+ * Retrieves the debugging context that characterizes the specified thread
+ * or process context.
+ *
+ * @param dmc The thread or process dmc for which we want the debugging context
+ * @param rm The request monitor that will contain the debugging context.
+ * null if no such context exists
+ */
+ public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Retrieves the current list of processes running on target.
+ * @param dmc The processor or core for which to list all processes
+ * @param rm Request completion monitor, to be filled in with array of process contexts.
+ */
+ void getRunningProcesses(IDMContext dmc, DataRequestMonitor<IProcessDMContext[]> rm);
+
+ /**
+ * Checks whether it is possible to attach the debugger to a new process.
+ * @param dmc The processor or core on which we want to attach to a process.
+ * @param rm Return if it is possible to attach.
+ */
+ void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Attaches debugger to the given process.
+ * When attaching to a process, a debugging context can now be used to characterize the process.
+ * This method can optionally choose to return this IDMContext inside the DataRequestMonitor.
+ * This can be useful for backends that do not have the ability to obtain the different
+ * debugging IDMContexts through {@link #getProcessesBeingDebugged(IDMContext, DataRequestMonitor)
+ */
+ void attachDebuggerToProcess(IProcessDMContext procCtx, DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Checks whether it is possible to detach the debugger from the specified process.
+ * @param dmc The debugging context from which we want to detach. This context
+ * should have IProcessDMContext as an ancestor.
+ * @param rm Return if it is possible to detach.
+ */
+ void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Detaches debugger from the given process.
+ * @param dmc The debugging context from which we want to detach. This context
+ * should have IProcessDMContext as an ancestor.
+ */
+ void detachDebuggerFromProcess(IDMContext dmc, RequestMonitor requestMonitor);
+
+ /**
+ * Checks whether it is possible to run a new process.
+ * @param dmc The processor or core on which we want to run a new process.
+ * @param rm Return if it is possible to run a new process.
+ */
+ void isRunNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Starts a new process.
+ * @param dmc The processor or core on which we want to run a new process.
+ * @param file Process image to use for the new process.
+ * @param attributes Attributes that give information on the process to be debugged
+ * @param rm Request completion monitor, to be filled in with the process context.
+ */
+ void runNewProcess(IDMContext dmc,
+ String file,
+ Map<String, Object> attributes,
+ DataRequestMonitor<IProcessDMContext> rm);
+
+ /**
+ * Checks whether it is possible to start a new process with the debugger attached
+ * @param dmc The processor or core on which we want to start and debug the new process.
+ * @param rm Return if it is possible to start a new process with the debugger attached.
+ */
+ void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Starts a new process with the debugger attached.
+ * @param dmc The processor or core on which we want to start and debug the new process.
+ * @param file Process image to use for the new process.
+ * @param attributes Attributes that give information on the process to be debugged
+ * @param rm Request completion monitor, to be filled in with the
+ * debugging context that can now be used to characterize the process
+ */
+ void debugNewProcess(IDMContext dmc,
+ String file,
+ Map<String, Object> attributes,
+ DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Retrieves the list of processes which are currently under debugger control.
+ *
+ * @param dmc The processor or core for which to list processes being debugged
+ * @param rm Request completion monitor which contains all debugging contexts representing
+ * the processes being debugged. Note that each of these contexts should also have
+ * IProcessDMContext as a parent.
+ */
+ void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm);
+
+ /**
+ * Checks whether the given process or thread can be terminated.
+ * @param thread Thread or process to terminate.
+ * @param rm Return token.
+ */
+ void canTerminate(IThreadDMContext thread, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Terminates the selected process or thread.
+ * @param thread Thread or process to terminate.
+ * @param rm Request completion monitor, indicates success or failure.
+ */
+ void terminate(IThreadDMContext thread, RequestMonitor requestMonitor);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java
new file mode 100644
index 00000000000..7397ead772b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+
+/**
+ * Service for accessing register data.
+ */
+public interface IRegisters extends IFormattedValues {
+
+ /**
+ * Event indicating groups have changed. The type of context returned by this
+ * event is generic, because different implementations of the the register service
+ * could configure register groups using different contexts. Some implementations
+ * could configure different register groups for each execution context, other
+ * services may have a global list of groups.
+ */
+ public interface IGroupsChangedDMEvent extends IDMEvent<IDMContext> {}
+
+ /** Register group context */
+ public interface IRegisterGroupDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating values for the group have changed. */
+ public interface IGroupChangedDMEvent extends IDMEvent<IRegisterGroupDMContext> {}
+
+ /** Event indicating registers in a group have changed. */
+ public interface IRegistersChangedDMEvent extends IDMEvent<IRegisterGroupDMContext> {}
+
+ /**
+ * Register groups only have a name and description. Sub groups and registers are
+ * retrieved through the service interface.
+ */
+ public interface IRegisterGroupDMData extends IDMData {
+ public String getName();
+ public String getDescription();
+ }
+
+ /** Register context */
+ public interface IRegisterDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating register value changed. */
+ public interface IRegisterChangedDMEvent extends IDMEvent<IRegisterDMContext> {}
+
+ /** Register information */
+ public interface IRegisterDMData extends IDMData {
+ String getName();
+ String getDescription();
+ boolean isReadable();
+ boolean isReadOnce();
+ boolean isWriteable();
+ boolean isWriteOnce();
+ boolean hasSideEffects();
+ boolean isVolatile();
+ boolean isFloat();
+ }
+
+ /** Bit field context */
+ public interface IBitFieldDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating register value changed. */
+ public interface IBitFieldChangedDMEvent extends IDMEvent<IBitFieldDMContext> {}
+
+ /**
+ * Bitfield data, big groups and mnemonics are retrieved at the same
+ * time as rest of bit field data
+ */
+ public interface IBitFieldDMData extends IDMData {
+ String getName();
+ String getDescription();
+ boolean isReadable();
+ boolean isReadOnce();
+ boolean isWriteable();
+ boolean isWriteOnce();
+ boolean hasSideEffects();
+ boolean isZeroBasedNumbering();
+ boolean isZeroBitLeftMost();
+ IBitGroup[] getBitGroup();
+ IMnemonic[] getMnemonics();
+ IMnemonic getCurrentMnemonicValue();
+ }
+
+ /** Bit group definition */
+ public interface IBitGroup {
+ int startBit();
+ int bitCount();
+ }
+
+ /** Bit field mnemonic */
+ public interface IMnemonic {
+ String getShortName();
+ String getLongName();
+ }
+
+ /**
+ * Retrieves the list of register groups.
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterGroups(IDMContext ctx, DataRequestMonitor<IRegisterGroupDMContext[]> rm);
+
+ /**
+ * Retrieves the list of registers for the given context. The given context could include
+ * a register group and an execution context or just an execution context, in which case all
+ * registers for all groups should be returned.
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getRegisters(IDMContext ctx, DataRequestMonitor<IRegisterDMContext[]> rm);
+
+ /**
+ * Retrieves bit fields for given register
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getBitFields(IDMContext ctx, DataRequestMonitor<IBitFieldDMContext[]> rm);
+
+ /**
+ * Retrieves a Register Group context. The given context could include a register
+ * group and an execution context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of group being requested
+ * @param rm Request completion monitor.
+ */
+ void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm);
+
+ /**
+ * Retrieves a Register context. The given context could include a register group and an execution
+ * context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of register being requested
+ * @param rm Request completion monitor.
+ */
+ void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm);
+
+ /**
+ * Retrieves bit field context. The given context could include a register and an execution
+ * context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of bit field being requested
+ * @param rm Request completion monitor.
+ */
+ void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm);
+
+ /**
+ * Retrieves register group data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterGroupData(IRegisterGroupDMContext dmc, DataRequestMonitor<IRegisterGroupDMData> rm);
+
+ /**
+ * Retrieves register data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterData(IRegisterDMContext dmc , DataRequestMonitor<IRegisterDMData> rm);
+
+ /**
+ * Retrieves bit field data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getBitFieldData(IBitFieldDMContext dmc , DataRequestMonitor<IBitFieldDMData> rm);
+
+
+
+ /**
+ * Writes a register value for a given register to the target
+ * @param regCtx Context containing the register.
+ * @param regValue Value of the register to be written.
+ * @param formatId Format of the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeRegister(IRegisterDMContext regCtx, String regValue, String formatId, RequestMonitor rm);
+
+ /**
+ * Writes a bit field value for a given bit field to the target
+ * @param bitFieldCtx Context containing the bit field.
+ * @param bitFieldValue Value of the bit field to be written.
+ * @param formatId Format of the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeBitField(IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, RequestMonitor rm);
+
+ /**
+ * Writes a bit field value for a given bit field to the target
+ * @param bitFieldCtx Context containing the bit field.
+ * @param mnemonic Mnemonic which represents the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java
new file mode 100644
index 00000000000..181d2f44418
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Modified for additional functionality
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * This interface provides access to controlling and monitoring the execution
+ * state of a process being debugged. This interface does not actually
+ * provide methods for creating or destroying execution contexts, it doesn't
+ * even have methods for getting labels. That's because it is expected that
+ * higher level services, ones that deal with processes, kernels, or target
+ * features will provide that functionality.
+ */
+public interface IRunControl extends IDMService
+{
+ /**
+ * Execution context is the object on which run control operations can be
+ * performed. A lot of higher-level services reference this context to build
+ * functionality on top of it, e.g. stack, expression evaluation, registers, etc.
+ */
+ public interface IExecutionDMContext extends IDMContext {}
+
+ /**
+ * Context representing a process, kernel, or some other logical container
+ * for execution contexts, which by itself can perform run-control
+ * operations.
+ */
+
+ public interface IContainerDMContext extends IExecutionDMContext {}
+
+ /** Flag indicating reason context state change. */
+ public enum StateChangeReason { UNKNOWN, USER_REQUEST, STEP, BREAKPOINT, EXCEPTION, CONTAINER, WATCHPOINT, SIGNAL, SHAREDLIB, ERROR, EVALUATION };
+
+ /**
+ * Indicates that the given thread has suspended.
+ */
+ public interface ISuspendedDMEvent extends IDMEvent<IExecutionDMContext> {
+ StateChangeReason getReason();
+ }
+
+ /**
+ * Indicates that the given thread has resumed.
+ */
+ public interface IResumedDMEvent extends IDMEvent<IExecutionDMContext> {
+ StateChangeReason getReason();
+ }
+
+ /**
+ * Indicates that the given container has suspended.
+ */
+ public interface IContainerSuspendedDMEvent extends ISuspendedDMEvent {
+ /**
+ * Returns the contexts which triggered the resume, which could be
+ * an empty array if not known.
+ */
+ IExecutionDMContext[] getTriggeringContexts();
+ }
+
+ /**
+ * Indicates that the given container has resumed.
+ */
+ public interface IContainerResumedDMEvent extends IResumedDMEvent {
+ /**
+ * Returns the contexts which triggered the resume, which could be an
+ * empty array if not known.
+ */
+ IExecutionDMContext[] getTriggeringContexts();
+ }
+
+ /**
+ * Indicates that a new execution context was started.
+ */
+ public interface IStartedDMEvent extends IDMEvent<IExecutionDMContext> {}
+
+ /**
+ * Indicates that an execution context has exited.
+ */
+ public interface IExitedDMEvent extends IDMEvent<IExecutionDMContext> {}
+
+ /**
+ * Display information for an execution context.
+ */
+ public interface IExecutionDMData extends IDMData {
+ StateChangeReason getStateChangeReason();
+ }
+
+ /**
+ * Retrieves execution data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm);
+
+ /**
+ * Returns execution contexts belonging to the given container context.
+ */
+ public void getExecutionContexts(IContainerDMContext c, DataRequestMonitor<IExecutionDMContext[]> rm);
+
+ /*
+ * Run control commands. They all require the IExecutionContext object on
+ * which they perform the operations.
+ */
+ void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm);
+ void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm);
+ boolean isSuspended(IExecutionDMContext context);
+ void resume(IExecutionDMContext context, RequestMonitor requestMonitor);
+ void suspend(IExecutionDMContext context, RequestMonitor requestMonitor);
+ public enum StepType { STEP_OVER, STEP_INTO, STEP_RETURN, INSTRUCTION_STEP_OVER, INSTRUCTION_STEP_INTO, INSTRUCTION_STEP_RETUTRN };
+ boolean isStepping(IExecutionDMContext context);
+ void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm);
+ void step(IExecutionDMContext context, StepType stepType, RequestMonitor requestMonitor);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java
new file mode 100644
index 00000000000..3fba2d7da39
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ *
+ */
+public interface ISignals extends IDsfService {
+ /**
+ * Marker interface for a context for which signals can be set.
+ */
+ public interface ISignalsDMContext extends IDMContext {};
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java
new file mode 100644
index 00000000000..b92dd3c83b1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Service for mapping debugger paths to host paths. This service is needed
+ * primarily by other services that need to access source-path mappings, such
+ * as the breakpoints service. For UI components, the platform source lookup
+ * interfaces could be sufficient.
+ */
+public interface ISourceLookup extends IDsfService {
+
+ public interface ISourceLookupDMContext extends IDMContext {}
+
+ public interface ISourceLookupChangedDMEvent extends IDMEvent<ISourceLookupDMContext> {}
+
+ /**
+ * Retrieves the host source object for given debugger path string.
+ */
+ void getSource(ISourceLookupDMContext ctx, String debuggerPath, DataRequestMonitor<Object> rm);
+
+ /**
+ * Retrieves the debugger path string for given host source object.
+ */
+ void getDebuggerPath(ISourceLookupDMContext ctx, Object source, DataRequestMonitor<String> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java
new file mode 100644
index 00000000000..d6003483f94
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2006,, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * Stack service provides access to stack information for a
+ * given execution context.
+ */
+public interface IStack extends IDMService {
+
+ /**
+ * Context for a specific stack frame. Besides allowing access to stack
+ * frame data, this context is used by other services that require a stack
+ * frame for evaluation.
+ */
+ public interface IFrameDMContext extends IDMContext {
+ int getLevel();
+ }
+
+ /**
+ * Stack frame information.
+ */
+ public interface IFrameDMData extends IDMData {
+ IAddress getAddress();
+ String getFile();
+ String getFunction();
+ int getLine();
+ int getColumn();
+ }
+
+ /**
+ * Variable context. This context only provides access to limited
+ * expression information. For displaying complete information,
+ * Expressions service should be used.
+ */
+ public interface IVariableDMContext extends IDMContext {}
+
+ /**
+ * Stack frame variable information.
+ */
+ public interface IVariableDMData extends IDMData {
+ String getName();
+ String getValue();
+ }
+
+ /**
+ * Retrieves stack frame data for given context.
+ * @param frameDmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getFrameData(final IFrameDMContext frameDmc, DataRequestMonitor<IFrameDMData> rm);
+
+ /**
+ * Retrieves stack frame variable data for given context.
+ * @param variableDmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getVariableData(IVariableDMContext variableDmc, DataRequestMonitor<IVariableDMData> rm);
+
+ /**
+ * Retrieves list of stack frames for the given execution context. Request
+ * will fail if the stack frame data is not available.
+ */
+ void getFrames(IDMContext execContext, DataRequestMonitor<IFrameDMContext[]> rm);
+
+ /**
+ * Retrieves the top stack frame for the given execution context.
+ * Retrieving just the top frame DMC and corresponding data can be much
+ * more efficient than just retrieving the whole stack, before the data
+ * is often included in the stopped event. Also for some UI functionality,
+ * such as setpping, only top stack frame is often needed.
+ * @param execContext
+ * @param rm
+ */
+ void getTopFrame(IDMContext execContext, DataRequestMonitor<IFrameDMContext> rm);
+
+ /**
+ * Retrieves variables which were arguments to the stack frame's function.
+ */
+ void getArguments(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm);
+
+ /**
+ * Retrieves variables local to the stack frame, including arguments.
+ */
+ void getLocals(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm);
+
+ /**
+ * Retrieves the number of stack frames available for the given context..
+ * @param dmc Context to retrieve data for.
+ * @param The maximum depth of stack to calculate. Should be 0 to calculate
+ * depth with no limit.
+ * @param rm Callback
+ */
+ void getStackDepth(IDMContext dmc, int maxDepth, DataRequestMonitor<Integer> rm);
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java
new file mode 100644
index 00000000000..ae2f507839f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * Stack service extension.
+ * <p>
+ * Adds the capability to retrieve a limited number of stack frames.
+ * </p>
+ *
+ * @since DSF 1.1
+ */
+public interface IStack2 extends IStack {
+
+ /**
+ * Convenience constant for use with {@link #getFrames(IDMContext, int, int, DataRequestMonitor)}
+ * to retrieve all stack frames.
+ */
+ public final static int ALL_FRAMES = -1;
+
+ /**
+ * Retrieves list of stack frames for the given execution context. Request
+ * will fail if the stack frame data is not available.
+ * <p>The range of stack frames can be limited by the <code>startIndex</code> and <code>endIndex</code> arguments.
+ * It is no error to specify an <code>endIndex</code> exceeding the number of available stack frames.
+ * A negative value for <code>endIndex</code> means to retrieve all stack frames. <code>startIndex</code> must be a non-negative value.
+ * </p>
+ *
+ * @param execContext the execution context to retrieve stack frames for
+ * @param startIndex the index of the first frame to retrieve
+ * @param endIndex the index of the last frame to retrieve (inclusive) or {@link #ALL_FRAMES}
+ * @param rm the request monitor
+ *
+ * @see #getFrames(IDMContext, DataRequestMonitor)
+ */
+ public abstract void getFrames(IDMContext execContext, int startIndex, int endIndex, DataRequestMonitor<IFrameDMContext[]> rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java
new file mode 100644
index 00000000000..16167692125
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * @since 1.1
+ */
+@ConfinedToDsfExecutor("getSession().getExecutor()")
+public interface IStepQueueManager {
+
+ /**
+ * Returns the session for which this step queue manager is used.
+ */
+ public DsfSession getSession();
+
+ /**
+ * Checks whether a step command can be queued up for given context.
+ */
+ public abstract void canEnqueueStep(IExecutionDMContext execCtx, StepType stepType, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Adds a step command to the execution queue for given context.
+ * @param execCtx Execution context that should perform the step.
+ * @param stepType Type of step to execute.
+ */
+ public abstract void enqueueStep(final IExecutionDMContext execCtx, final StepType stepType);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java
new file mode 100644
index 00000000000..bf92dd13caa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * Service for accessing debugger symbols. This service builds on the Modules
+ * service, but not all debuggers provide access for parsing symbols so this
+ * service is separated.
+ * @see IModules
+ */
+public interface ISymbols extends IDMService {
+ public interface ISymbolObjectDMContext extends IDMContext {}
+
+ /**
+ * Data about a debug symbol.
+ */
+ public interface ISymbolObjectDMData extends IDMData {
+ String getName();
+ String getTypeName();
+ String getFilepath();
+ }
+
+ /**
+ * Indicates that the list of symbol objects is changed. Parsing debug
+ * symbols can be a long running operation (order of 10's of seconds or
+ * minues), so it is useful for the service to provide access to the data
+ * even while it's still parsing. This event may be issued periodically
+ * by the service to indicate that a section of debug symbols has been
+ * parsed.
+ */
+ public interface ISymbolDataChangedDMEvent extends IDMEvent<IModules.ISymbolDMContext> {}
+
+ /**
+ * Retrieves the list of symbols.
+ * @param symCtx Symbols context to retrieve symbols for.
+ * @param rm Request completion monitor. The return value is an iterator (rather than
+ * array) since there could be a very large number of symbols returned.
+ */
+ public void getSymbols(IModules.ISymbolDMContext symCtx, DataRequestMonitor<Iterable<ISymbolObjectDMContext>> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java
new file mode 100644
index 00000000000..3054e2af136
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This service builds on top of standard run control service to provide
+ * step queuing functionality. Step queuing essentially allows user to press
+ * and hold the step key and achieve maximum stepping speed. If this service
+ * is used, other service implementations, such as stack and expressions, can
+ * use it to avoid requesting data from debugger back end if another step is
+ * about to be executed.
+ *
+ * @deprecated The functionality has been integrated in the UI layer.
+ */
+@Deprecated
+public class StepQueueManager extends AbstractDsfService implements IStepQueueManager
+{
+ /**
+ * Amount of time in milliseconds, that it takes the ISteppingTimedOutEvent
+ * event to be issued after a step is started.
+ * @see ISteppingTimedOutEvent
+ */
+ public final static int STEPPING_TIMEOUT = 500;
+
+ /**
+ * The depth of the step queue. In other words, the maximum number of steps
+ * that are queued before the step queue manager throwing them away.
+ */
+ public final static int STEP_QUEUE_DEPTH = 3;
+
+ /**
+ * Indicates that the given context has been stepping for some time,
+ * and the UI (views and actions) may need to be updated accordingly.
+ */
+ public interface ISteppingTimedOutEvent extends IDMEvent<IExecutionDMContext> {}
+
+
+ private static class StepRequest {
+ StepType fStepType;
+ StepRequest(StepType type) {
+ fStepType = type;
+ }
+ }
+
+ private IRunControl fRunControl;
+ private int fQueueDepth = STEP_QUEUE_DEPTH;
+ private Map<IExecutionDMContext,List<StepRequest>> fStepQueues = new HashMap<IExecutionDMContext,List<StepRequest>>();
+ private Map<IExecutionDMContext,Boolean> fTimedOutFlags = new HashMap<IExecutionDMContext,Boolean>();
+ private Map<IExecutionDMContext,ScheduledFuture<?>> fTimedOutFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
+
+ public StepQueueManager(DsfSession session) {
+ super(session);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IDsfService
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ private void doInitialize(final RequestMonitor requestMonitor) {
+ fRunControl = getServicesTracker().getService(IRunControl.class);
+
+ getSession().addServiceEventListener(this, null);
+ register(new String[]{ StepQueueManager.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor requestMonitor) {
+ unregister();
+ getSession().removeServiceEventListener(this);
+ super.shutdown(requestMonitor);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfPlugin.getBundleContext();
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.service.IStepQueueManager#canEnqueueStep(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.dsf.debug.service.IRunControl.StepType, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ public void canEnqueueStep(IExecutionDMContext execCtx, StepType stepType, DataRequestMonitor<Boolean> rm) {
+ if (doCanEnqueueStep(execCtx, stepType)) {
+ rm.setData(true);
+ rm.done();
+ } else {
+ fRunControl.canStep(execCtx, stepType, rm);
+ }
+ }
+
+ private boolean doCanEnqueueStep(IExecutionDMContext execCtx, StepType stepType) {
+ return fRunControl.isStepping(execCtx) && !isSteppingTimedOut(execCtx);
+ }
+
+ /**
+ * Returns the number of step commands that are queued for given execution
+ * context.
+ */
+ public int getPendingStepCount(IExecutionDMContext execCtx) {
+ List<StepRequest> stepQueue = fStepQueues.get(execCtx);
+ if (stepQueue == null) return 0;
+ return stepQueue.size();
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.service.IStepQueueManager#enqueueStep(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.dsf.debug.service.IRunControl.StepType)
+ */
+ public void enqueueStep(final IExecutionDMContext execCtx, final StepType stepType) {
+ fRunControl.canStep(
+ execCtx, stepType, new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess() && getData()) {
+ fRunControl.step(execCtx, stepType, new RequestMonitor(getExecutor(), null));
+ } else if (doCanEnqueueStep(execCtx, stepType)) {
+ List<StepRequest> stepQueue = fStepQueues.get(execCtx);
+ if (stepQueue == null) {
+ stepQueue = new LinkedList<StepRequest>();
+ fStepQueues.put(execCtx, stepQueue);
+ }
+ if (stepQueue.size() < fQueueDepth) {
+ stepQueue.add(new StepRequest(stepType));
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Returns whether the step instruction for the given context has timed out.
+ */
+ public boolean isSteppingTimedOut(IExecutionDMContext execCtx) {
+ for (IExecutionDMContext timedOutCtx : fTimedOutFlags.keySet()) {
+ if (execCtx.equals(timedOutCtx) || DMContexts.isAncestorOf(execCtx, timedOutCtx)) {
+ return fTimedOutFlags.get(timedOutCtx);
+ }
+ }
+ return false;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final ISuspendedDMEvent e) {
+ // Take care of the stepping time out
+ fTimedOutFlags.remove(e.getDMContext());
+ ScheduledFuture<?> future = fTimedOutFutures.remove(e.getDMContext());
+ if (future != null) future.cancel(false);
+
+ // Check if there's a step pending, if so execute it
+ if (fStepQueues.containsKey(e.getDMContext())) {
+ List<StepRequest> queue = fStepQueues.get(e.getDMContext());
+ final StepRequest request = queue.remove(queue.size() - 1);
+ if (queue.isEmpty()) fStepQueues.remove(e.getDMContext());
+ fRunControl.canStep(
+ e.getDMContext(), request.fStepType,
+ new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess() && getData()) {
+ fRunControl.step(
+ e.getDMContext(), request.fStepType, new RequestMonitor(getExecutor(), null));
+ } else {
+ // For whatever reason we can't step anymore, so clear out
+ // the step queue.
+ fStepQueues.remove(e.getDMContext());
+ }
+ }
+ });
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final IResumedDMEvent e) {
+ if (e.getReason().equals(StateChangeReason.STEP)) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.FALSE);
+ // We shouldn't have a stepping timeout running unless we get two
+ // stepping events in a row without a suspended, which would be a
+ // protocol error.
+ assert !fTimedOutFutures.containsKey(e.getDMContext());
+ fTimedOutFutures.put(
+ e.getDMContext(),
+ getExecutor().schedule(
+ new DsfRunnable() { public void run() {
+ fTimedOutFutures.remove(e.getDMContext());
+
+ if (getSession().isActive()) {
+ // Issue the stepping time-out event.
+ getSession().dispatchEvent(
+ new ISteppingTimedOutEvent() {
+ public IExecutionDMContext getDMContext() { return e.getDMContext(); }
+ },
+ getProperties());
+ }
+ }},
+ STEPPING_TIMEOUT, TimeUnit.MILLISECONDS)
+ );
+
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ISteppingTimedOutEvent e) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.TRUE);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java
new file mode 100644
index 00000000000..0c0f1360da2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java
@@ -0,0 +1,549 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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
+ * Ericsson - Modified for caching commands corresponding to multiple execution contexts
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * This is a utility class for caching results of MI Commands. Return MIInfo
+ * data is retrieved from the cache if command was previously executed, and
+ * it is executed with MICommand service if it was not previously seen.
+ *
+ * Resetting the cache has to be performed by the object owning the cache when
+ * when an event indicates that the data is obsolete (which is specific to the
+ * types of commands being cached).
+ */
+
+public class CommandCache implements ICommandListener
+{
+ static enum CommandStyle { COALESCED, NONCOALESCED }
+
+ /**
+ * Holds cache information for a given command.
+ * @param <V> Type matches the result type associated with the command.
+ */
+ class CommandInfo {
+
+ /*
+ * Control variables.
+ */
+
+ /** List of the request monitors associated with this command */
+ private final List<DataRequestMonitor<ICommandResult>> fCurrentRequestMonitors ;
+
+ /** Original command. Need for reference from Queue completion notification */
+ private final ICommand<ICommandResult> fCommand;
+
+ /** Style of this command ( internal coalesced or not) */
+ private final CommandStyle fCmdStyle;
+
+ /** Command being processed for this command */
+ private CommandInfo fCoalescedCmd;
+
+ private ICommandToken fToken;
+
+ public CommandInfo(CommandStyle cmdstyle, ICommand<ICommandResult> cmd, DataRequestMonitor<ICommandResult> rm ) {
+ fCmdStyle = cmdstyle;
+ fCommand = cmd;
+ fCurrentRequestMonitors = new LinkedList<DataRequestMonitor<ICommandResult>>();
+ fCurrentRequestMonitors.add(rm);
+ fCoalescedCmd = null;
+ }
+
+ public CommandStyle getCommandstyle() { return fCmdStyle; }
+ public List<DataRequestMonitor<ICommandResult>> getRequestMonitorList() { return fCurrentRequestMonitors; }
+ public ICommand<ICommandResult> getCommand() { return fCommand; }
+ public CommandInfo getCoalescedCmd() { return fCoalescedCmd; }
+ public void setCoalescedCmd( CommandInfo cmd ) { fCoalescedCmd = cmd; }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CommandInfo)) return false;
+ CommandInfo otherCmd = (CommandInfo)other;
+
+ return otherCmd.fCommand.equals(fCommand);
+ }
+
+ @Override
+ public int hashCode() {
+ return fCommand.hashCode();
+ }
+ }
+
+ class CommandResultInfo {
+ private final ICommandResult fData;
+ private final IStatus fStatus;
+
+ public CommandResultInfo(ICommandResult data, IStatus status) {
+ fData = data;
+ fStatus = status;
+ }
+
+ public ICommandResult getData() { return fData; }
+ public IStatus getStatus() { return fStatus; }
+ }
+
+ private DsfSession fSession;
+
+ private ICommandControl fCommandControl;
+
+ /*
+ * This class contains 5 significant lists.
+ *
+ * Cached Results :
+ *
+ * Contains a mapping of commands and their completed results. Until the cached
+ * results are cleared by the owner of the cache.
+ *
+ * Pending Commands Not Queued :
+ *
+ * The Control object has not yet indicated that it has recognized the command
+ * yet. The user is not allowed to interrogate these objects until the Control
+ * object indicates they have been queued ( commandQueued notification ).
+ *
+ * Pending Commands Unsent :
+ *
+ * This is the list of commands which have been issued to the Control object but
+ * have not been actually issued to the backend. These commands represent coalesce
+ * options. They may be compared against the Queued list being maintained by the
+ * Control object until told otherwise - commandSent notification ).
+ *
+ * Pending Commands Sent :
+ *
+ * This is a list of commands which have been issued to the Control object and
+ * have also been sent to the backend. It is not possible use these objects for
+ * coalescents.
+ *
+ * Coalesced Pending Q :
+ *
+ * These represent original commands for which a new coalesced command has been
+ * created. When the coalesced commands completes the results will be decomposed
+ * when back into individual results from this command.
+ */
+ private Set<IDMContext> fAvailableContexts = new HashSet<IDMContext>();
+
+ private Map<IDMContext, HashMap<CommandInfo, CommandResultInfo>> fCachedContexts = new HashMap<IDMContext, HashMap<CommandInfo, CommandResultInfo>>();
+
+ private ArrayList<CommandInfo> fPendingQCommandsSent = new ArrayList<CommandInfo>();
+
+ private ArrayList<CommandInfo> fPendingQCommandsNotYetSent = new ArrayList<CommandInfo>();
+
+ private ArrayList<CommandInfo> fPendingQWaitingForCoalescedCompletion = new ArrayList<CommandInfo>();
+
+ public CommandCache(DsfSession session, ICommandControl control) {
+ fSession = session;
+ fCommandControl = control;
+
+ /*
+ * We listen for the notifications that the commands have been sent to the
+ * backend from the GDB/MI Communications engine.
+ */
+ fCommandControl.addCommandListener(this);
+ }
+
+ /*
+ * Constructs a coalesced command if possible.
+ */
+ private CommandInfo getCoalescedCommand(CommandInfo cmd) {
+
+ for ( CommandInfo currentUnsentEntry : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
+ /*
+ * Get the current unsent entry to determine if we can coalesced with it.
+ */
+ ICommand<?> unsentCommand = currentUnsentEntry.getCommand();
+
+ /*
+ * Check if we can so construct a new COALESCED command from scratch.
+ */
+
+ // For sanity's sake, cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ ICommand<ICommandResult> coalescedCmd =
+ (ICommand<ICommandResult>)unsentCommand.coalesceWith( cmd.getCommand() );
+
+ if ( coalescedCmd != null ) {
+ CommandInfo coalescedCmdInfo = new CommandInfo( CommandStyle.COALESCED, coalescedCmd, null) ;
+
+ if ( currentUnsentEntry.getCommandstyle() == CommandStyle.COALESCED ) {
+ /*
+ * We matched a command which is itself already a COALESCED command. So
+ * we need to run through the reference list and point all the current
+ * command which are referencing the command we just subsumed and change
+ * them to point to the new super command.
+ */
+
+ for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
+
+ if ( waitingEntry.getCoalescedCmd() == currentUnsentEntry ) {
+ /*
+ * This referenced the old command change it to point to the new one.
+ */
+ waitingEntry.setCoalescedCmd(coalescedCmdInfo);
+ }
+ }
+ } else {
+ /*
+ * This currently unsent entry needs to go into the coalescing list. To
+ * be completed when the coalesced command comes back with a result.
+ */
+ fPendingQWaitingForCoalescedCompletion.add(currentUnsentEntry);
+ currentUnsentEntry.setCoalescedCmd(coalescedCmdInfo);
+ }
+
+ /*
+ * Either way we want to take the command back from the Control object so it
+ * does not continue to process it.
+ */
+ fPendingQCommandsNotYetSent.remove(currentUnsentEntry);
+ fCommandControl.removeCommand(currentUnsentEntry.fToken);
+
+ return( coalescedCmdInfo );
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Executes given ICommand, or retrieves the cached result if known.
+ * @param command Command to execute.
+ * @param rm Return token, contains the retrieved MIInfo object as
+ * well as its cache status.
+ */
+ public <V extends ICommandResult> void execute(ICommand<V> command, DataRequestMonitor<V> rm) {
+ assert fSession.getExecutor().isInExecutorThread();
+
+ // Cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ final ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)command;
+ @SuppressWarnings("unchecked")
+ final DataRequestMonitor<ICommandResult> genericDone = (DataRequestMonitor<ICommandResult>) rm;
+
+ CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, genericDone) ;
+
+ final IDMContext context = genericCommand.getContext();
+
+ /*
+ * If command is already cached, just return the cached data.
+ */
+ if(fCachedContexts.get(context) != null && fCachedContexts.get(context).containsKey(cachedCmd)){
+ CommandResultInfo result = fCachedContexts.get(context).get(cachedCmd);
+ if (result.getStatus().getSeverity() <= IStatus.INFO) {
+ @SuppressWarnings("unchecked")
+ V v = (V)result.getData();
+ rm.setData(v);
+ } else {
+ rm.setStatus(result.getStatus());
+ }
+ rm.done();
+ return;
+ }
+
+ /*
+ * Return an error if the target is available anymore.
+ */
+ if (!isTargetAvailable(command.getContext())) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Target not available.", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * If we are already waiting for this command to complete,
+ * add this request monitor to list of waiting monitors.
+ */
+ for ( CommandInfo sentCommand : fPendingQCommandsSent ) {
+ if ( sentCommand.equals( cachedCmd )) {
+ sentCommand.getRequestMonitorList().add(genericDone);
+ return;
+ }
+ }
+ for ( CommandInfo notYetSentCommand : fPendingQCommandsNotYetSent ) {
+ if ( notYetSentCommand.equals( cachedCmd )) {
+ notYetSentCommand.getRequestMonitorList().add(genericDone);
+ return;
+ }
+ }
+
+
+ /*
+ * We see if this command can be combined into a coalesced one. The
+ * coalesce routine will take care of the already enqueued one which
+ * this command is being coalesced with.
+ */
+
+ CommandInfo coalescedCmd = getCoalescedCommand(cachedCmd);
+
+ if ( coalescedCmd != null ) {
+ /*
+ * The original command we were handed needs to go into the waiting QUEUE.
+ * We also need to point it it to the coalesced command.
+ */
+ fPendingQWaitingForCoalescedCompletion.add(cachedCmd);
+ cachedCmd.setCoalescedCmd(coalescedCmd);
+ cachedCmd = coalescedCmd;
+ }
+
+ /*
+ * Now we have a command to send ( coalesced or not ). Put it in the cannot touch
+ * it list and give it to the Control object. Our state handlers will move it into
+ * the proper list as the Control object deals with it.
+ */
+ final CommandInfo finalCachedCmd = cachedCmd;
+ fPendingQCommandsNotYetSent.add(finalCachedCmd);
+
+ finalCachedCmd.fToken = fCommandControl.queueCommand(
+ finalCachedCmd.getCommand(),
+ new DataRequestMonitor<ICommandResult>(fSession.getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+
+ /*
+ * Match this up with a command set we know about.
+ */
+ if ( ! fPendingQCommandsSent.remove(finalCachedCmd) ) {
+ /*
+ * It should not be the case that this is possible. It would mean we
+ * have mismanaged the queues or completions are lost at the lower
+ * levels. When the removal and cancellation is completed this code
+ * will probably not be here. But for now just return.
+ */
+ return ;
+ }
+
+ ICommandResult result = getData();
+ IStatus status = getStatus();
+
+ if ( finalCachedCmd.getCommandstyle() == CommandStyle.COALESCED ) {
+ /*
+ * We matched a command which is itself already a COALESCED command. So
+ * we need to go through the list of unsent commands which were not sent
+ * because the coalesced command represented it. For each match we find
+ * we create a new result from the coalesced command for it.
+ */
+
+ for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
+
+ if ( waitingEntry.getCoalescedCmd() == finalCachedCmd ) {
+
+ /*
+ * Remove this entry from the list since we can complete it.
+ */
+ fPendingQWaitingForCoalescedCompletion.remove(waitingEntry);
+
+ // Cast the calculated result back to the requested type.
+ @SuppressWarnings("unchecked")
+ V subResult = (V)result.getSubsetResult(waitingEntry.getCommand());
+ CommandResultInfo subResultInfo = new CommandResultInfo(subResult, status);
+
+ if(fCachedContexts.get(context) != null){
+ fCachedContexts.get(context).put(waitingEntry, subResultInfo);
+ } else {
+ HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
+ map.put(waitingEntry, subResultInfo);
+ fCachedContexts.put(context, map);
+ }
+
+ if (!isSuccess()) {
+
+ /*
+ * We had some form of error with the original command. So notify the
+ * original requesters of the issues.
+ */
+ for (DataRequestMonitor<?> pendingRM : waitingEntry.getRequestMonitorList()) {
+ pendingRM.setStatus(status);
+ pendingRM.done();
+ }
+ } else {
+ assert subResult != null;
+
+ /*
+ * Notify the original requesters of the positive results.
+ */
+ for (DataRequestMonitor<? extends ICommandResult> pendingRM : waitingEntry.getRequestMonitorList()) {
+ // Cast the pending return token to match the requested type.
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
+
+ vPendingRM.setData(subResult);
+ vPendingRM.done();
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * This is an original request which completed. Indicate success or
+ * failure to the original requesters.
+ */
+ CommandResultInfo resultInfo = new CommandResultInfo(result, status);
+
+ if (fCachedContexts.get(context) != null){
+ fCachedContexts.get(context).put(finalCachedCmd, resultInfo);
+ } else {
+ HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
+ map.put(finalCachedCmd, resultInfo);
+ fCachedContexts.put(context, map);
+ }
+
+ if (!isSuccess()) {
+ /*
+ * We had some form of error with the original command. So notify the
+ * original requesters of the issues.
+ */
+ for (DataRequestMonitor<?> pendingRM : finalCachedCmd.getRequestMonitorList()) {
+ pendingRM.setStatus(status);
+ pendingRM.done();
+ }
+ } else {
+ // Cast the calculated result back to the requested type.
+ @SuppressWarnings("unchecked")
+ V vResult = (V)result;
+
+ for (DataRequestMonitor<? extends ICommandResult> pendingRM : finalCachedCmd.getRequestMonitorList()) {
+ // Cast the pending return token to match the requested type.
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
+
+ vPendingRM.setData(vResult);
+ vPendingRM.done();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * TODO
+ */
+ public void setContextAvailable(IDMContext context, boolean isAvailable) {
+ if (isAvailable) {
+ fAvailableContexts.add(context);
+ } else {
+ fAvailableContexts.remove(context);
+ for (Iterator<IDMContext> itr = fAvailableContexts.iterator(); itr.hasNext();) {
+ if (DMContexts.isAncestorOf(context, itr.next())) {
+ itr.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * TODO
+ * @see #setContextAvailable(IDMContext, boolean)
+ */
+ public boolean isTargetAvailable(IDMContext context) {
+ for (IDMContext availableContext : fAvailableContexts) {
+ if (context.equals(availableContext) || DMContexts.isAncestorOf(context, availableContext)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Clears the cache data.
+ */
+ public void reset() {
+ fCachedContexts.clear();
+ }
+
+ public void commandRemoved(ICommandToken token) {
+ /*
+ * Do nothing.
+ */
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandQueued(org.eclipse.cdt.dsf.mi.core.command.ICommand)
+ */
+ public void commandQueued(ICommandToken token) {
+ /*
+ * Do nothing.
+ */
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandDone(org.eclipse.cdt.dsf.mi.core.command.ICommand, org.eclipse.cdt.dsf.mi.core.command.ICommandResult)
+ */
+ public void commandDone(ICommandToken token, ICommandResult result) {
+ /*
+ * We handle the done with a runnable where we initiated the command
+ * so there is nothing to do here.
+ */
+ }
+
+ /*
+ * Move the command into our internal sent list. This means we can no longer look at
+ * this command for possible coalescence since it has been given to the debug engine
+ * and is currently being processed.
+ *
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandSent(org.eclipse.cdt.dsf.mi.core.command.ICommand)
+ */
+ public void commandSent(ICommandToken token) {
+
+ // Cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)token.getCommand();
+
+ CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, null) ;
+
+ for ( CommandInfo unqueuedCommand : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
+ if ( unqueuedCommand.equals( cachedCmd )) {
+ fPendingQCommandsNotYetSent.remove(unqueuedCommand);
+ fPendingQCommandsSent.add(unqueuedCommand);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Clears the cache entries for given context. Clears the whole cache if
+ * context parameter is null.
+ */
+ public void reset(IDMContext dmc) {
+ if (dmc == null) {
+ fCachedContexts.clear();
+ return;
+ }
+ for (Iterator<IDMContext> itr = fCachedContexts.keySet().iterator(); itr.hasNext();) {
+ IDMContext keyDmc = itr.next();
+ if (keyDmc != null && (dmc.equals(keyDmc) || DMContexts.isAncestorOf(keyDmc, dmc))) {
+ itr.remove();
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java
new file mode 100644
index 00000000000..6c63ae8fb35
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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
+ * Ericsson - Modified for additional features in DSF Reference implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+
+/**
+ * Command interface for creating and manipulating GDB/MI commands
+ * for the DSF GDB reference implemenation. The command represents
+ * the GDB/MI request which will be put on the wire to the GDB
+ * backend.
+ */
+
+public interface ICommand<V extends ICommandResult> {
+ /**
+ * Takes the supplied command and coalesces it with this one.
+ * The result is a new third command which represent the two
+ * original commands.
+ * <br>Note: the result type associated with the resurned command may be
+ * different than the result type associated with either of the commands
+ * being coalesced.
+ *
+ * @return newly created command, or null if command cannot be coalesced
+ */
+ public ICommand<? extends ICommandResult> coalesceWith( ICommand<? extends ICommandResult> command );
+
+ /**
+ * Returns the context that this command is to be evaluated in. May be null
+ * if the command does not need to be evaluated in a specific context.
+ */
+ public IDMContext getContext();
+}
+
+
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java
new file mode 100644
index 00000000000..dd174d3bd4a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+
+/**
+ * API for sending commands to the debugger and for receiving command results
+ * and asynchronous events. The command control may be implemented by a service
+ * or a non-service object.
+ *
+ * @see ICommandControlService
+ */
+public interface ICommandControl {
+
+ /**
+ * Adds the specified command to the queue of commands to be processed.
+ *
+ * @param command Specific command to be processed
+ * @param rm Request completion monitor
+ * @return None
+ */
+ <V extends ICommandResult> ICommandToken queueCommand(ICommand<V> command, DataRequestMonitor<V> rm);
+
+ /**
+ * Removes the specified command from the processor queue.
+ *
+ * @param command Specific command to be removed
+ * @return None
+ */
+ void removeCommand(ICommandToken token);
+
+ /**
+ * Adds a notification handler for the Command processor.
+ *
+ * @param command listener to be added
+ * @return None
+ */
+ void addCommandListener(ICommandListener listener);
+
+ /**
+ * Removes a notification handler for the Command processor.
+ *
+ * @param command listener to be removed
+ * @return None
+ */
+ void removeCommandListener(ICommandListener listener);
+
+ /**
+ * Adds a notification handler for the Event processor.
+ *
+ * @param event listener to be added
+ * @return None
+ */
+ void addEventListener(IEventListener listener);
+
+ /**
+ * Removes a notification handler for the Event processor.
+ *
+ * @param event listener to be removed
+ * @return None
+ */
+ void removeEventListener(IEventListener listener);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java
new file mode 100644
index 00000000000..0672d5ec986
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Service which acts as a command control.
+ *
+ * @since 1.1
+ */
+public interface ICommandControlService extends ICommandControl, IDsfService {
+
+ /**
+ * Context representing a command control service. All contexts which
+ * originate from a given command control service, should have that
+ * control's context in their hierarchy.
+ *
+ * @see ICommandControlService#getContext()
+ */
+ public interface ICommandControlDMContext extends IDMContext {
+ /**
+ * Returns the ID of the command control that this context
+ * represents.
+ */
+ public String getCommandControlId();
+ }
+
+ /**
+ * Event indicating that the back end process has started.
+ */
+ public interface ICommandControlInitializedDMEvent extends IDMEvent<ICommandControlDMContext> {};
+
+ /**
+ * Event indicating that the back end process has terminated.
+ */
+ public interface ICommandControlShutdownDMEvent extends IDMEvent<ICommandControlDMContext> {};
+
+ /**
+ * Returns the identifier of this command control service. It can be used
+ * to distinguish between multiple instances of command control services.
+ */
+ public String getId();
+
+ /**
+ * returns the context representing this command control.
+ */
+ public ICommandControlDMContext getContext();
+
+ /**
+ * Returns whether this command control is currently active. A command
+ * control service is active if it has been initialized and has not yet
+ * shut down.
+ * @return
+ */
+ public boolean isActive();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java
new file mode 100644
index 00000000000..f7a0f80ae79
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+
+/**
+ * Synchronous listener to commands being sent and received.
+ * All the registered listeners will be called in the same
+ * dispatch cycle as when the result of the command is submitted.
+ */
+
+@ConfinedToDsfExecutor("")
+public interface ICommandListener {
+ /**
+ * Notifies that the specified command has been added to the Command Queue.
+ * It has not yet been sent. In this state the command can be examined and
+ * possibly withdrawn because it has been coalesced with another command.
+ *
+ * @return None
+ * @param command Command which has been added to the Queue
+ */
+ public void commandQueued(ICommandToken token);
+
+ /**
+ * Notification that the given command was sent to the debugger. At this
+ * point the command is no longer in the Command Queue and should not be
+ * examined. The only thing which can be done is to try and cancel the
+ * command.
+ *
+ * @return None
+ * @param command
+ */
+ public void commandSent(ICommandToken token);
+
+ /**
+ * Notifies that the specified command has been removed from the
+ * Command Queue. This notification means that the command has
+ * been removed from the queue and not sent to the backend. The
+ * user has specifically removed it, perhaps because it has been
+ * combined with another. Or some state change has occured and
+ * there is no longer a need to get this particular set of data.
+ *
+ * @return None
+ * @param Command which has been sent to the backend
+ */
+ public void commandRemoved(ICommandToken token);
+
+ /**
+ * Notifies that the specified command has been completed.
+ *
+ * @return None
+ * @param Command which has been sent to the backend
+ */
+ public void commandDone(ICommandToken token, ICommandResult result);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java
new file mode 100644
index 00000000000..09e53154c43
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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.cdt.dsf.debug.service.command;
+
+public interface ICommandResult {
+ /**
+ * Returns an ICommandResult which is a subset command result. The command
+ * result which is being passed in is from a coalesced command. The result
+ * which is desired is contained within those results. In this instance we
+ * are processing the command result from the coalesced command to get our
+ * command result.
+ * <i>Note:</i> The type of returned command result must match the type
+ * associated with the subset command that is passed in the argument.
+ *
+ * @return result for this particular command.
+ */
+ public <V extends ICommandResult> V getSubsetResult( ICommand<V> command );
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java
new file mode 100644
index 00000000000..ccd80d234d2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.debug.service.command;
+
+/**
+ * Token returned by ICommandControl.queueCommand(). This token can be used
+ * to uniquely identify a command when calling ICommandControl.removeCommand()
+ * or when implementing the ICommandListener listener methods.
+ */
+public interface ICommandToken {
+ /**
+ * Returns the command that this was created for.
+ */
+ public ICommand<? extends ICommandResult> getCommand();
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java
new file mode 100644
index 00000000000..49fa20f3eee
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java
@@ -0,0 +1,19 @@
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+
+/**
+ * Synchronous listener for events issued from the debugger. All
+ * registered listeners will be called in the same dispatch cycle.
+ */
+
+@ConfinedToDsfExecutor("")
+public interface IEventListener {
+ /**
+ * Notifies that the given asynchronous output was received from the
+ * debugger.
+ * @param output output that was received from the debugger. Format
+ * of the output data is debugger specific.
+ */
+ public void eventReceived(Object output);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java
new file mode 100644
index 00000000000..2e881b18c6c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems - Initial API and implementation
+ * Nokia - Added support for AbsoluteSourceContainer( 159833 )
+ * Wind River Systems - Adapted for use with DSF
+*******************************************************************************/
+package org.eclipse.cdt.dsf.debug.sourcelookup;
+
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * DSF source lookup director.
+ */
+public class DsfSourceLookupDirector extends CSourceLookupDirector {
+
+ private final DsfSession fSession;
+
+ public DsfSourceLookupDirector(DsfSession session) {
+ fSession = session;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupDirector#initializeParticipants()
+ */
+ @Override
+ public void initializeParticipants() {
+ super.initializeParticipants();
+ addParticipants( new ISourceLookupParticipant[]{ new DsfSourceLookupParticipant(fSession) } );
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java
new file mode 100644
index 00000000000..11a105e6f2e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.debug.sourcelookup;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * Source lookup participant that should be used with DSF-based debuggers.
+ */
+@ThreadSafe
+public class DsfSourceLookupParticipant implements ISourceLookupParticipant {
+ protected static final Object[] EMPTY = new Object[0];
+
+ private DsfExecutor fExecutor;
+ private String fSessionId;
+ private DsfServicesTracker fServicesTracker;
+ private ISourceLookupDirector fDirector;
+ private Map<String, List<Object>> fLookupCache = Collections.synchronizedMap(new HashMap<String, List<Object>>());
+
+ public DsfSourceLookupParticipant(DsfSession session) {
+ fSessionId = session.getId();
+ fExecutor = session.getExecutor();
+ fServicesTracker = new DsfServicesTracker(DsfPlugin.getBundleContext(), fSessionId);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#init(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector)
+ */
+ public void init(ISourceLookupDirector director) {
+ fDirector = director;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#dispose()
+ */
+ public void dispose() {
+ fServicesTracker.dispose();
+ fDirector = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#findSourceElements(java.lang.Object)
+ */
+ public Object[] findSourceElements(Object object) throws CoreException {
+ CoreException single = null;
+ MultiStatus multiStatus = null;
+ List<Object> results = null;
+
+ String name = getSourceName(object);
+ if (name != null) {
+ results = fLookupCache.get(name);
+ if (results != null) {
+ return results.toArray();
+ } else {
+ results = new ArrayList<Object>();
+ }
+ ISourceContainer[] containers = getSourceContainers();
+ for (int i = 0; i < containers.length; i++) {
+ try {
+ ISourceContainer container = containers[i];
+ if (container != null) {
+ Object[] objects = container.findSourceElements(name);
+ if (objects.length > 0) {
+ if (isFindDuplicates()) {
+ results.addAll(Arrays.asList(objects));
+ } else {
+ results.add(objects[0]);
+ break;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ if (single == null) {
+ single = e;
+ } else if (multiStatus == null) {
+ multiStatus = new MultiStatus(DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, new IStatus[]{single.getStatus()}, "Source Lookup error", null); //$NON-NLS-1$
+ multiStatus.add(e.getStatus());
+ } else {
+ multiStatus.add(e.getStatus());
+ }
+ }
+ }
+
+ if (!results.isEmpty()) {
+ synchronized(fLookupCache) {
+ if (!fLookupCache.containsKey(name)) {
+ fLookupCache.put(name, results);
+ }
+ }
+ }
+ }
+ if (results == null || results.isEmpty()) {
+ if (multiStatus != null) {
+ throw new CoreException(multiStatus);
+ } else if (single != null) {
+ throw single;
+ }
+ return EMPTY;
+ }
+ return results.toArray();
+ }
+
+ /**
+ * Returns whether this participant's source lookup director is configured
+ * to search for duplicate source elements.
+ *
+ * @return whether this participant's source lookup director is configured
+ * to search for duplicate source elements
+ */
+ protected boolean isFindDuplicates() {
+ ISourceLookupDirector director = fDirector;
+ if (director != null) {
+ return director.isFindDuplicates();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the source containers currently registered with this participant's
+ * source lookup director.
+ *
+ * @return the source containers currently registered with this participant's
+ * source lookup director
+ */
+ protected ISourceContainer[] getSourceContainers() {
+ ISourceLookupDirector director = fDirector;
+ if (director != null) {
+ return director.getSourceContainers();
+ }
+ return new ISourceContainer[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#sourceContainersChanged(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector)
+ */
+ public void sourceContainersChanged(ISourceLookupDirector director) {
+ fLookupCache.clear();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupParticipant#getSourceName(java.lang.Object)
+ */
+ public String getSourceName(Object object) throws CoreException {
+ if ( !(object instanceof IDMContext) ||
+ !((IDMContext)object).getSessionId().equals(fSessionId) )
+ {
+ throw new CoreException(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invalid object", null)); //$NON-NLS-1$
+ }
+
+ final IDMContext dmc = (IDMContext)object;
+ Query<String> query = new Query<String>() {
+ @Override
+ protected void execute(final DataRequestMonitor<String> rm) {
+ getSourceNameOnDispatchThread(dmc, rm);
+ }};
+ fExecutor.execute(query);
+ try {
+ return query.get();
+ } catch (InterruptedException e) { assert false : "Interrupted exception in DSF executor"; //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof CoreException) {
+ throw (CoreException)e.getCause();
+ }
+ assert false : "Unexptected exception"; //$NON-NLS-1$
+ }
+ return null; // Should never get here.
+ }
+
+ @ConfinedToDsfExecutor("fExecutor")
+ private void getSourceNameOnDispatchThread(IDMContext dmc, final DataRequestMonitor<String> rm) {
+ if (!(dmc instanceof IStack.IFrameDMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "No source for this object", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ IFrameDMContext frameDmc = (IFrameDMContext)dmc;
+
+ IStack stackService = fServicesTracker.getService(IStack.class);
+ if (stackService == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Stack data not available", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ stackService.getFrameData(
+ frameDmc,
+ new DataRequestMonitor<IFrameDMData>(fExecutor, rm) { @Override
+ public void handleSuccess() {
+ rm.setData(getData().getFile());
+ rm.done();
+ }});
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java
new file mode 100644
index 00000000000..11ccf06857b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.internal;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfPlugin extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.dsf"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfPlugin fgPlugin;
+
+ // BundleContext of this plugin
+ private static BundleContext fgBundleContext;
+
+ // Debugging flag
+ public static boolean DEBUG = false;
+
+ /**
+ * The constructor
+ */
+ public DsfPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.cdt.dsf/debug")); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ fgBundleContext = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+ public static void debug(String message) {
+ if (DEBUG) {
+ System.out.println(message);
+ }
+ }
+
+ public static String getDebugTime() {
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ long time = System.currentTimeMillis();
+ long seconds = (time / 1000) % 1000;
+ if (seconds < 100) traceBuilder.append('0');
+ if (seconds < 10) traceBuilder.append('0');
+ traceBuilder.append(seconds);
+ traceBuilder.append(',');
+ long millis = time % 1000;
+ if (millis < 100) traceBuilder.append('0');
+ if (millis < 10) traceBuilder.append('0');
+ traceBuilder.append(millis);
+ return traceBuilder.toString();
+ }
+
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java
new file mode 100644
index 00000000000..8d085eb6c27
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.service;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Standard base implementation of the DSF service. This is a convenience
+ * class that provides the basic functionality that all DSF services have
+ * to implement.
+ */
+abstract public class AbstractDsfService
+ implements IDsfService, IDsfStatusConstants
+{
+ /** Reference to the session that this service belongs to. */
+ private DsfSession fSession;
+
+ /** Startup order number of this service. */
+ private int fStartupNumber;
+
+ /** Registration object for this service. */
+ private ServiceRegistration fRegistration;
+
+ /** Tracker for services that this service depends on. */
+ private DsfServicesTracker fTracker;
+
+ /** Properties that this service was registered with */
+ @SuppressWarnings("unchecked")
+ private Dictionary fProperties;
+
+ /** Properties that this service was registered with */
+ private String fFilter;
+
+ /**
+ * Only constructor, requires a reference to the session that this
+ * service belongs to.
+ * @param session
+ */
+ public AbstractDsfService(DsfSession session) {
+ fSession = session;
+ }
+
+ public DsfExecutor getExecutor() { return fSession.getExecutor(); }
+
+ @SuppressWarnings("unchecked")
+ public Dictionary getProperties() { return fProperties; }
+
+ public String getServiceFilter() { return fFilter; }
+
+ public int getStartupNumber() { return fStartupNumber; }
+
+ public void initialize(RequestMonitor rm) {
+ fTracker = new DsfServicesTracker(getBundleContext(), fSession.getId());
+ fStartupNumber = fSession.getAndIncrementServiceStartupCounter();
+ rm.done();
+ }
+
+ public void shutdown(RequestMonitor rm) {
+ fTracker.dispose();
+ fTracker = null;
+ rm.done();
+ }
+
+ /** Returns the session object for this service */
+ public DsfSession getSession() { return fSession; }
+
+ /**
+ * Sub-classes should return the bundle context of the plugin, which the
+ * service belongs to.
+ */
+ abstract protected BundleContext getBundleContext();
+
+ /** Returns the tracker for the services that this service depends on. */
+ protected DsfServicesTracker getServicesTracker() { return fTracker; }
+
+ /**
+ * Registers this service.
+ */
+ @SuppressWarnings("unchecked")
+ protected void register(String[] classes, Dictionary properties) {
+
+ /*
+ * If this service has already been registered, make sure we
+ * keep the names it has been registered with. However, we
+ * must trigger a new registration or else OSGI will keep the two
+ * registration separate.
+ */
+ if (fRegistration != null) {
+ String[] previousClasses = (String[])fRegistration.getReference().getProperty(Constants.OBJECTCLASS);
+
+ // Use a HashSet to avoid duplicates
+ Set<String> newClasses = new HashSet<String>();
+ newClasses.addAll(Arrays.asList(previousClasses));
+ newClasses.addAll(Arrays.asList(classes));
+ classes = newClasses.toArray(new String[0]);
+
+ /*
+ * Also keep all previous properties.
+ */
+ if (fProperties != null) {
+ for (Enumeration e = fProperties.keys() ; e.hasMoreElements();) {
+ Object key = e.nextElement();
+ Object value = fProperties.get(key);
+ properties.put(key, value);
+ }
+ }
+
+ // Now, cancel the previous registration
+ unregister();
+ }
+ /*
+ * Ensure that the list of classes contains the base DSF service
+ * interface, as well as the actual class type of this object.
+ */
+ if (!Arrays.asList(classes).contains(IDsfService.class.getName())) {
+ String[] newClasses = new String[classes.length + 1];
+ System.arraycopy(classes, 0, newClasses, 1, classes.length);
+ newClasses[0] = IDsfService.class.getName();
+ classes = newClasses;
+ }
+ if (!Arrays.asList(classes).contains(getClass().getName())) {
+ String[] newClasses = new String[classes.length + 1];
+ System.arraycopy(classes, 0, newClasses, 1, classes.length);
+ newClasses[0] = getClass().getName();
+ classes = newClasses;
+ }
+ /*
+ * Make sure that the session ID is set in the service properties.
+ * The session ID distinguishes this service instance from instances
+ * of the same service in other sessions.
+ */
+ properties.put(PROP_SESSION_ID, getSession().getId());
+ fProperties = properties;
+ fRegistration = getBundleContext().registerService(classes, this, properties);
+
+ /*
+ * Retrieve the OBJECTCLASS property directly from the service
+ * registration info. This is the best bet for getting an accurate
+ * value.
+ */
+ fRegistration.getReference().getProperty(Constants.OBJECTCLASS);
+ fProperties.put(Constants.OBJECTCLASS, fRegistration.getReference().getProperty(Constants.OBJECTCLASS));
+
+ /*
+ * Create the filter for this service based on all the properties. If
+ * there is a single service instance per session, or if the properties
+ * parameter uniquely identifies this service instance among other
+ * instances in this session. Then this filter will fetch this service
+ * and only this service from OSGi.
+ */
+ fFilter = generateFilter(fProperties);
+ }
+
+ /**
+ * Generates an LDAP filter to uniquely identify this service.
+ */
+ @SuppressWarnings("unchecked")
+ private String generateFilter(Dictionary properties) {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(&"); //$NON-NLS-1$
+
+ for (Enumeration keys = properties.keys(); keys.hasMoreElements();) {
+ Object key = keys.nextElement();
+ Object value = properties.get(key);
+ if (value instanceof Object[]) {
+ /*
+ * For arrays, add a test to check that every element in array
+ * is present. This is here mainly to handle OBJECTCLASS property.
+ */
+ for (Object arrayValue : (Object[])value) {
+ filter.append('(');
+ filter.append(key.toString());
+ filter.append("=*"); //$NON-NLS-1$
+ filter.append(arrayValue.toString());
+ filter.append(')');
+ }
+ } else {
+ filter.append('(');
+ filter.append(key.toString());
+ filter.append('=');
+ filter.append(value.toString());
+ filter.append(')');
+ }
+ }
+ filter.append(')');
+ return filter.toString();
+ }
+
+ /**
+ * De-registers this service.
+ *
+ */
+ protected void unregister() {
+ if (fRegistration != null) {
+ fRegistration.unregister();
+ }
+ fRegistration = null;
+ }
+
+ /** Returns the registration object that was obtained when this service was registered */
+ protected ServiceRegistration getServiceRegistration() { return fRegistration; }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java
new file mode 100644
index 00000000000..9f2e5525dcb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.dsf.service;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for service event handler methods. The name of the event
+ * handler method is irrelevant, only the annotation is checked.
+ * <p>
+ * Each service event handler method should have one or two parameters:
+ * <li>
+ * <br> First argument is required and it should be the event object, with
+ * type with the event class desired.
+ * <br> Second argument is optional, and it has to be of type Dictionary<String,String>.
+ * If this parameter is declared, the handler will be passed the properties
+ * dictionary of the service that submitted the event.
+ * </li>
+ * <p>
+ * It is expected that service event classes are hierarchical. So that if a
+ * handler is registered for a super-class of another event, this handler
+ * will be called every time one of the sub-class events is invoked.
+ * If a listener declares a handler for an event AND a superclass of that event,
+ * both handlers will be invoked when the event is dispatched.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface DsfServiceEventHandler {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java
new file mode 100644
index 00000000000..02b83b94b1d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.dsf.service;
+
+/**
+ * Utility class containing status methods to use with DSF services.
+ */
+public class DsfServices {
+
+ /**
+ * Creates a properly formatted OSGi service filter for a DSF service based
+ * on service class and session ID.
+ * @param serviceClass Class of the service to create the filter for.
+ * @param sessionId Session ID of the session that the service belongs to.
+ * @return Filter string to identify the given service.
+ */
+ public static String createServiceFilter(Class<?> serviceClass, String sessionId) {
+ String serviceId =
+ "(&" + //$NON-NLS-1$
+ "(OBJECTCLASS=" + //$NON-NLS-1$
+ serviceClass.getName() +
+ ")" + //$NON-NLS-1$
+ "(" + //$NON-NLS-1$
+ IDsfService.PROP_SESSION_ID +
+ "=" + //$NON-NLS-1$
+ sessionId +
+ ")" + //$NON-NLS-1$
+ ")" ; //$NON-NLS-1$
+
+ return serviceId;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java
new file mode 100644
index 00000000000..9a98805798c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.service;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Convenience class to help track DSF services that a given
+ * client needs to use. This class is similar to the standard OSGI
+ * org.osgi.util.tracker.ServiceTracker class, with a few differences:
+ * <br>1. This class is assumed to be accessed by a single thread hence it
+ * has no synchronization built in, while OSGI ServiceTracker synchronized
+ * access to its data.
+ * <br>2. This class is primarily designed to track multiple services of
+ * different type (class), while OSGI ServiceTracker is designed to work with
+ * single class type, with optional filtering options.
+ * <br>3. This class uses knowledge of DSF sessions to help narrow down
+ * service references.
+ * <br>4. OSGI Service tracker explicitly listens to OSGI service
+ * startup/shutdown events and it will clear a reference to a service as
+ * soon as it's shut down. This class leaves it up to the client to make
+ * sure that it doesn't access a service once that service has been shut down.
+ * <p>
+ * That said, it might be more convenient for certain types of clients to use
+ * OSGI Service tracker for the additional features it provides.
+ *
+ * @see org.osgi.util.tracker.ServiceTracker
+ */
+public class DsfServicesTracker {
+
+ private static String getServiceFilter(String sessionId) {
+ return ("(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")").intern(); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ private static class ServiceKey
+ {
+ String fClassName;
+ String fFilter;
+ public ServiceKey(Class<?> clazz, String filter) {
+ fClassName = clazz != null ? clazz.getName() : null;
+ fFilter = filter;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // I guess this doesn't have to assume fFilter can be null, but oh well.
+ return other instanceof ServiceKey &&
+ ((fClassName == null && ((ServiceKey)other).fClassName == null) ||
+ (fClassName != null && fClassName.equals(((ServiceKey)other).fClassName))) &&
+ ((fFilter == null && ((ServiceKey)other).fFilter == null) ||
+ (fFilter != null && fFilter.equals(((ServiceKey)other).fFilter)));
+ }
+
+ @Override
+ public int hashCode() {
+ return (fClassName == null ? 0 : fClassName.hashCode()) + (fFilter == null ? 0 : fFilter.hashCode());
+ }
+ }
+
+ private BundleContext fBundleContext;
+ private Map<ServiceKey,ServiceReference> fServiceReferences = new HashMap<ServiceKey,ServiceReference>();
+ private Map<ServiceReference,Object> fServices = new HashMap<ServiceReference,Object>();
+ private String fServiceFilter;
+
+ /**
+ * Only constructor.
+ * @param bundleContext Context of the plugin that the client lives in.
+ * @param sessionId The DSF session that this tracker will be used for.
+ */
+ public DsfServicesTracker(BundleContext bundleContext, String sessionId) {
+ fBundleContext = bundleContext;
+ fServiceFilter = getServiceFilter(sessionId);
+ }
+
+ /**
+ * Retrieves a service reference for given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return OSGI service reference object to the desired service, null if not found
+ */
+ @SuppressWarnings("unchecked")
+ public ServiceReference getServiceReference(Class serviceClass, String filter) {
+ ServiceKey key = new ServiceKey(serviceClass, filter != null ? filter : fServiceFilter);
+ if (fServiceReferences.containsKey(key)) {
+ return fServiceReferences.get(key);
+ }
+
+ try {
+ ServiceReference[] references = fBundleContext.getServiceReferences(key.fClassName, key.fFilter);
+ assert references == null || references.length <= 1;
+ if (references == null || references.length == 0) {
+ return null;
+ } else {
+ fServiceReferences.put(key, references[0]);
+ return references[0];
+ }
+ } catch(InvalidSyntaxException e) {
+ assert false : "Invalid session ID syntax"; //$NON-NLS-1$
+ } catch(IllegalStateException e) {
+ // Can occur when plugin is shutting down.
+ }
+ return null;
+ }
+
+ /**
+ * Convenience class to retrieve a service based on class name only.
+ * @param serviceClass class of the desired service
+ * @return instance of the desired service, null if not found
+ */
+ public <V> V getService(Class<V> serviceClass) {
+ return getService(serviceClass, null);
+ }
+
+ /**
+ * Retrieves the service given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return instance of the desired service, null if not found
+ */
+ @SuppressWarnings("unchecked")
+ public <V> V getService(Class<V> serviceClass, String filter) {
+ ServiceReference serviceRef = getServiceReference(serviceClass, filter);
+ if (serviceRef == null) {
+ return null;
+ } else {
+ if (fServices.containsKey(serviceRef)) {
+ return (V)fServices.get(serviceRef);
+ } else {
+ V service = (V)fBundleContext.getService(serviceRef);
+ fServices.put(serviceRef, service);
+ return service;
+ }
+ }
+ }
+
+ /**
+ * Un-gets all the serferences held by this tracker. Must be called
+ * to avoid leaking OSGI service references.
+ */
+ public void dispose() {
+ for (Iterator<ServiceReference> itr = fServices.keySet().iterator(); itr.hasNext();) {
+ fBundleContext.ungetService(itr.next());
+ itr.remove();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java
new file mode 100644
index 00000000000..349ae16447e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.Filter;
+
+/**
+ * Class to manage DSF sessions. A DSF session is a way to
+ * associate a set of DSF services that are running simultaneously and
+ * are interacting with each other to provide a complete set of functionality.
+ * <p>
+ * Properties of a session are following:
+ * <br>1. Each session is associated with a single DSF executor, although there
+ * could be multiple sessions using the same executor.
+ * <br>2. Each session has a unique String identifier, which has to be used by
+ * the services belonging to this session when registering with OSGI services.
+ * <br>3. Each session has its set of service event listeners.
+ * <br>4. Start and end of each session is announced by events, which are always
+ * sent on that session's executor dispatch thread.
+ *
+ * @see org.eclipse.cdt.dsf.concurrent.DsfExecutor
+ */
+@ConfinedToDsfExecutor("getExecutor")
+public class DsfSession
+{
+ /**
+ * Listener for session started events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ */
+ public static interface SessionStartedListener {
+ /**
+ * Called when a new session is started. It is always called in the
+ * dispatch thread of the new session.
+ */
+ public void sessionStarted(DsfSession session);
+ }
+
+ /**
+ * Listener for session ended events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ */
+ public static interface SessionEndedListener {
+ /**
+ * Called when a session is ended. It is always called in the
+ * dispatch thread of the session.
+ */
+ public void sessionEnded(DsfSession session);
+ }
+
+ private static int fgSessionIdCounter = 0;
+ private static Set<DsfSession> fgActiveSessions = Collections.synchronizedSet(new HashSet<DsfSession>());
+ private static List<SessionStartedListener> fSessionStartedListeners = Collections.synchronizedList(new ArrayList<SessionStartedListener>());
+ private static List<SessionEndedListener> fSessionEndedListeners = Collections.synchronizedList(new ArrayList<SessionEndedListener>());
+
+ /** Returns true if given session is currently active */
+ public static boolean isSessionActive(String sessionId) {
+ return getSession(sessionId) != null;
+ }
+
+ /** Returns a session instance for given session identifier */
+ @ThreadSafe
+ public static DsfSession getSession(String sessionId) {
+ synchronized(fgActiveSessions) {
+ for (DsfSession session : fgActiveSessions) {
+ if (session.getId().equals(sessionId)) {
+ return session;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void addSessionStartedListener(SessionStartedListener listener) {
+ assert !fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void removeSessionStartedListener(SessionStartedListener listener) {
+ assert fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.remove(listener);
+ }
+
+ /**
+ * Registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void addSessionEndedListener(SessionEndedListener listener) {
+ assert !fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void removeSessionEndedListener(SessionEndedListener listener) {
+ assert fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.remove(listener);
+ }
+
+ /**
+ * Starts and returns a new session instance. This method can be called on any
+ * thread, but the session-started listeners will be called using the session's
+ * executor.
+ * @param executor The DSF executor to use for this session.
+ * @param ownerId ID (plugin ID preferably) of the owner of this session
+ * @return instance object of the new session
+ */
+ @ThreadSafe
+ public static DsfSession startSession(DsfExecutor executor, String ownerId) {
+ synchronized(fgActiveSessions) {
+ final DsfSession newSession = new DsfSession(executor, ownerId, Integer.toString(fgSessionIdCounter++));
+ fgActiveSessions.add(newSession);
+ executor.submit( new DsfRunnable() { public void run() {
+ SessionStartedListener[] listeners = fSessionStartedListeners.toArray(
+ new SessionStartedListener[fSessionStartedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionStarted(newSession);
+ }
+ }});
+ return newSession;
+ }
+ }
+
+ /**
+ * Terminates the given session. This method can be also called on any
+ * thread, but the session-ended listeners will be called using the session's
+ * executor.
+ * @param session session to terminate
+ */
+ @ThreadSafe
+ public static void endSession(final DsfSession session) {
+ synchronized(fgActiveSessions) {
+ if (!fgActiveSessions.contains(session)) {
+ throw new IllegalArgumentException();
+ }
+ fgActiveSessions.remove(session);
+ session.getExecutor().submit( new DsfRunnable() { public void run() {
+ SessionEndedListener[] listeners = fSessionEndedListeners.toArray(
+ new SessionEndedListener[fSessionEndedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionEnded(session);
+ }
+ }});
+ }
+ }
+
+ private static class ListenerEntry {
+ Object fListener;
+ Filter fFilter;
+
+ ListenerEntry(Object listener, Filter filter) {
+ fListener = listener;
+ fFilter = filter;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof ListenerEntry && fListener.equals(((ListenerEntry)other).fListener);
+ }
+
+ @Override
+ public int hashCode() { return fListener.hashCode(); }
+ }
+
+ /** ID (plugin ID preferably) of the owner of this session */
+ private String fOwnerId;
+
+ /** Session ID of this session. */
+ private String fId;
+
+ /** Dispatch-thread executor for this session */
+ private DsfExecutor fExecutor;
+
+ /** Service start-up counter for this session */
+ private int fServiceInstanceCounter;
+
+ /** Map of registered event listeners. */
+ private Map<ListenerEntry,Method[]> fListeners = new HashMap<ListenerEntry,Method[]>();
+
+ /**
+ * Map of registered adapters, for implementing the
+ * IModelContext.getAdapter() method.
+ * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#getAdapter
+ */
+ @SuppressWarnings("unchecked")
+ private Map<Class,Object> fAdapters = Collections.synchronizedMap(new HashMap<Class,Object>());
+
+ /** Returns the owner ID of this session */
+ public String getOwnerId() { return fOwnerId; }
+
+ public boolean isActive() { return DsfSession.isSessionActive(fId); }
+
+ /** Returns the ID of this session */
+ public String getId() { return fId; }
+
+ /** Returns the DSF executor of this session */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Adds a new listener for service events in this session.
+ * @param listener the listener that will receive service events
+ * @param filter optional filter to restrict the services that the
+ * listener will receive events from
+ */
+ public void addServiceEventListener(Object listener, Filter filter) {
+ ListenerEntry entry = new ListenerEntry(listener, filter);
+ assert !fListeners.containsKey(entry);
+ fListeners.put(entry, getEventHandlerMethods(listener));
+ }
+
+ /**
+ * Removes the given listener.
+ * @param listener listener to remove
+ */
+ public void removeServiceEventListener(Object listener) {
+ ListenerEntry entry = new ListenerEntry(listener, null);
+ assert fListeners.containsKey(entry);
+ fListeners.remove(entry);
+ }
+
+ /**
+ * Retrieves and increments the startup counter for services in this session.
+ * DSF services should retrieve this counter when they are initialized,
+ * and should return it through IService.getStartupNumber(). This number is then
+ * used to prioritize service events.
+ * @return current startup counter value
+ */
+ public int getAndIncrementServiceStartupCounter() { return fServiceInstanceCounter++; }
+
+ /**
+ * Dispatches the given event to service event listeners. The event is submitted to
+ * the executor to be dispatched.
+ * @param event to be sent out
+ * @param serviceProperties properties of the service requesting the event to be dispatched
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void dispatchEvent(final Object event, final Dictionary serviceProperties) {
+ getExecutor().submit(new DsfRunnable() {
+ public void run() { doDispatchEvent(event, serviceProperties);}
+ @Override
+ public String toString() { return "Event: " + event + ", from service " + serviceProperties; } //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+ /**
+ * Registers a IModelContext adapter of given type.
+ * @param adapterType class type to register the adapter for
+ * @param adapter adapter instance to register
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void registerModelAdapter(Class adapterType, Object adapter) {
+ fAdapters.put(adapterType, adapter);
+ }
+
+ /**
+ * Un-registers a IModelContext adapter of given type.
+ * @param adapterType adapter type to unregister
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void unregisterModelAdapter(Class adapterType) {
+ fAdapters.remove(adapterType);
+ }
+
+ /**
+ * Retrieves an adapter for given type for IModelContext.
+ * @param adapterType adapter type to look fors
+ * @return adapter object for given type, null if none is registered with the session
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public Object getModelAdapter(Class adapterType) {
+ return fAdapters.get(adapterType);
+ }
+
+ @Override
+ @ThreadSafe
+ public boolean equals(Object other) {
+ return other instanceof DsfSession && fId.equals(((DsfSession)other).fId);
+ }
+
+ @Override
+ @ThreadSafe
+ public int hashCode() { return fId.hashCode(); }
+
+ @SuppressWarnings("unchecked")
+ private void doDispatchEvent(Object event, Dictionary serviceProperties) {
+ // Build a list of listeners;
+ SortedMap<ListenerEntry,List<Method>> listeners = new TreeMap<ListenerEntry,List<Method>>(new Comparator<ListenerEntry>() {
+ public int compare(ListenerEntry o1, ListenerEntry o2) {
+ if (o1.fListener == o2.fListener) {
+ return 0;
+ } if (o1.fListener instanceof IDsfService && !(o2.fListener instanceof IDsfService)) {
+ return Integer.MIN_VALUE;
+ } else if (o2.fListener instanceof IDsfService && !(o1.fListener instanceof IDsfService)) {
+ return Integer.MAX_VALUE;
+ } else if ( (o1.fListener instanceof IDsfService) && (o2.fListener instanceof IDsfService) ) {
+ return ((IDsfService)o1.fListener).getStartupNumber() - ((IDsfService)o2.fListener).getStartupNumber();
+ }
+ return 1;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+ });
+
+ // Build a list of listeners and methods that are registered for this event class.
+ Class<?> eventClass = event.getClass();
+ for (Map.Entry<ListenerEntry,Method[]> entry : fListeners.entrySet()) {
+ if (entry.getKey().fFilter != null && !entry.getKey().fFilter.match(serviceProperties)) {
+ // Dispatching service doesn't match the listener's filter, skip it.
+ continue;
+ }
+ Method[] allMethods = entry.getValue();
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method method : allMethods) {
+ assert method.getParameterTypes().length > 0 : eventClass.getName() + "." + method.getName() //$NON-NLS-1$
+ + " signature contains zero parameters"; //$NON-NLS-1$
+ if ( method.getParameterTypes()[0].isAssignableFrom(eventClass) ) {
+ matchingMethods.add(method);
+ }
+ }
+ if (!matchingMethods.isEmpty()) {
+ listeners.put(entry.getKey(), matchingMethods);
+ }
+ }
+
+ // Call the listeners
+ for (Map.Entry<ListenerEntry,List<Method>> entry : listeners.entrySet()) {
+ for (Method method : entry.getValue()) {
+ try {
+ method.invoke(entry.getKey().fListener, new Object[] { event } );
+ }
+ catch (IllegalAccessException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Security exception when calling a service event handler method", e)); //$NON-NLS-1$
+ assert false : "IServiceEventListener.ServiceHandlerMethod method not accessible, is listener declared public?"; //$NON-NLS-1$
+ }
+ catch (InvocationTargetException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invocation exception when calling a service event handler method", e)); //$NON-NLS-1$
+ assert false : "Exception thrown by a IServiceEventListener.ServiceHandlerMethod method"; //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ private Method[] getEventHandlerMethods(Object listener)
+ {
+ List<Method> retVal = new ArrayList<Method>();
+ try {
+ Method[] methods = listener.getClass().getMethods();
+ for (Method method : methods) {
+ if (method.isAnnotationPresent(DsfServiceEventHandler.class)) {
+ Class<?>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length > 2) {
+ throw new IllegalArgumentException("ServiceEventHandler method has incorrect number of parameters"); //$NON-NLS-1$
+ }
+ retVal.add(method);
+ }
+ }
+ } catch(SecurityException e) {
+ throw new IllegalArgumentException("No permission to access ServiceEventHandler method"); //$NON-NLS-1$
+ }
+
+ if (retVal.isEmpty()) {
+ throw new IllegalArgumentException("No methods marked with @ServiceEventHandler in listener, is listener declared public?"); //$NON-NLS-1$
+ }
+ return retVal.toArray(new Method[retVal.size()]);
+ }
+
+ /**
+ * Class to be instanciated only using startSession()
+ */
+ @ThreadSafe
+ private DsfSession(DsfExecutor executor, String ownerId, String id) {
+ fId = id;
+ fOwnerId = ownerId;
+ fExecutor = executor;
+ }
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java
new file mode 100644
index 00000000000..f0181ea115b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.dsf.service;
+
+import java.util.Dictionary;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * The inteface that all DSF services must implement. It only privides a
+ * few features to help manage and identify the servies using the OSGI services
+ * framework.
+ * <p>
+ * Each service should register itself with OSGI services framework using
+ * the BundleContext.registerService() method. And each service should use the
+ * session ID that it is registering with as one of the service properties. If there
+ * is more than one instance of the service to be instanciated for a given session,
+ * additional properties should be used when registering the service to allow clients
+ * to uniquely identify the services.
+ * <p>
+ * By convention, all methods of DSF services can be called only on the dispatch
+ * thread of the DSF executor that is associated with the service. If a
+ * service exposes a method that is to be called on non-dispatch thread, it should
+ * be documented so.
+ *
+ * @see org.osgi.framework.BundleContext#registerService(String[], Object, Dictionary)
+ */
+@ConfinedToDsfExecutor("getExecutor")
+public interface IDsfService {
+
+ /**
+ * Property name for the session-id of this service. This property should be set by
+ * all DSF services when they are registered with OSGI service framework.
+ */
+ final static String PROP_SESSION_ID = "org.eclipse.cdt.dsf.service.IService.session_id"; //$NON-NLS-1$
+
+ /**
+ * Returns the DSF Session that this service belongs to.
+ */
+ DsfSession getSession();
+
+ /**
+ * Returns the executor that should be used to call methods of this service.
+ * This method is equivalent to calling getSession().getExecutor()
+ */
+ DsfExecutor getExecutor();
+
+ /**
+ * Returns the map of properties that this service was registered with.
+ */
+ @SuppressWarnings("unchecked")
+ Dictionary getProperties();
+
+ /**
+ * Returns a filter string that can be used to uniquely identify this
+ * service. This filter string should be based on the properties and class
+ * name, which were used to register this service.
+ * @see org.osgi.framework.BundleContext#getServiceReferences
+ */
+ String getServiceFilter();
+
+ /**
+ * Performs initialization and registration of the given service. Implementation
+ * should initialize the service, so that all methods and events belonging to this
+ * service can be used following the initialization.
+ * <br>Note: Since service initializaiton should be performed by an external
+ * logic, if this service depends on other services, the implementaion should
+ * assume that these services are already present, and if they are not, the
+ * initializaiton should fail.
+ * @param requestMonitor callback to be submitted when the initialization is complete
+ */
+ void initialize(RequestMonitor requestMonitor);
+
+ /**
+ * Performs shutdown and de-registration of the given service.
+ * @param requestMonitor callback to be submitted when shutdown is complete
+ */
+ void shutdown(RequestMonitor requestMonitor);
+
+ /**
+ * Returns the startup order number of this service among services in the same session.
+ * Implementations should get this number during initialization by calling
+ * Session.getAndIncrementServiceStartupCounter(). This counter is used to Session
+ * objects to prioritize the listeners of service events.
+ * @return startup order number of this service
+ * @see org.eclipse.cdt.dsf.service.DsfSession#getAndIncrementServiceStartupCounter()
+ */
+ int getStartupNumber();
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.classpath b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.classpath
new file mode 100644
index 00000000000..304e86186aa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.cvsignore b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.cvsignore
new file mode 100644
index 00000000000..ba077a4031a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.project b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.project
new file mode 100644
index 00000000000..2d088321537
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.examples.dsf.pda.ui</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/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..d777d691415
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,65 @@
+#Tue Jun 24 11:03:46 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=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=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..a453d5834ef
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,24 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: PDA Example Device Debugging UI Plug-in
+Bundle-SymbolicName: org.eclipse.cdt.examples.dsf.pda.ui;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.examples.dsf.pda.ui.PDAUIPlugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.debug.core,
+ org.eclipse.ui,
+ org.eclipse.debug.ui,
+ org.eclipse.jface.text,
+ org.eclipse.ui.editors,
+ org.eclipse.ui.workbench.texteditor,
+ org.eclipse.ui.ide,
+ org.eclipse.cdt.examples.dsf.pda,
+ org.eclipse.cdt.dsf,
+ org.eclipse.cdt.dsf.ui
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.cdt.examples.dsf.pda.ui,
+ org.eclipse.cdt.examples.dsf.pda.ui.breakpoints,
+ org.eclipse.cdt.examples.dsf.pda.ui.editor,
+ org.eclipse.cdt.examples.dsf.pda.ui.launcher
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/about.html b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/about.html
new file mode 100644
index 00000000000..c1cb2e12f40
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>May 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/build.properties b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/build.properties
new file mode 100644
index 00000000000..e5e3b48cf3f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/build.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+ bin/,\
+ about.html,\
+ META-INF/,\
+ .,\
+ icons/
+src.includes = src/,\
+ about.html,\
+ icons/,\
+ plugin.xml
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/icons/full/obj16/pda.gif b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/icons/full/obj16/pda.gif
new file mode 100644
index 00000000000..9a6adbfc87e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/icons/full/obj16/pda.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml
new file mode 100644
index 00000000000..da6e4f6b6ee
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/plugin.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+ <launchConfigurationTabGroup
+ class="org.eclipse.cdt.examples.dsf.pda.ui.launcher.PDATabGroup"
+ description="Specify and launch a PDA(DSF) program"
+ id="org.eclipse.cdt.examples.dsf.pda.tabGroup"
+ type="org.eclipse.cdt.examples.dsf.pda.launchType"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+ <launchConfigurationTypeImage
+ icon="icons/full/obj16/pda.gif"
+ configTypeID="org.eclipse.cdt.examples.dsf.pda.launchType"
+ id="org.eclipse.cdt.examples.dsf.pda.typeImage"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ class="org.eclipse.cdt.examples.dsf.pda.ui.PDAAdapterFactory"
+ adaptableType="org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch">
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory"/>
+ </factory>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.editors">
+ <editor
+ filenames="*.pda"
+ class="org.eclipse.cdt.examples.dsf.pda.ui.editor.PDAEditor"
+ icon="icons/full/obj16/pda.gif"
+ default="true"
+ name="PDA(DSF) Editor"
+ id="org.eclipse.cdt.examples.dsf.pda.editor"
+ extensions="pda"/>
+ </extension>
+ <extension
+ point="org.eclipse.ui.editorActions">
+ <editorContribution
+ targetID="org.eclipse.cdt.examples.dsf.pda.editor"
+ id="org.eclipse.cdt.examples.dsf.pda.rulerActions">
+ <action
+ label="Not Used"
+ class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
+ style="push"
+ actionID="RulerDoubleClick"
+ id="org.eclipse.cdt.examples.dsf.pda.doubleClickBreakpointAction"/>
+ </editorContribution>
+ </extension>
+ <extension
+ point="org.eclipse.ui.contexts">
+ <context
+ parentId="org.eclipse.debug.ui.debugging"
+ description="Debugging PDA(DSF) Programs"
+ name="Debugging PDA(DSF) Programs"
+ id="org.eclipse.cdt.examples.dsf.pda.debugging"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.ui.debugModelContextBindings">
+ <modelContextBinding
+ contextId="org.eclipse.cdt.examples.dsf.pda.debugging"
+ debugModelId="org.eclipse.cdt.examples.dsf.pda.debugModel"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.ui.contextViewBindings">
+ <contextViewBinding
+ contextId="org.eclipse.cdt.examples.dsf.pda.debugging"
+ viewId="org.eclipse.cdt.examples.dsf.pda.dataStackView"/>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.popupMenus">
+ <viewerContribution
+ targetID="org.eclipse.cdt.examples.dsf.pda.editor.rulerMenu"
+ id="org.eclipse.cdt.examples.dsf.pda.editor.rulerActions">
+ <action
+ label="Toggle Breakpoint"
+ class="org.eclipse.debug.ui.actions.RulerToggleBreakpointActionDelegate"
+ menubarPath="debug"
+ id="org.eclipse.cdt.examples.dsf.pda.editor.ruler.toggleBreakpointAction"/>
+ </viewerContribution>
+ <viewerContribution
+ targetID="org.eclipse.cdt.examples.dsf.pda.editor.contextMenu"
+ id="org.eclipse.cdt.examples.dsf.pda.editor.menuActions">
+ <action
+ label="Run to Line"
+ definitionId="org.eclipse.debug.ui.commands.RunToLine"
+ class="org.eclipse.debug.ui.actions.RunToLineActionDelegate"
+ menubarPath="additions"
+ id="org.eclipse.cdt.examples.dsf.pda.editor.context.runToLineAction"/>
+ </viewerContribution>
+ </extension>
+
+ <extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ class="org.eclipse.cdt.examples.dsf.pda.ui.breakpoints.PDAEditorAdapterFactory"
+ adaptableType="org.eclipse.cdt.examples.dsf.pda.ui.editor.PDAEditor">
+ <adapter type="org.eclipse.debug.ui.actions.IToggleBreakpointsTarget"/>
+ </factory>
+ </extension> -->
+</plugin>
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAAdapterFactory.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAAdapterFactory.java
new file mode 100644
index 00000000000..ce756d66613
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAAdapterFactory.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.pda.ui;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfResumeCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepIntoCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepOverCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfStepReturnCommand;
+import org.eclipse.cdt.dsf.debug.ui.actions.DsfSuspendCommand;
+import org.eclipse.cdt.dsf.debug.ui.sourcelookup.DsfSourceDisplayAdapter;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.DefaultDsfModelSelectionPolicyFactory;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch;
+import org.eclipse.cdt.examples.dsf.pda.ui.actions.PDATerminateCommand;
+import org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.PDAVMAdapter;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.core.commands.IResumeHandler;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.core.model.IDebugModelProvider;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
+import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
+
+/**
+ * The adapter factory is the central point of control of view model and other
+ * UI adapters of a DSF-based debugger. As new launches are created and
+ * old ones removed, this factory manages the life cycle of the associated
+ * UI adapters.
+ * <p>
+ * As a platform adapter factory, this factory only provides adapters for
+ * the launch object. Adapters for all other objects in the DSF model hierarchy
+ * are registered with the DSF session.
+ * </p>
+ */
+@ThreadSafe
+@SuppressWarnings({"restriction"})
+public class PDAAdapterFactory implements IAdapterFactory, ILaunchesListener2
+{
+ /**
+ * Contains the set of adapters that are created for each launch instance.
+ */
+ @Immutable
+ private static class LaunchAdapterSet {
+ // View Model adapter
+ final PDAVMAdapter fViewModelAdapter;
+
+ // Source lookup and positioning adapter
+ final DsfSourceDisplayAdapter fSourceDisplayAdapter;
+
+ // Command adapters
+ final DsfStepIntoCommand fStepIntoCommand;
+ final DsfStepOverCommand fStepOverCommand;
+ final DsfStepReturnCommand fStepReturnCommand;
+ final DsfSuspendCommand fSuspendCommand;
+ final DsfResumeCommand fResumeCommand;
+ final PDATerminateCommand fTerminateCommand;
+
+ // Adapters for integration with other UI actions
+ final IDebugModelProvider fDebugModelProvider;
+ final PDALaunch fLaunch;
+
+ final SteppingController fSteppingController;
+
+ private IModelSelectionPolicyFactory fModelSelectionPolicyFactory;
+
+ LaunchAdapterSet(PDALaunch launch) {
+ // Initialize launch and session.
+ fLaunch = launch;
+ DsfSession session = launch.getSession();
+
+ // register stepping controller
+ fSteppingController = new SteppingController(session);
+ session.registerModelAdapter(SteppingController.class, fSteppingController);
+
+ // Initialize VM
+ fViewModelAdapter = new PDAVMAdapter(session, fSteppingController);
+
+ // Initialize source lookup
+ fSourceDisplayAdapter = new DsfSourceDisplayAdapter(session, (ISourceLookupDirector)launch.getSourceLocator(), fSteppingController);
+ session.registerModelAdapter(ISourceDisplay.class, fSourceDisplayAdapter);
+
+ // Default selection policy
+ fModelSelectionPolicyFactory = new DefaultDsfModelSelectionPolicyFactory();
+ session.registerModelAdapter(IModelSelectionPolicyFactory.class, fModelSelectionPolicyFactory);
+
+ // Initialize retargetable command handler.
+ fStepIntoCommand = new DsfStepIntoCommand(session, null);
+ fStepOverCommand = new DsfStepOverCommand(session, null);
+ fStepReturnCommand = new DsfStepReturnCommand(session);
+ fSuspendCommand = new DsfSuspendCommand(session);
+ fResumeCommand = new DsfResumeCommand(session);
+ fTerminateCommand = new PDATerminateCommand(session);
+ session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand);
+ session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand);
+ session.registerModelAdapter(IStepReturnHandler.class, fStepReturnCommand);
+ session.registerModelAdapter(ISuspendHandler.class, fSuspendCommand);
+ session.registerModelAdapter(IResumeHandler.class, fResumeCommand);
+ session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand);
+
+ // Initialize debug model provider
+ fDebugModelProvider = new IDebugModelProvider() {
+ public String[] getModelIdentifiers() {
+ return new String[] { PDAPlugin.ID_PDA_DEBUG_MODEL };
+ }
+ };
+ session.registerModelAdapter(IDebugModelProvider.class, fDebugModelProvider);
+
+ // Register the launch as an adapter This ensures that the launch,
+ // and debug model ID will be associated with all DMContexts from this
+ // session.
+ session.registerModelAdapter(ILaunch.class, fLaunch);
+ }
+
+ void dispose() {
+ DsfSession session = fLaunch.getSession();
+
+ fViewModelAdapter.dispose();
+
+ session.unregisterModelAdapter(ISourceDisplay.class);
+ if (fSourceDisplayAdapter != null) fSourceDisplayAdapter.dispose();
+
+ session.unregisterModelAdapter(SteppingController.class);
+ fSteppingController.dispose();
+
+ session.unregisterModelAdapter(IModelSelectionPolicyFactory.class);
+
+ session.unregisterModelAdapter(IStepIntoHandler.class);
+ session.unregisterModelAdapter(IStepOverHandler.class);
+ session.unregisterModelAdapter(IStepReturnHandler.class);
+ session.unregisterModelAdapter(ISuspendHandler.class);
+ session.unregisterModelAdapter(IResumeHandler.class);
+ session.unregisterModelAdapter(ITerminateHandler.class);
+ fStepIntoCommand.dispose();
+ fStepOverCommand.dispose();
+ fStepReturnCommand.dispose();
+ fSuspendCommand.dispose();
+ fResumeCommand.dispose();
+ fTerminateCommand.dispose();
+ }
+ }
+
+ /**
+ * Active adapter sets. They are accessed using the launch instance
+ * which owns the debug services session.
+ */
+ private static Map<PDALaunch, LaunchAdapterSet> fgLaunchAdapterSets =
+ Collections.synchronizedMap(new HashMap<PDALaunch, LaunchAdapterSet>());
+
+ /**
+ * Map of launches for which adapter sets have already been disposed.
+ * This map (used as a set) is maintained in order to avoid re-creating an
+ * adapter set after the launch was removed from the launch manager, but
+ * while the launch is still being held by other classes which may
+ * request its adapters. A weak map is used to avoid leaking
+ * memory once the launches are no longer referenced.
+ * <p>
+ * Access to this map is synchronized using the fgLaunchAdapterSets
+ * instance.
+ * </p>
+ */
+ private static Map<ILaunch, Object> fgDisposedLaunchAdapterSets =
+ new WeakHashMap<ILaunch, Object>();
+
+ static void disposeAdapterSet(ILaunch launch) {
+ synchronized(fgLaunchAdapterSets) {
+ if ( fgLaunchAdapterSets.containsKey(launch) ) {
+ fgLaunchAdapterSets.remove(launch).dispose();
+ fgDisposedLaunchAdapterSets.put(launch, null);
+ }
+ }
+ }
+
+ public PDAAdapterFactory() {
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
+ }
+
+ // This IAdapterFactory method returns adapters for the PDA launch object only.
+ @SuppressWarnings("unchecked") // IAdapterFactory is Java 1.3
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if (!(adaptableObject instanceof PDALaunch)) return null;
+
+ PDALaunch launch = (PDALaunch)adaptableObject;
+
+ // Check for valid session.
+ // Note: even if the session is no longer active, the adapter set
+ // should still be returned. This is because the view model may still
+ // need to show elements representing a terminated process/thread/etc.
+ DsfSession session = launch.getSession();
+ if (session == null) return null;
+
+ // Find the correct set of adapters based on the launch. If not found
+ // it means that we have a new launch, and we have to create a
+ // new set of adapters.
+ LaunchAdapterSet adapterSet;
+ synchronized(fgLaunchAdapterSets) {
+ // The adapter set for the given launch was already disposed.
+ // Return a null adapter.
+ if (fgDisposedLaunchAdapterSets.containsKey(launch)) {
+ return null;
+ }
+ adapterSet = fgLaunchAdapterSets.get(launch);
+ if (adapterSet == null) {
+ adapterSet = new LaunchAdapterSet(launch);
+ fgLaunchAdapterSets.put(launch, adapterSet);
+ }
+ }
+
+ // Returns the adapter type for the launch object.
+ if (adapterType.equals(IElementContentProvider.class)) return adapterSet.fViewModelAdapter;
+ else if (adapterType.equals(IModelProxyFactory.class)) return adapterSet.fViewModelAdapter;
+ else return null;
+ }
+
+ @SuppressWarnings("unchecked") // IAdapterFactory is Java 1.3
+ public Class[] getAdapterList() {
+ return new Class[] { IElementContentProvider.class, IModelProxyFactory.class, IColumnPresentationFactory.class };
+ }
+
+ public void launchesRemoved(ILaunch[] launches) {
+ // Dispose the set of adapters for a launch only after the launch is
+ // removed from the view. If the launch is terminated, the adapters
+ // are still needed to populate the contents of the view.
+ for (ILaunch launch : launches) {
+ if (launch instanceof PDALaunch) {
+ disposeAdapterSet(launch);
+ }
+ }
+ }
+
+ public void launchesTerminated(ILaunch[] launches) {
+ }
+
+ public void launchesAdded(ILaunch[] launches) {
+ }
+
+ public void launchesChanged(ILaunch[] launches) {
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAUIPlugin.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAUIPlugin.java
new file mode 100644
index 00000000000..e45c6727647
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/PDAUIPlugin.java
@@ -0,0 +1,155 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.internal.util.BundleUtility;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class PDAUIPlugin extends AbstractUIPlugin {
+
+ public static String PLUGIN_ID = "org.eclipse.cdt.examples.dsf.pda.ui ";
+
+ //The shared instance.
+ private static PDAUIPlugin plugin;
+
+ private static BundleContext fContext;
+
+ private final static String ICONS_PATH = "icons/full/";//$NON-NLS-1$
+ private final static String PATH_OBJECT = ICONS_PATH + "obj16/"; //Model object icons //$NON-NLS-1$
+
+ /**
+ * PDA program image
+ */
+ public final static String IMG_OBJ_PDA = "IMB_OBJ_PDA";
+
+ /**
+ * Keyword color
+ */
+ public final static RGB KEYWORD = new RGB(0,0,255);
+ public final static RGB LABEL = new RGB(128, 128, 0);
+
+ /**
+ * Managed colors
+ */
+ private Map<RGB, Color> fColors = new HashMap<RGB, Color>();
+
+ /**
+ * The constructor.
+ */
+ public PDAUIPlugin() {
+ super();
+ plugin = this;
+ }
+
+ /**
+ * This method is called upon plug-in activation
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fContext = context;
+ super.start(context);
+// Toggles single threaded adapter example
+// IAdapterManager adapterManager = Platform.getAdapterManager();
+// IAdapterFactory factory = new AdapterFactory();
+// adapterManager.registerAdapters(factory, PDADebugTarget.class);
+ }
+
+ /**
+ * This method is called when the plug-in is stopped
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ disposeAdapterSets();
+ super.stop(context);
+ plugin = null;
+ fContext = null;
+ for (Map.Entry<RGB, Color> entry : fColors.entrySet()) {
+ entry.getValue().dispose();
+ }
+ }
+
+ /**
+ * Returns the shared instance.
+ */
+ public static PDAUIPlugin getDefault() {
+ return plugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fContext;
+ }
+
+ @Override
+ protected void initializeImageRegistry(ImageRegistry reg) {
+ declareImage(IMG_OBJ_PDA, PATH_OBJECT + "pda.gif");
+ }
+
+ /**
+ * Declares a workbench image given the path of the image file (relative to
+ * the workbench plug-in). This is a helper method that creates the image
+ * descriptor and passes it to the main <code>declareImage</code> method.
+ *
+ * @param symbolicName the symbolic name of the image
+ * @param path the path of the image file relative to the base of the workbench
+ * plug-ins install directory
+ * <code>false</code> if this is not a shared image
+ */
+ private void declareImage(String key, String path) {
+ URL url = BundleUtility.find("org.eclipse.cdt.examples.dsf.pda.ui", path);
+ ImageDescriptor desc = ImageDescriptor.createFromURL(url);
+ getImageRegistry().put(key, desc);
+ }
+
+ /**
+ * Returns the color described by the given RGB.
+ *
+ * @param rgb
+ * @return color
+ */
+ public Color getColor(RGB rgb) {
+ Color color = fColors.get(rgb);
+ if (color == null) {
+ color= new Color(Display.getCurrent(), rgb);
+ fColors.put(rgb, color);
+ }
+ return color;
+ }
+
+ /**
+ * Dispose adapter sets for all launches.
+ */
+ private void disposeAdapterSets() {
+ for (ILaunch launch : DebugPlugin.getDefault().getLaunchManager().getLaunches()) {
+ if (launch instanceof PDALaunch) {
+ PDAAdapterFactory.disposeAdapterSet(launch);
+ }
+ }
+ }
+
+ }
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/actions/PDATerminateCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/actions/PDATerminateCommand.java
new file mode 100644
index 00000000000..923be68441f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/actions/PDATerminateCommand.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.pda.ui.actions;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.examples.dsf.pda.service.PDACommandControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+import org.eclipse.cdt.examples.dsf.pda.ui.PDAUIPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+
+/**
+ * The terminate command is specialized for the PDA debugger. Currently there
+ * is no standard interface for terminating a debug session in DSF, because the
+ * details of initiating and shutting down a debug session vary greatly in
+ * different debuggers.
+ */
+public class PDATerminateCommand implements ITerminateHandler {
+ // The executor and the services tracker, both initialized from a DSF session.
+ private final DsfSession fSession;
+ private final DsfServicesTracker fTracker;
+
+ public PDATerminateCommand(DsfSession session) {
+ fSession = session;
+ fTracker = new DsfServicesTracker(PDAUIPlugin.getBundleContext(), session.getId());
+ }
+
+ public void dispose() {
+ // DSF services tracker always has to be disposed, because the OSGi services
+ // use reference counting.
+ fTracker.dispose();
+ }
+
+ // Run control may not be available after a connection is terminated and shut down.
+ public void canExecute(final IEnabledStateRequest request) {
+ // Terminate can only operate on a single element.
+ if (request.getElements().length != 1 ||
+ !(request.getElements()[0] instanceof IDMVMContext) )
+ {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ // Find the PDA program context in the selected element. If one is not found,
+ // the action should be disabled.
+ IDMVMContext vmc = (IDMVMContext)request.getElements()[0];
+ final PDAVirtualMachineDMContext pdaProgramCtx = DMContexts.getAncestorOfType(vmc.getDMContext(), PDAVirtualMachineDMContext.class);
+ if (pdaProgramCtx == null) {
+ request.setEnabled(false);
+ request.done();
+ return;
+ }
+
+ try {
+ fSession.getExecutor().execute(
+ new DsfRunnable() {
+ public void run() {
+ // Get the processes service and the exec context.
+ PDACommandControl commandControl = fTracker.getService(PDACommandControl.class);
+ if (commandControl == null || pdaProgramCtx == null) {
+ // Context or service already invalid.
+ request.setEnabled(false);
+ request.done();
+ } else {
+ // Check whether the control is terminated.
+ request.setEnabled(!commandControl.isTerminated());
+ request.done();
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // The DSF session for this context is no longer active. It's possible to check
+ // for this condition before calling fSession.getExecutor().execute(), but
+ // since this method is executing in a different thread than the session control,
+ // there would still be a chance for a race condition leading to this exception.
+ request.setEnabled(false);
+ request.done();
+ }
+ }
+
+ public boolean execute(final IDebugCommandRequest request) {
+ // Skip the checks and assume that this method is called only if the action
+ // was enabled.
+
+ try {
+ fSession.getExecutor().submit(new DsfRunnable() {
+ public void run() {
+ // If the command control service is available, attempt to terminate the program.
+ PDACommandControl commandControl = fTracker.getService(PDACommandControl.class);
+ if (commandControl != null) {
+
+ commandControl.terminate(
+ new RequestMonitor(ImmediateExecutor.getInstance(), null) {
+ @Override
+ protected void handleCompleted() {
+ request.setStatus(getStatus());
+ request.done();
+ }
+ });
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ request.setStatus(new Status(IStatus.ERROR, PDAUIPlugin.PLUGIN_ID, "PDA debug session is shut down."));
+ request.done();
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDABreakpointAdapter.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDABreakpointAdapter.java
new file mode 100644
index 00000000000..806e87bd88b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDABreakpointAdapter.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.breakpoints;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDALineBreakpoint;
+import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDAWatchpoint;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.ILineBreakpoint;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+
+/**
+ * Adapter to create breakpoints in PDA files.
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.ui.
+ * </p>
+ */
+public class PDABreakpointAdapter implements IToggleBreakpointsTargetExtension {
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleLineBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ ITextEditor textEditor = getEditor(part);
+ if (textEditor != null) {
+ IResource resource = (IResource) textEditor.getEditorInput().getAdapter(IResource.class);
+ ITextSelection textSelection = (ITextSelection) selection;
+ int lineNumber = textSelection.getStartLine();
+ IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(PDAPlugin.ID_PDA_DEBUG_MODEL);
+ for (int i = 0; i < breakpoints.length; i++) {
+ IBreakpoint breakpoint = breakpoints[i];
+ if (breakpoint instanceof ILineBreakpoint && resource.equals(breakpoint.getMarker().getResource())) {
+ if (((ILineBreakpoint)breakpoint).getLineNumber() == (lineNumber + 1)) {
+ // remove
+ breakpoint.delete();
+ return;
+ }
+ }
+ }
+ // create line breakpoint (doc line numbers start at 0)
+ PDALineBreakpoint lineBreakpoint = new PDALineBreakpoint(resource, lineNumber + 1);
+ DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(lineBreakpoint);
+ }
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleLineBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
+ return getEditor(part) != null;
+ }
+
+ /**
+ * Returns the editor being used to edit a PDA file, associated with the
+ * given part, or <code>null</code> if none.
+ *
+ * @param part workbench part
+ * @return the editor being used to edit a PDA file, associated with the
+ * given part, or <code>null</code> if none
+ */
+ private ITextEditor getEditor(IWorkbenchPart part) {
+ if (part instanceof ITextEditor) {
+ ITextEditor editorPart = (ITextEditor) part;
+ IResource resource = (IResource) editorPart.getEditorInput().getAdapter(IResource.class);
+ if (resource != null) {
+ String extension = resource.getFileExtension();
+ if (extension != null && extension.equals("pda")) {
+ return editorPart;
+ }
+ }
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleMethodBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
+ return false;
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#toggleWatchpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ String[] variableAndFunctionName = getVariableAndFunctionName(part, selection);
+ if (variableAndFunctionName != null && part instanceof ITextEditor && selection instanceof ITextSelection) {
+ ITextEditor editorPart = (ITextEditor)part;
+ int lineNumber = ((ITextSelection)selection).getStartLine();
+ IResource resource = (IResource) editorPart.getEditorInput().getAdapter(IResource.class);
+ String var = variableAndFunctionName[0];
+ String fcn = variableAndFunctionName[1];
+ // look for existing watchpoint to delete
+ IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(PDAPlugin.ID_PDA_DEBUG_MODEL);
+ for (int i = 0; i < breakpoints.length; i++) {
+ IBreakpoint breakpoint = breakpoints[i];
+ if (breakpoint instanceof PDAWatchpoint && resource.equals(breakpoint.getMarker().getResource())) {
+ PDAWatchpoint watchpoint = (PDAWatchpoint)breakpoint;
+ String otherVar = watchpoint.getVariableName();
+ String otherFcn = watchpoint.getFunctionName();
+ if (otherVar.equals(var) && otherFcn.equals(fcn)) {
+ breakpoint.delete();
+ return;
+ }
+ }
+ }
+ // create watchpoint
+ PDAWatchpoint watchpoint = new PDAWatchpoint(resource, lineNumber + 1, fcn, var, true, true);
+ DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(watchpoint);
+ }
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTarget#canToggleWatchpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
+ return getVariableAndFunctionName(part, selection) != null;
+ }
+
+ /**
+ * Returns the variable and function names at the current line, or <code>null</code> if none.
+ *
+ * @param part text editor
+ * @param selection text selection
+ * @return the variable and function names at the current line, or <code>null</code> if none.
+ * The array has two elements, the first is the variable name, the second is the function name.
+ */
+ private String[] getVariableAndFunctionName(IWorkbenchPart part, ISelection selection) {
+ ITextEditor editor = getEditor(part);
+ if (editor != null && selection instanceof ITextSelection) {
+ ITextSelection textSelection = (ITextSelection) selection;
+ IDocumentProvider documentProvider = editor.getDocumentProvider();
+ try {
+ documentProvider.connect(this);
+ IDocument document = documentProvider.getDocument(editor.getEditorInput());
+ IRegion region = document.getLineInformationOfOffset(textSelection.getOffset());
+ String string = document.get(region.getOffset(), region.getLength()).trim();
+ if (string.startsWith("var ")) {
+ String varName = string.substring(4).trim();
+ String fcnName = getFunctionName(document, varName, document.getLineOfOffset(textSelection.getOffset()));
+ return new String[] {varName, fcnName};
+ }
+ } catch (CoreException e) {
+ } catch (BadLocationException e) {
+ } finally {
+ documentProvider.disconnect(this);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the name of the function containing the given variable defined at the given
+ * line number in the specified document.
+ *
+ * @param document PDA source file
+ * @param varName variable name
+ * @param line line numbner at which the variable is defined
+ * @return name of function defining the variable
+ */
+ private String getFunctionName(IDocument document, String varName, int line) {
+ // This is a simple guess at the function name - look for the labels preceeding
+ // the variable definition, and then see if there are any 'calls' to that
+ // label. If none, assumet the variable is in the "_main_" function
+ String source = document.get();
+ int lineIndex = line - 1;
+ while (lineIndex >= 0) {
+ try {
+ IRegion information = document.getLineInformation(lineIndex);
+ String lineText = document.get(information.getOffset(), information.getLength());
+ if (lineText.startsWith(":")) {
+ String label = lineText.substring(1);
+ if (source.indexOf("call " + label) >= 0) {
+ return label;
+ }
+ }
+ lineIndex--;
+ } catch (BadLocationException e) {
+ }
+ }
+ return "_main_";
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#toggleBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ if (canToggleWatchpoints(part, selection)) {
+ toggleWatchpoints(part, selection);
+ } else {
+ toggleLineBreakpoints(part, selection);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension#canToggleBreakpoints(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
+ */
+ public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
+ return canToggleLineBreakpoints(part, selection) || canToggleWatchpoints(part, selection);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDAEditorAdapterFactory.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDAEditorAdapterFactory.java
new file mode 100644
index 00000000000..0fdfb769b78
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/breakpoints/PDAEditorAdapterFactory.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.breakpoints;
+import org.eclipse.cdt.examples.dsf.pda.ui.editor.PDAEditor;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+
+
+/**
+ * Creates a toggle breakpoint adapter
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.ui.
+ * </p>
+ */
+public class PDAEditorAdapterFactory implements IAdapterFactory {
+
+ @SuppressWarnings("unchecked") // IAdapterFactory is Java 1.3
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if (adaptableObject instanceof PDAEditor) {
+ ITextEditor editorPart = (ITextEditor) adaptableObject;
+ IResource resource = (IResource) editorPart.getEditorInput().getAdapter(IResource.class);
+ if (resource != null) {
+ String extension = resource.getFileExtension();
+ if (extension != null && extension.equals("pda")) {
+ if (adapterType.equals(IToggleBreakpointsTarget.class)) {
+ return new PDABreakpointAdapter();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked") // IAdapterFactory is Java 1.3
+ public Class[] getAdapterList() {
+ return new Class[]{IToggleBreakpointsTarget.class};
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/AnnotationHover.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/AnnotationHover.java
new file mode 100644
index 00000000000..4f27cb49e94
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/AnnotationHover.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.jface.text.source.ISourceViewer;
+
+/**
+ * Returns hover for breakpoints.
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.ui.
+ * </p>
+ */
+public class AnnotationHover implements IAnnotationHover {
+
+ public String getHoverInfo(ISourceViewer sourceViewer, int lineNumber) {
+ IAnnotationModel annotationModel = sourceViewer.getAnnotationModel();
+ Iterator<?> iterator = annotationModel.getAnnotationIterator();
+ while (iterator.hasNext()) {
+ Annotation annotation = (Annotation) iterator.next();
+ Position position = annotationModel.getPosition(annotation);
+ try {
+ int lineOfAnnotation = sourceViewer.getDocument().getLineOfOffset(position.getOffset());
+ if (lineNumber == lineOfAnnotation) {
+ return annotation.getText();
+ }
+ } catch (BadLocationException e) {
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistProcessor.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistProcessor.java
new file mode 100644
index 00000000000..6db376d2c00
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistProcessor.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.contentassist.IContextInformationValidator;
+
+public class PDAContentAssistProcessor implements IContentAssistProcessor {
+
+ public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
+ int index = offset - 1;
+ StringBuffer prefix = new StringBuffer();
+ IDocument document = viewer.getDocument();
+ while (index > 0) {
+ try {
+ char prev = document.getChar(index);
+ if (Character.isWhitespace(prev)) {
+ break;
+ }
+ prefix.insert(0, prev);
+ index--;
+ } catch (BadLocationException e) {
+ }
+ }
+
+ List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
+ String[] keywords = PDAScanner.fgKeywords;
+ if (prefix.length() > 0) {
+ String word = prefix.toString();
+ for (int i = 0; i < keywords.length; i++) {
+ String keyword = keywords[i];
+ if (keyword.startsWith(word) && word.length() < keyword.length()) {
+ proposals.add(new CompletionProposal(keyword + " ", index + 1, offset - (index + 1), keyword.length() + 1));
+ }
+ }
+ } else {
+ // propose all keywords
+ for (int i = 0; i < keywords.length; i++) {
+ String keyword = keywords[i];
+ proposals.add(new CompletionProposal(keyword + " ", offset, 0, keyword.length() + 1));
+ }
+ }
+ if (!proposals.isEmpty()) {
+ return proposals.toArray(new ICompletionProposal[proposals.size()]);
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int)
+ */
+ public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters()
+ */
+ public char[] getCompletionProposalAutoActivationCharacters() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters()
+ */
+ public char[] getContextInformationAutoActivationCharacters() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage()
+ */
+ public String getErrorMessage() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator()
+ */
+ public IContextInformationValidator getContextInformationValidator() {
+ return null;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistant.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistant.java
new file mode 100644
index 00000000000..5ba2782f8fb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAContentAssistant.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.contentassist.ContentAssistant;
+import org.eclipse.swt.widgets.Shell;
+
+public class PDAContentAssistant extends ContentAssistant {
+
+ public PDAContentAssistant() {
+ super();
+
+ PDAContentAssistProcessor processor= new PDAContentAssistProcessor();
+ setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE);
+
+ enableAutoActivation(false);
+ enableAutoInsert(false);
+
+ setInformationControlCreator(getInformationControlCreator());
+ }
+
+ private IInformationControlCreator getInformationControlCreator() {
+ return new IInformationControlCreator() {
+ public IInformationControl createInformationControl(Shell parent) {
+ return new DefaultInformationControl(parent);
+ }
+ };
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditor.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditor.java
new file mode 100644
index 00000000000..198575f32ef
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditor.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import java.util.ResourceBundle;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.texteditor.AbstractDecoratedTextEditor;
+import org.eclipse.ui.texteditor.ContentAssistAction;
+import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
+
+/**
+ * PDA editor
+ */
+public class PDAEditor extends AbstractDecoratedTextEditor {
+
+ /**
+ * Creates a PDE editor
+ */
+ public PDAEditor() {
+ super();
+ setSourceViewerConfiguration(new PDASourceViewerConfiguration());
+ setRulerContextMenuId("pda.editor.rulerMenu");
+ setEditorContextMenuId("pda.editor.editorMenu");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.AbstractTextEditor#createActions()
+ */
+ protected void createActions() {
+ super.createActions();
+ ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.cdt.examples.dsf.pda.ui.editor.PDAEditorMessages"); //$NON-NLS-1$
+ IAction action = new ContentAssistAction(bundle, "ContentAssistProposal.", this); //$NON-NLS-1$
+ action.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS);
+ setAction("ContentAssistProposal", action); //$NON-NLS-1$
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditorMessages.properties b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditorMessages.properties
new file mode 100644
index 00000000000..3215e8892de
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAEditorMessages.properties
@@ -0,0 +1,15 @@
+###############################################################################
+# Copyright (c) 2000, 2007 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
+###############################################################################
+
+ContentAssistProposal.label=Content &Assist
+ContentAssistProposal.tooltip=Content Assist
+ContentAssistProposal.image=
+ContentAssistProposal.description=Content Assist \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAScanner.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAScanner.java
new file mode 100644
index 00000000000..2604c65c0d6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDAScanner.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import org.eclipse.cdt.examples.dsf.pda.ui.PDAUIPlugin;
+import org.eclipse.jface.text.TextAttribute;
+import org.eclipse.jface.text.rules.BufferedRuleBasedScanner;
+import org.eclipse.jface.text.rules.IRule;
+import org.eclipse.jface.text.rules.IWordDetector;
+import org.eclipse.jface.text.rules.Token;
+import org.eclipse.jface.text.rules.WordRule;
+
+
+/**
+ * PDA editor keyword scanner.
+ */
+public class PDAScanner extends BufferedRuleBasedScanner {
+
+ /**
+ * PDA keywods
+ */
+ public static final String[] fgKeywords = new String[] {
+ "add", "branch_not_zero", "call", "dec", "dup",
+ "halt", "output", "pop", "push", "return", "var"
+ };
+
+ /**
+ * Detects potential keywords
+ */
+ class PDAWordDetector implements IWordDetector {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.rules.IWordDetector#isWordStart(char)
+ */
+ public boolean isWordStart(char c) {
+ return Character.isLetter(c);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.rules.IWordDetector#isWordPart(char)
+ */
+ public boolean isWordPart(char c) {
+ return Character.isLetter(c) || c == '_';
+ }
+ }
+
+ /**
+ * Detects PDA branch labels
+ */
+ class PDALabelDetector extends PDAWordDetector {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.rules.IWordDetector#isWordStart(char)
+ */
+ public boolean isWordStart(char c) {
+ return c == ':';
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.rules.IWordDetector#isWordPart(char)
+ */
+ public boolean isWordPart(char c) {
+ return super.isWordPart(c) || Character.isDigit(c);
+ }
+ }
+
+ /**
+ * Constructs a scanner that identifies PDA keywords.
+ */
+ public PDAScanner() {
+ // keywords
+ Token token = new Token(new TextAttribute(PDAUIPlugin.getDefault().getColor(PDAUIPlugin.KEYWORD)));
+ WordRule keywords = new WordRule(new PDAWordDetector());
+ for (int i = 0; i < fgKeywords.length; i++) {
+ String keyword = fgKeywords[i];
+ keywords.addWord(keyword, token);
+ }
+ // labels
+ token = new Token(new TextAttribute(PDAUIPlugin.getDefault().getColor(PDAUIPlugin.LABEL)));
+ WordRule labels = new WordRule(new PDALabelDetector(), token);
+ setRules(new IRule[]{keywords, labels});
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDASourceViewerConfiguration.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDASourceViewerConfiguration.java
new file mode 100644
index 00000000000..15b6704d341
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PDASourceViewerConfiguration.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.jface.text.presentation.PresentationReconciler;
+import org.eclipse.jface.text.rules.DefaultDamagerRepairer;
+import org.eclipse.jface.text.source.IAnnotationHover;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
+
+/**
+ * Source view configuration for the PDA editor
+ */
+public class PDASourceViewerConfiguration extends TextSourceViewerConfiguration {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getTextHover(org.eclipse.jface.text.source.ISourceViewer, java.lang.String)
+ */
+ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
+ return new TextHover();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getAnnotationHover(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ public IAnnotationHover getAnnotationHover(ISourceViewer sourceViewer) {
+ return new AnnotationHover();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getPresentationReconciler(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) {
+ PresentationReconciler reconciler = new PresentationReconciler();
+ reconciler.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+ DefaultDamagerRepairer dr = new DefaultDamagerRepairer(new PDAScanner());
+ reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);
+ return reconciler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getContentAssistant(org.eclipse.jface.text.source.ISourceViewer)
+ */
+ public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
+ return new PDAContentAssistant();
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PopFrameActionDelegate.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PopFrameActionDelegate.java
new file mode 100644
index 00000000000..e3a6212fa80
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/PopFrameActionDelegate.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.ui.IActionDelegate2;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+
+
+public class PopFrameActionDelegate implements IObjectActionDelegate, IActionDelegate2 {
+
+ //private PDAThread fThread = null;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IObjectActionDelegate#setActivePart(org.eclipse.jface.action.IAction, org.eclipse.ui.IWorkbenchPart)
+ */
+ public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+ /*
+ try {
+ fThread.pop();
+ } catch (DebugException e) {
+ }*/
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ /* if (selection instanceof IStructuredSelection) {
+ IStructuredSelection ss = (IStructuredSelection) selection;
+ Object element = ss.getFirstElement();
+ if (element instanceof PDAStackFrame) {
+ PDAStackFrame frame = (PDAStackFrame) element;
+ //#ifdef ex5
+//# // TODO: Exercise 5 - enable the action if the frame's thread supports it
+ //#else
+ fThread = (PDAThread) frame.getThread();
+ try {
+ action.setEnabled(fThread.canPop() && fThread.getTopStackFrame().equals(frame));
+ } catch (DebugException e) {
+ }
+ return;
+ //#endif
+ }
+
+ }
+ action.setEnabled(false);
+ */
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate2#init(org.eclipse.jface.action.IAction)
+ */
+ public void init(IAction action) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate2#dispose()
+ */
+ public void dispose() {
+ //fThread = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate2#runWithEvent(org.eclipse.jface.action.IAction, org.eclipse.swt.widgets.Event)
+ */
+ public void runWithEvent(IAction action, Event event) {
+ run(action);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/TextHover.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/TextHover.java
new file mode 100644
index 00000000000..0ca40e87d90
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/TextHover.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+
+
+/**
+ * Produces debug hover for the PDA debugger.
+ */
+public class TextHover implements ITextHover {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
+ */
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ /*String varName = null;
+ try {
+ varName = textViewer.getDocument().get(hoverRegion.getOffset(), hoverRegion.getLength());
+ } catch (BadLocationException e) {
+ return null;
+ }
+ if (varName.startsWith("$") && varName.length() > 1) {
+ varName = varName.substring(1);
+ }
+
+ PDAStackFrame frame = null;
+ IAdaptable debugContext = DebugUITools.getDebugContext();
+ if (debugContext instanceof PDAStackFrame) {
+ frame = (PDAStackFrame) debugContext;
+ } else if (debugContext instanceof PDAThread) {
+ PDAThread thread = (PDAThread) debugContext;
+ try {
+ frame = (PDAStackFrame) thread.getTopStackFrame();
+ } catch (DebugException e) {
+ return null;
+ }
+ } else if (debugContext instanceof PDADebugTarget) {
+ PDADebugTarget target = (PDADebugTarget) debugContext;
+ try {
+ IThread[] threads = target.getThreads();
+ if (threads.length > 0) {
+ frame = (PDAStackFrame) threads[0].getTopStackFrame();
+ }
+ } catch (DebugException e) {
+ return null;
+ }
+ }
+ if (frame != null) {
+ try {
+ IVariable[] variables = frame.getVariables();
+ for (int i = 0; i < variables.length; i++) {
+ IVariable variable = variables[i];
+ if (variable.getName().equals(varName)) {
+ return varName + " = " + variable.getValue().getValueString();
+ }
+ }
+ } catch (DebugException e) {
+ }
+ }*/
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.text.ITextHover#getHoverRegion(org.eclipse.jface.text.ITextViewer, int)
+ */
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ return WordFinder.findWord(textViewer.getDocument(), offset);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/WordFinder.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/WordFinder.java
new file mode 100644
index 00000000000..e67e1adfaaa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/editor/WordFinder.java
@@ -0,0 +1,80 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.editor;
+
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
+
+/**
+ * Looks for an identifier in a source file
+ */
+public class WordFinder {
+
+ /**
+ * Returns the region in the given document that contains an identifier, or
+ * <code>null</code> if none.
+ *
+ * @param document document to search
+ * @param offset offset at which to look for an identifier
+ * @return region containing an identifier, or <code>null</code>
+ */
+ public static IRegion findWord(IDocument document, int offset) {
+
+ int start= -1;
+ int end= -1;
+
+
+ try {
+
+ int pos= offset;
+ char c;
+
+ while (pos >= 0) {
+ c= document.getChar(pos);
+ if (!Character.isJavaIdentifierPart(c))
+ break;
+ --pos;
+ }
+
+ start= pos;
+
+ pos= offset;
+ int length= document.getLength();
+
+ while (pos < length) {
+ c= document.getChar(pos);
+ if (!Character.isJavaIdentifierPart(c))
+ break;
+ ++pos;
+ }
+
+ end= pos;
+
+ } catch (BadLocationException x) {
+ }
+
+ if (start > -1 && end > -1) {
+ if (start == offset && end == offset)
+ return new Region(offset, 0);
+ else if (start == offset)
+ return new Region(start, end - start);
+ else
+ return new Region(start + 1, end - start - 1);
+ }
+
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDAMainTab.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDAMainTab.java
new file mode 100644
index 00000000000..6f4ca94aa4d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDAMainTab.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.launcher;
+
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.ui.PDAUIPlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ResourceListSelectionDialog;
+
+
+/**
+ * Tab to specify the PDA program to run/debug.
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.ui.
+ * </p>
+ */
+public class PDAMainTab extends AbstractLaunchConfigurationTab {
+
+ private Text fProgramText;
+ private Button fProgramButton;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ public void createControl(Composite parent) {
+ Font font = parent.getFont();
+
+ Composite comp = new Composite(parent, SWT.NONE);
+ setControl(comp);
+ GridLayout topLayout = new GridLayout();
+ topLayout.verticalSpacing = 0;
+ topLayout.numColumns = 3;
+ comp.setLayout(topLayout);
+ comp.setFont(font);
+
+ createVerticalSpacer(comp, 3);
+
+ Label programLabel = new Label(comp, SWT.NONE);
+ programLabel.setText("&Program:");
+ GridData gd = new GridData(GridData.BEGINNING);
+ programLabel.setLayoutData(gd);
+ programLabel.setFont(font);
+
+ fProgramText = new Text(comp, SWT.SINGLE | SWT.BORDER);
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ fProgramText.setLayoutData(gd);
+ fProgramText.setFont(font);
+ fProgramText.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ fProgramButton = createPushButton(comp, "&Browse...", null); //$NON-NLS-1$
+ fProgramButton.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ browsePDAFiles();
+ }
+ });
+ }
+
+ /**
+ * Open a resource chooser to select a PDA program
+ */
+ protected void browsePDAFiles() {
+ ResourceListSelectionDialog dialog = new ResourceListSelectionDialog(getShell(), ResourcesPlugin.getWorkspace().getRoot(), IResource.FILE);
+ dialog.setTitle("PDA Program");
+ dialog.setMessage("Select PDA Program");
+ if (dialog.open() == Window.OK) {
+ Object[] files = dialog.getResult();
+ IFile file = (IFile) files[0];
+ fProgramText.setText(file.getFullPath().toString());
+ }
+
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
+ */
+ public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration)
+ */
+ public void initializeFrom(ILaunchConfiguration configuration) {
+ //#ifdef ex1
+//# // TODO: Exercise 1 - retrieve the program path attribute from the launch configuration
+//# String program = null;
+//# if (program != null) {
+//# fProgramText.setText(program);
+//# }
+ //#else
+ try {
+ String program = null;
+ program = configuration.getAttribute(PDAPlugin.ATTR_PDA_PROGRAM, (String)null);
+ if (program != null) {
+ fProgramText.setText(program);
+ }
+ } catch (CoreException e) {
+ setErrorMessage(e.getMessage());
+ }
+ //#endif
+ }
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#performApply(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy)
+ */
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ String program = fProgramText.getText().trim();
+ if (program.length() == 0) {
+ program = null;
+ }
+ //#ifdef ex1
+//# // TODO: Exercise 1 - update the launch configuration with the path to
+//# // currently specified program
+ //#else
+ configuration.setAttribute(PDAPlugin.ATTR_PDA_PROGRAM, program);
+ //#endif
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getName()
+ */
+ public String getName() {
+ return "Main";
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#isValid(org.eclipse.debug.core.ILaunchConfiguration)
+ */
+ public boolean isValid(ILaunchConfiguration launchConfig) {
+ setErrorMessage(null);
+ setMessage(null);
+ String text = fProgramText.getText();
+ //#ifdef ex1
+//# // TODO: Exercise 1 - validate the currently specified program exists and is not
+//# // empty, providing the user with feedback.
+ //#else
+ if (text.length() > 0) {
+ IPath path = new Path(text);
+ if (ResourcesPlugin.getWorkspace().getRoot().findMember(path) == null) {
+ setErrorMessage("Specified program does not exist");
+ return false;
+ }
+ } else {
+ setMessage("Specify a program");
+ }
+ //#endif
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTab#getImage()
+ */
+ public Image getImage() {
+ return PDAUIPlugin.getDefault().getImageRegistry().get(PDAUIPlugin.IMG_OBJ_PDA);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDATabGroup.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDATabGroup.java
new file mode 100644
index 00000000000..7c9ed2fb073
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/launcher/PDATabGroup.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.launcher;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
+
+/**
+ * Tab group for a PDA application
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.ui.
+ * </p>
+ */
+public class PDATabGroup extends AbstractLaunchConfigurationTabGroup {
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.ui.ILaunchConfigurationTabGroup#createTabs(org.eclipse.debug.ui.ILaunchConfigurationDialog, java.lang.String)
+ */
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+ //#ifdef ex1
+//# // TODO: Exercise 1 - add the PDA main tab, source lookup tab and common
+//# // tab to the tab group
+ //#else
+ setTabs(new ILaunchConfigurationTab[] {
+ new PDAMainTab(),
+ new SourceLookupTab(),
+ new CommonTab()
+ });
+ //#endif
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/PDAVMAdapter.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/PDAVMAdapter.java
new file mode 100644
index 00000000000..2e1761f769c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/PDAVMAdapter.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.pda.ui.viewmodel;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.AbstractDebugVMAdapter;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.SteppingController;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.register.RegisterVMProvider;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.variable.VariableVMProvider;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.launch.PDALaunchVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+@ThreadSafe
+@SuppressWarnings("restriction")
+public class PDAVMAdapter extends AbstractDebugVMAdapter
+{
+ public PDAVMAdapter(DsfSession session, SteppingController controller) {
+ super(session, controller);
+ getSession().registerModelAdapter(IColumnPresentationFactory.class, this);
+ }
+
+ @Override
+ public void dispose() {
+ getSession().unregisterModelAdapter(IColumnPresentationFactory.class);
+ super.dispose();
+ }
+
+ @Override
+ protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) {
+ if ( IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) {
+ return new PDALaunchVMProvider(this, context, getSession());
+ } else if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) {
+ return new VariableVMProvider(this, context, getSession());
+ } else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) {
+ return new ExpressionVMProvider(this, context, getSession());
+ } else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId()) ) {
+ return new RegisterVMProvider(this, context, getSession());
+ }
+ return null;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDALaunchVMProvider.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDALaunchVMProvider.java
new file mode 100644
index 00000000000..b00b63e8946
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDALaunchVMProvider.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Modified for new functionality
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.AbstractLaunchVMProvider;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.LaunchRootVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StackFramesVMNode;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.StandardProcessVMNode;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+
+/**
+ * View Model provider for the Launch (AKA Debug) view. The launch VM
+ * provider is configured with three nodes:
+ * <ul>
+ * <li> LaunchRootVMNode - This is the root of the PDA view model.</li>
+ * <li> PDAVirtualMachineVMNode - Supplies the element representing PDA VM</li>
+ * <li> PDAThreadsVMNode - Supplies the PDA thread elements</li>
+ * <li> StackFramesVMNode - Supplies the stack frame elements.</li>
+ * <li> StandardProcessVMNode - Supplies elements representing the PDA
+ * debugger process.</li>
+ * </ul>
+ */
+@SuppressWarnings("restriction")
+public class PDALaunchVMProvider extends AbstractLaunchVMProvider
+ implements IDebugEventSetListener, ILaunchesListener2
+{
+ @ThreadSafe
+ public PDALaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)
+ {
+ super(adapter, presentationContext, session);
+
+ IRootVMNode launchNode = new LaunchRootVMNode(this);
+ setRootNode(launchNode);
+
+ // Launch node is a parent to the processes and program nodes.
+ IVMNode pdaVirtualMachineNode = new PDAVirtualMachineVMNode(this, getSession());
+ IVMNode processesNode = new StandardProcessVMNode(this);
+ addChildNodes(launchNode, new IVMNode[] { pdaVirtualMachineNode, processesNode});
+
+ // Virtual machine node is under the PDA threads node.
+ IVMNode threadsNode = new PDAThreadsVMNode(this, getSession());
+ addChildNodes(pdaVirtualMachineNode, new IVMNode[] { threadsNode });
+
+ // Stack frames node is under the PDA threads node.
+ IVMNode stackFramesNode = new StackFramesVMNode(this, getSession());
+ addChildNodes(threadsNode, new IVMNode[] { stackFramesNode });
+
+ // Register the LaunchVM provider as a listener to debug and launch
+ // events. These events are used by the launch and processes nodes.
+ DebugPlugin.getDefault().addDebugEventListener(this);
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAThreadsVMNode.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAThreadsVMNode.java
new file mode 100644
index 00000000000..043f4bc9f08
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAThreadsVMNode.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson - Modified for multi threaded functionality
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.launch;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMData;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.AbstractThreadVMNode;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.examples.dsf.pda.service.PDARunControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.ui.IMemento;
+
+
+/**
+ * View model node supplying the PDA thread elements. It extends
+ * the base threads node and adds label and memento generation.
+ */
+@SuppressWarnings("restriction")
+public class PDAThreadsVMNode extends AbstractThreadVMNode
+ implements IElementLabelProvider, IElementMementoProvider
+{
+ public PDAThreadsVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session);
+ }
+
+ @Override
+ public String toString() {
+ return "PDAThreadVMNode(" + getSession().getId() + ")";
+ }
+
+ @Override
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+ final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class);
+ if ( runControl == null ) {
+ handleFailedUpdate(update);
+ continue;
+ }
+
+ final PDAThreadDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAThreadDMContext.class);
+
+ String imageKey = null;
+ if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+ } else {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+ }
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+ // Find the Reason for the State
+ getDMVMProvider().getModelData(
+ this, update, runControl, dmc,
+ new ViewerDataRequestMonitor<IExecutionDMData>(getSession().getExecutor(), update) {
+ @Override
+ public void handleCompleted(){
+ if (!isSuccess()) {
+ update.setLabel("<unavailable>", 0);
+ update.done();
+ return;
+ }
+
+ // We're in a new dispatch cycle, and we have to check whether the
+ // service reference is still valid.
+ final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class);
+ if ( runControl == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ final StateChangeReason reason = getData().getStateChangeReason();
+
+ // Create Labels of type Thread[GDBthreadId]RealThreadID/Name (State: Reason)
+ // Thread[1] 3457 (Suspended:BREAKPOINT)
+ final StringBuilder builder = new StringBuilder();
+ builder.append("Thread ");
+ builder.append(dmc.getID());
+ if(getServicesTracker().getService(IRunControl.class).isSuspended(dmc))
+ builder.append(" (Suspended");
+ else
+ builder.append(" (Running");
+ // Reason will be null before ContainerSuspendEvent is fired
+ if(reason != null) {
+ builder.append(" : ");
+ builder.append(reason);
+ }
+ builder.append(")");
+ update.setLabel(builder.toString(), 0);
+ update.done();
+ }
+ },
+ getExecutor());
+
+ }
+ }
+
+ private String produceThreadElementName(String viewName, PDAThreadDMContext execCtx) {
+ return "Thread." + execCtx.getID();
+ }
+
+ private static final String MEMENTO_NAME = "THREAD_MEMENTO_NAME";
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+ */
+ public void compareElements(IElementCompareRequest[] requests) {
+ for ( IElementCompareRequest request : requests ) {
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ String mementoName = memento.getString(MEMENTO_NAME);
+ if (mementoName != null) {
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+ if ( dmc instanceof PDAThreadDMContext) {
+ String elementName = produceThreadElementName(
+ request.getPresentationContext().getId(), (PDAThreadDMContext) dmc );
+ request.setEqual( elementName.equals( mementoName ) );
+ }
+ }
+ }
+ request.done();
+ }
+ }
+
+ /*
+ * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+ */
+ public void encodeElements(IElementMementoRequest[] requests) {
+ for ( IElementMementoRequest request : requests ) {
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ if (element instanceof IDMVMContext) {
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+ if ( dmc instanceof PDAThreadDMContext) {
+ String elementName = produceThreadElementName( request.getPresentationContext().getId(), (PDAThreadDMContext) dmc );
+ memento.putString(MEMENTO_NAME, elementName);
+ }
+ }
+ request.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
new file mode 100644
index 00000000000..62b57922fa3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda.ui/src/org/eclipse/cdt/examples/dsf/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Ericsson 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:
+ * Ericsson - Initial API and implementation
+ * Wind River Systems - Factored out AbstractContainerVMNode
+ *******************************************************************************/
+
+package org.eclipse.cdt.examples.dsf.pda.ui.viewmodel.launch;
+
+
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMData;
+import org.eclipse.cdt.dsf.debug.ui.viewmodel.launch.AbstractContainerVMNode;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.examples.dsf.pda.service.PDACommandControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.ui.IMemento;
+
+
+/**
+ * View Model node representing a PDA virtual machine. It extends
+ * the base container node and adds label and memento generation.
+ */
+@SuppressWarnings("restriction")
+public class PDAVirtualMachineVMNode extends AbstractContainerVMNode
+ implements IElementMementoProvider
+{
+ public PDAVirtualMachineVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session);
+ }
+
+ @Override
+ public String toString() {
+ return "PDAContainerVMNode(" + getSession().getId() + ")";
+ }
+
+
+ @Override
+ protected void updateElementsInSessionThread(IChildrenUpdate update) {
+ // Get the instance of the service. Note that there is no race condition
+ // in getting the service since this method is called only in the
+ // service executor thread.
+ final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class);
+
+ // Check if the service is available. If it is not, no elements are
+ // updated.
+ if (commandControl == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ update.setChild(createVMContext(commandControl.getContext()), 0);
+ update.done();
+ }
+
+
+ @Override
+ protected void updateLabelInSessionThread(final ILabelUpdate update) {
+ // Get a reference to the run control service.
+ final IRunControl runControl = getServicesTracker().getService(IRunControl.class);
+ if (runControl == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // Find the PDA program context.
+ final PDAVirtualMachineDMContext programCtx =
+ findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAVirtualMachineDMContext.class);
+
+ // Call service to get current program state
+ final boolean isSuspended = runControl.isSuspended(programCtx);
+
+ // Set the program icon based on the running state of the program.
+ String imageKey = null;
+ if (isSuspended) {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+ } else {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+ }
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+ // Retrieve the last state change reason
+ getDMVMProvider().getModelData(
+ this, update, runControl, programCtx,
+ new ViewerDataRequestMonitor<IExecutionDMData>(ImmediateExecutor.getInstance(), update)
+ {
+ @Override
+ public void handleCompleted(){
+ // If the request failed, fail the udpate.
+ if (!isSuccess()) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // Compose the thread name string.
+ final StringBuilder builder = new StringBuilder();
+
+ builder.append("PDA [");
+ builder.append(programCtx.getProgram());
+ builder.append("]");
+
+ if(isSuspended) {
+ builder.append(" (Suspended");
+ } else {
+ builder.append(" (Running");
+ }
+ // Reason will be null before ContainerSuspendEvent is fired
+ if(getData().getStateChangeReason() != null) {
+ builder.append(" : ");
+ builder.append(getData().getStateChangeReason());
+ }
+ builder.append(")");
+ update.setLabel(builder.toString(), 0);
+ update.done();
+ }
+ },
+ getExecutor());
+ }
+
+ private String produceProgramElementName( String viewName , PDAVirtualMachineDMContext execCtx ) {
+ return "PDA." + execCtx.getProgram(); //$NON-NLS-1$
+ }
+
+ private final String MEMENTO_NAME = "PDAPROGRAM_MEMENTO_NAME"; //$NON-NLS-1$
+
+ public void compareElements(IElementCompareRequest[] requests) {
+
+ for ( IElementCompareRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+ String mementoName = memento.getString(MEMENTO_NAME);
+
+ if (mementoName != null) {
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof PDAVirtualMachineDMContext) {
+
+ String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc );
+ request.setEqual( elementName.equals( mementoName ) );
+ }
+ }
+ }
+ request.done();
+ }
+ }
+
+ public void encodeElements(IElementMementoRequest[] requests) {
+
+ for ( IElementMementoRequest request : requests ) {
+
+ Object element = request.getElement();
+ IMemento memento = request.getMemento();
+
+ if (element instanceof IDMVMContext) {
+
+ IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+ if ( dmc instanceof PDAVirtualMachineDMContext) {
+
+ String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc );
+ memento.putString(MEMENTO_NAME, elementName);
+ }
+ }
+ request.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/.classpath b/dsf/org.eclipse.cdt.examples.dsf.pda/.classpath
new file mode 100644
index 00000000000..8fe3727bbf5
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="pdavm/src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/.cvsignore b/dsf/org.eclipse.cdt.examples.dsf.pda/.cvsignore
new file mode 100644
index 00000000000..ba077a4031a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/.options b/dsf/org.eclipse.cdt.examples.dsf.pda/.options
new file mode 100755
index 00000000000..f796395f8e0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/.options
@@ -0,0 +1 @@
+org.eclipse.cdt.examples.dsf.pda/debug = false
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/.project b/dsf/org.eclipse.cdt.examples.dsf.pda/.project
new file mode 100644
index 00000000000..4546d07eba3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.examples.dsf.pda</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/dsf/org.eclipse.cdt.examples.dsf.pda/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.examples.dsf.pda/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..cfb0bdd17eb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Tue Jun 24 11:03:29 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.examples.dsf.pda/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..076c5b661d1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/META-INF/MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: PDA Example Device Debugging Core Plug-in
+Bundle-SymbolicName: org.eclipse.cdt.examples.dsf.pda;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.examples.dsf.pda.PDAPlugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.core.variables,
+ org.eclipse.debug.core,
+ org.eclipse.cdt.dsf,
+ org.junit4;bundle-version="4.3.1",
+ org.eclipse.cdt.core;bundle-version="5.0.0"
+Bundle-ActivationPolicy: lazy
+Export-Package: org.eclipse.cdt.examples.dsf.pda,
+ org.eclipse.cdt.examples.dsf.pda.breakpoints,
+ org.eclipse.cdt.examples.dsf.pda.launch,
+ org.eclipse.cdt.examples.dsf.pda.service,
+ org.eclipse.cdt.examples.dsf.pda.service.commands,
+ org.eclipse.cdt.examples.dsf.pda.sourcelookup
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/about.html b/dsf/org.eclipse.cdt.examples.dsf.pda/about.html
new file mode 100644
index 00000000000..c1cb2e12f40
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>May 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/build.properties b/dsf/org.eclipse.cdt.examples.dsf.pda/build.properties
new file mode 100644
index 00000000000..04af87485ac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/build.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# 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
+# Wind River Systems - adapted to use with DSF
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = plugin.xml,\
+ pdavm/,\
+ META-INF/,\
+ about.html,\
+ .,\
+ readme.html,\
+ samples/
+src.includes = about.html,\
+ src/
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/docs/protocol.html b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/docs/protocol.html
new file mode 100644
index 00000000000..1d79f31a4fc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/docs/protocol.html
@@ -0,0 +1,308 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>PDA Debugger Protocol Reference</title>
+</head>
+<body>
+
+<h2>PDA Debugger Protocol Reference</h2>
+
+<h3>clear</h3>
+Clears any breakpoint set on given line
+<pre>
+ C: clear {line}
+ R: ok
+</pre>
+
+
+<h3>data</h3>
+Retrieves data stack information
+<pre>
+ C: data {thread_id}
+ R: {value 1}|{value 2}|{value 3}|...|
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>drop</h3>
+Returns from the current frame without executing the rest of instructions.
+
+<pre>
+If VM running:
+ C: drop {thread_id}
+ R: ok
+ E: resumed {thread_id} drop
+ E: suspended {thread_id} drop
+
+If VM suspended:
+ C: drop {thread_id}
+ R: ok
+ E: vmresumed drop
+ E: vmsuspended {thread_id} drop
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>eval</h3>
+Sets what events cause the execution to stop.
+
+<pre>
+ C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
+ R: ok
+ E: resumed {thread_id} client
+ E: evalresult result
+ E: suspended {thread_id} eval
+
+Errors:
+ error: invalid thread
+ error: cannot evaluate while vm is suspended
+ error: thread running
+</pre>
+
+
+<h3>eventstop</h3>
+Sets what events cause the execution to stop.
+
+<pre>
+ C: eventstop {event_name} {0|1}
+ R: ok
+ ...
+ E: suspended event {event_name}
+</pre>
+
+
+<h3>exit</h3>
+Instructs the debugger to exit.
+
+<pre>
+ C: exit
+ R: ok
+</pre>
+
+
+<h3>popdata</h3>
+Pops the top value from the data stack
+
+<pre>
+ C: popdata {thread_id}
+ R: ok
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>pushdata</h3>
+Pushes the given value on top of the data stack.
+
+<pre>
+ C: pushdata {thread_id} {value}
+ R: ok
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>resume</h3>
+Resumes the execution of a single thread. Can be issued only if the virtual
+machine is running.
+
+<pre>
+ C: resume {thread_id}
+ R: ok
+ E: resumed {thread_id} client
+
+Errors:
+ error: invalid thread
+ error: cannot resume thread when vm is suspended
+ error: thread already running
+</pre>
+
+
+<h3>set</h3>
+Sets a breakpoint at given line
+
+<pre>
+Suspend a single thread:
+ C: set {line_number} 0
+ R: ok
+ C: resume {thread_id}
+ E: resumed {thread_id} client
+ E: suspended {thread_id} breakpoint line_number
+
+Suspend the VM:
+ C: set {line_number} 1
+ R: ok
+ C: vmresume
+ E: vmresumed client
+ E: vmsuspended {thread_id} breakpoint line_number
+</pre>
+
+
+<h3>setdata</h3>
+Sets a data value in the data stack at the given location
+
+<pre>
+ C: setdata {thread_id} {index} {value}
+ R: ok
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>setvar</h3>
+Sets a variable value
+
+<pre>
+ C: setvar {thread_id} {frame_number} {variable} {value}
+ R: ok
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>stack</h3>
+Retrieves command stack information
+
+<pre>
+ C: stack {thread_id}
+ R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>step</h3>
+Executes next instruction
+
+<pre>
+If VM running:
+ C: step {thread_id}
+ R: ok
+ E: resumed {thread_id} client
+ E: suspended {thread_id} step
+
+If VM suspended:
+ C: step {thread_id}
+ R: ok
+ E: vmresumed client
+ E: vmsuspended {thread_id} step
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>stepreturn</h3>
+Executes instructions until the current subroutine is finished
+
+<pre>
+If VM running:
+ C: stepreturn {thread_id}
+ R: ok
+ E: resumed {thread_id} client
+ E: suspended {thread_id} step
+
+If VM suspended:
+ C: stepreturn {thread_id}
+ R: ok
+ E: vmresumed client
+ E: vmsuspended {thread_id} step
+
+Errors:
+ error: invalid thread
+</pre>
+
+
+<h3>suspend</h3>
+Suspends execution of a single thread. Can be issued only if the virtual
+machine is running.
+
+<pre>
+ C: suspend {thread_id}
+ R: ok
+ E: suspended {thread_id} client
+
+Errors:
+ error: invalid thread
+ error: vm already suspended
+ error: thread already suspended
+</pre>
+
+<h3>threads</h3>
+Retrieves the list of active threads
+
+<pre>
+ C: threads
+ R: {thread id} {thread id} ...
+</pre>
+
+<h3>var</h3>
+Retrieves variable value
+
+<pre>
+ C: var {thread_id} {frame_number} {variable_name}
+ R: {variable_value}
+
+Errors:
+ error: invalid thread
+ error: variable undefined
+</pre>
+
+
+<h3>watch</h3>
+Sets a watchpoint on a given variable
+
+<pre>
+ C: watch {function}::{variable_name} {watch_operation}
+ R: ok
+ C: resume
+ R: resumed client
+ E: suspended watch {watch_operation} {function}::{variable_name}
+</pre>
+
+The <code>watch_operation<code> value can be:
+<ul>
+ <li>0 - no watch</li>
+ <li>1 - read watch</li>
+ <li>2 - write watch</li>
+ <li>3 - both, etc.</li>
+</ul>
+
+
+<h3>vmresume</h3>
+Resumes the execution of the whole virtual machine
+
+<pre>
+ C: vmresume
+ R: ok
+ E: vmresumed client
+
+Errors:
+ error: vm already running
+</pre>
+
+<h3>vmsuspend</h3>
+Suspends the execution of the whole virtual machine
+
+<pre>
+ C: vmsuspend
+ R: ok
+ E: vmsuspended client
+
+Errors:
+ error: thread already suspended
+</pre>
+</body>
+
+</html>
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/src/org/eclipse/cdt/examples/pdavm/PDAVirtualMachine.java b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/src/org/eclipse/cdt/examples/pdavm/PDAVirtualMachine.java
new file mode 100644
index 00000000000..5b40a1da7c7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/src/org/eclipse/cdt/examples/pdavm/PDAVirtualMachine.java
@@ -0,0 +1,1378 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.pdavm;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.StringWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ */
+@SuppressWarnings("serial")
+public class PDAVirtualMachine {
+
+ static class Stack extends LinkedList<Object> {
+ public Object pop() {
+ return isEmpty() ? 0 : remove(size() - 1);
+ }
+
+ public void push(Object value) {
+ add(value);
+ }
+ }
+
+ static class Register {
+ Register(String name) {
+ fName = name;
+ }
+ String fName;
+ String fGroup = "<no_group>";
+ boolean fIsWriteable = true;
+ Map<String, BitField> fBitFields = new LinkedHashMap<String, BitField>(0);
+ int fValue;
+ }
+
+ static class BitField {
+ BitField(String name) {
+ fName = name;
+ }
+ String fName;
+ int fBitOffset;
+ int fBitCount;
+ Map<String, Integer> fMnemonics = new LinkedHashMap<String, Integer>(0);
+ }
+
+ Map<String,Register> fRegisters = new LinkedHashMap<String,Register>(0);
+
+ class Args {
+ final String[] fArgs;
+
+ int next = 0;
+
+ Args(String[] args) {
+ fArgs = args;
+ }
+
+ String getNextStringArg() {
+ if (fArgs.length > next) {
+ return fArgs[next++];
+ }
+ return "";
+ }
+
+ int getNextIntArg() {
+ String arg = getNextStringArg();
+ try {
+ return Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ }
+ return 0;
+ }
+
+ boolean getNextBooleanArg() {
+ String arg = getNextStringArg();
+ try {
+ return Boolean.parseBoolean(arg);
+ } catch (NumberFormatException e) {
+ }
+ return false;
+ }
+
+ Object getNextIntOrStringArg() {
+ String arg = getNextStringArg();
+ try {
+ return Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ }
+ return arg;
+ }
+
+ PDAThread getThreadArg() {
+ int id = getNextIntArg();
+ return fThreads.get(id);
+ }
+ }
+
+ class PDAThread {
+ final int fID;
+
+ /** The push down automata data stack (the data stack). */
+ final Stack fStack = new Stack();
+
+ /**
+ * PDAThread copy of the code. It can differ from the program if
+ * performing an evaluation.
+ */
+ String[] fThreadCode;
+
+ /** PDAThread copy of the labels. */
+ Map<String, Integer> fThreadLabels;
+
+ /** The stack of stack frames (the control stack) */
+ final List<Frame> fFrames = new LinkedList<Frame>();
+
+ /** Current stack frame (not includced in fFrames) */
+ Frame fCurrentFrame;
+
+ /**
+ * The run flag is true if the thread is running. If the run flag is
+ * false, the thread exits the next time the main instruction loop runs.
+ */
+ boolean fRun = true;
+
+ String fSuspend = null;
+
+ boolean fStep = false;
+
+ boolean fStepReturn = false;
+
+ int fSavedPC;
+
+ boolean fPerformingEval = false;
+
+ PDAThread(int id, String function, int pc) {
+ fID = id;
+ fCurrentFrame = new Frame(function, pc);
+ fThreadCode = fCode;
+ fThreadLabels = fLabels;
+ }
+ }
+
+ final Map<Integer, PDAThread> fThreads = new LinkedHashMap<Integer, PDAThread>();
+
+ int fNextThreadId = 1;
+
+ boolean fStarted = true;
+ /**
+ * The code is stored as an array of strings, each line of the source file
+ * being one entry in the array.
+ */
+ final String[] fCode;
+
+ /** A mapping of labels to indicies in the code array */
+ final Map<String, Integer> fLabels;
+
+ /** Each stack frame is a mapping of variable names to values. */
+ class Frame {
+ final Map<String, Object> fLocalVariables = new LinkedHashMap<String, Object>();
+
+ /**
+ * The name of the function in this frame
+ */
+ final String fFunction;
+
+ /**
+ * The current program counter in the frame the pc points to the next
+ * instruction to be executed
+ */
+ int fPC;
+
+ Frame(String function, int pc) {
+ fFunction = function;
+ fPC = pc;
+ }
+
+ void set(String name, Object value) {
+ if (name.startsWith("$")) {
+ setRegisterValue(name, value);
+ } else {
+ fLocalVariables.put(name, value);
+ }
+ }
+
+ Object get(String name) {
+ if (name.startsWith("$")) {
+ return getRegisterValue(name);
+ } else {
+ return fLocalVariables.get(name);
+ }
+ }
+ }
+
+ void setRegisterValue(String name, Object value) {
+ Register reg = fRegisters.get(getRegisterPartOfName(name));
+ if (reg == null) return;
+ String bitFieldName = getBitFieldPartOfName(name);
+ if (bitFieldName != null) {
+ BitField bitField = reg.fBitFields.get(bitFieldName);
+ if (bitField == null) return;
+ Integer intValue = null;
+ if (value instanceof Integer) {
+ intValue = (Integer)value;
+ } else if (value instanceof String) {
+ intValue = bitField.fMnemonics.get(value);
+ }
+ if (intValue != null) {
+ int bitFieldMask = 2^(bitField.fBitCount - 1);
+ int registerMask = ~(bitFieldMask << bitField.fBitOffset);
+ int bitFieldValue = intValue & bitFieldMask;
+ reg.fValue = (reg.fValue & registerMask) | (bitFieldValue << bitField.fBitOffset);
+ }
+ } else if (value instanceof Integer) {
+ reg.fValue = ((Integer)value).intValue();
+ }
+ }
+
+ Object getRegisterValue(String name) {
+ Register reg = fRegisters.get(getRegisterPartOfName(name));
+ if (reg == null) return null;
+ String bitFieldName = getBitFieldPartOfName(name);
+ if (bitFieldName != null) {
+ BitField bitField = reg.fBitFields.get(bitFieldName);
+ if (bitField == null) return null;
+ int bitFieldMask = 2^(bitField.fBitCount - 1);
+ int registerMask = bitFieldMask << bitField.fBitOffset;
+ return (reg.fValue & registerMask) >> bitField.fBitOffset;
+ } else {
+ return reg.fValue;
+ }
+ }
+
+ /**
+ * Breakpoints are stored per each each line of code. The boolean indicates
+ * whether the whole VM should suspend or just the triggering thread.
+ */
+ final Map<Integer, Boolean> fBreakpoints = new HashMap<Integer, Boolean>();
+
+ /**
+ * The suspend flag is true if the VM should suspend running the program and
+ * just listen for debug commands.
+ */
+ String fSuspendVM;
+
+ /** Flag indicating whether the debugger is performing a step. */
+ boolean fStepVM = false;
+
+ /** Flag indicating whether the debugger is performing a step return */
+ boolean fStepReturnVM = false;
+
+ int fSteppingThread = 0;
+
+ /** Name of the pda program being debugged */
+ final String fFilename;
+
+ /** The command line argument to start a debug session. */
+ final boolean fDebug;
+
+ /** The port to listen for debug commands on */
+ final int fCommandPort;
+
+ /**
+ * Command socket for receiving debug commands and sending command responses
+ */
+ Socket fCommandSocket;
+
+ /** Command socket reader */
+ BufferedReader fCommandReceiveStream;
+
+ /** Command socket write stream. */
+ OutputStream fCommandResponseStream;
+
+ /** The port to send debug events to */
+ final int fEventPort;
+
+ /** Event socket */
+ Socket fEventSocket;
+
+ /** Event socket and write stream. */
+ OutputStream fEventStream;
+
+ /** The eventstops table holds which events cause suspends and which do not. */
+ final Map<String, Boolean> fEventStops = new HashMap<String, Boolean>();
+ {
+ fEventStops.put("unimpinstr", false);
+ fEventStops.put("nosuchlabel", false);
+ }
+
+ /**
+ * The watchpoints table holds watchpoint information.
+ * <p/>
+ * variablename_stackframedepth => N
+ * <ul>
+ * <li>N = 0 is no watch</li>
+ * <li>N = 1 is read watch</li>
+ * <li>N = 2 is write watch</li>
+ * <li>N = 3 is both, etc.</li>
+ */
+ final Map<String, Integer> fWatchpoints = new HashMap<String, Integer>();
+
+ public static void main(String[] args) {
+ String programFile = args.length >= 1 ? args[0] : null;
+ if (programFile == null) {
+ System.err.println("Error: No program specified");
+ return;
+ }
+
+ String debugFlag = args.length >= 2 ? args[1] : "";
+ boolean debug = "-debug".equals(debugFlag);
+ int commandPort = 0;
+ int eventPort = 0;
+
+ if (debug) {
+ String commandPortStr = args.length >= 3 ? args[2] : "";
+ try {
+ commandPort = Integer.parseInt(commandPortStr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: Invalid command port");
+ return;
+ }
+
+ String eventPortStr = args.length >= 4 ? args[3] : "";
+ try {
+ eventPort = Integer.parseInt(eventPortStr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: Invalid event port");
+ return;
+ }
+ }
+
+ PDAVirtualMachine pdaVM = null;
+ try {
+ pdaVM = new PDAVirtualMachine(programFile, debug, commandPort, eventPort);
+ pdaVM.startDebugger();
+ } catch (IOException e) {
+ System.err.println("Error: " + e.toString());
+ return;
+ }
+ pdaVM.run();
+ }
+
+ PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException {
+ fFilename = inputFile;
+
+ // Load all the code into memory
+ FileReader fileReader = new FileReader(inputFile);
+ StringWriter stringWriter = new StringWriter();
+ List<String> code = new LinkedList<String>();
+ int c = fileReader.read();
+ while (c != -1) {
+ if (c == '\n') {
+ code.add(stringWriter.toString().trim());
+ stringWriter = new StringWriter();
+ } else {
+ stringWriter.write(c);
+ }
+ c = fileReader.read();
+ }
+ code.add(stringWriter.toString().trim());
+ fCode = code.toArray(new String[code.size()]);
+
+ fLabels = mapLabels(fCode);
+
+ fDebug = debug;
+ fCommandPort = commandPort;
+ fEventPort = eventPort;
+ }
+
+ /**
+ * Initializes the labels map
+ */
+ Map<String, Integer> mapLabels(String[] code) {
+ Map<String, Integer> labels = new HashMap<String, Integer>();
+ for (int i = 0; i < code.length; i++) {
+ if (code[i].length() != 0 && code[i].charAt(0) == ':') {
+ labels.put(code[i].substring(1), i);
+ }
+ }
+ return labels;
+ }
+
+ void sendCommandResponse(String response) {
+ try {
+ fCommandResponseStream.write(response.getBytes());
+ fCommandResponseStream.flush();
+ } catch (IOException e) {
+ }
+ }
+
+ void sendDebugEvent(String event, boolean error) {
+ if (fDebug) {
+ try {
+ fEventStream.write(event.getBytes());
+ fEventStream.write('\n');
+ fEventStream.flush();
+ } catch (IOException e) {
+ System.err.println("Error: " + e);
+ System.exit(1);
+ }
+ } else if (error) {
+ System.err.println("Error: " + event);
+ }
+ }
+
+ void startDebugger() throws IOException {
+ if (fDebug) {
+ System.out.println("-debug " + fCommandPort + " " + fEventPort);
+ }
+
+ ServerSocket commandServerSocket = new ServerSocket(fCommandPort);
+ fCommandSocket = commandServerSocket.accept();
+ fCommandReceiveStream = new BufferedReader(new InputStreamReader(fCommandSocket.getInputStream()));
+ fCommandResponseStream = new PrintStream(fCommandSocket.getOutputStream());
+ commandServerSocket.close();
+
+ ServerSocket eventServerSocket = new ServerSocket(fEventPort);
+ fEventSocket = eventServerSocket.accept();
+ fEventStream = new PrintStream(fEventSocket.getOutputStream());
+ eventServerSocket.close();
+
+ System.out.println("debug connection accepted");
+
+ fSuspendVM = "client";
+ }
+
+ void run() {
+ int id = fNextThreadId++;
+ fThreads.put(id, new PDAThread(id, "main", 0));
+ if (fDebug) {
+ sendDebugEvent("started " + id, false);
+ }
+
+ boolean allThreadsSuspended = false;
+ while (!fThreads.isEmpty()) {
+ checkForBreakpoint();
+
+ if (fSuspendVM != null) {
+ debugUI();
+ } else {
+ yieldToDebug(allThreadsSuspended);
+ if (fSuspendVM != null) {
+ // Received a command to suspend VM, skip executing threads.
+ continue;
+ }
+ }
+
+ PDAThread[] threadsCopy = fThreads.values().toArray(new PDAThread[fThreads.size()]);
+ allThreadsSuspended = true;
+ for (PDAThread thread : threadsCopy) {
+ if (thread.fSuspend == null) {
+ allThreadsSuspended = false;
+
+ String instruction = thread.fThreadCode[thread.fCurrentFrame.fPC];
+ thread.fCurrentFrame.fPC++;
+ doOneInstruction(thread, instruction);
+ if (thread.fCurrentFrame.fPC >= thread.fThreadCode.length) {
+ // Thread reached end of code, exit from the thread.
+ thread.fRun = false;
+ } else if (thread.fStepReturn) {
+ // If this thread is in a step-return operation, check
+ // if we've returned from a call.
+ instruction = thread.fThreadCode[thread.fCurrentFrame.fPC];
+ if ("return".equals(instruction)) {
+ // Note: this will only be triggered if the current
+ // thread also has the fStepReturn flag set.
+ if (fStepReturnVM) {
+ fSuspendVM = thread.fID + " step";
+ } else {
+ thread.fSuspend = "step";
+ }
+ }
+ }
+ if (!thread.fRun) {
+ sendDebugEvent("exited " + thread.fID, false);
+ fThreads.remove(thread.fID);
+ } else if (thread.fSuspend != null) {
+ sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false);
+ thread.fStep = thread.fStepReturn = thread.fPerformingEval = false;
+ }
+ }
+ }
+
+ // Force thread context switch to avoid starving out other
+ // processes in the system.
+ Thread.yield();
+ }
+
+ sendDebugEvent("terminated", false);
+ if (fDebug) {
+ try {
+ fCommandReceiveStream.close();
+ fCommandResponseStream.close();
+ fCommandSocket.close();
+ fEventStream.close();
+ fEventSocket.close();
+ } catch (IOException e) {
+ System.out.println("Error: " + e);
+ }
+ }
+
+ }
+
+ void doOneInstruction(PDAThread thread, String instr) {
+ StringTokenizer tokenizer = new StringTokenizer(instr);
+ String op = tokenizer.nextToken();
+ List<String> tokens = new LinkedList<String>();
+ while (tokenizer.hasMoreTokens()) {
+ tokens.add(tokenizer.nextToken());
+ }
+ Args args = new Args(tokens.toArray(new String[tokens.size()]));
+
+ boolean opValid = true;
+ if (op.equals("add")) iAdd(thread, args);
+ else if (op.equals("branch_not_zero")) iBranchNotZero(thread, args);
+ else if (op.equals("call")) iCall(thread, args);
+ else if (op.equals("dec")) iDec(thread, args);
+ else if (op.equals("def")) iDef(thread, args);
+ else if (op.equals("dup")) iDup(thread, args);
+ else if (op.equals("exec")) iExec(thread, args);
+ else if (op.equals("halt")) iHalt(thread, args);
+ else if (op.equals("output")) iOutput(thread, args);
+ else if (op.equals("pop")) iPop(thread, args);
+ else if (op.equals("push")) iPush(thread, args);
+ else if (op.equals("return")) iReturn(thread, args);
+ else if (op.equals("var")) iVar(thread, args);
+ else if (op.equals("xyzzy")) iInternalEndEval(thread, args);
+ else if (op.startsWith(":")) {} // label
+ else if (op.startsWith("#")) {} // comment
+ else {
+ opValid = false;
+ }
+
+ if (!opValid) {
+ sendDebugEvent("unimplemented instruction " + op, true);
+ if (fEventStops.get("unimpinstr")) {
+ fSuspendVM = thread.fID + " event unimpinstr";
+ thread.fCurrentFrame.fPC--;
+ }
+ } else if (thread.fStep) {
+ if (fStepVM) {
+ fSuspendVM = thread.fID + " step";
+ fStepVM = false;
+ } else {
+ thread.fSuspend = "step";
+ }
+ thread.fStep = false;
+ }
+ }
+
+ void checkForBreakpoint() {
+ if (fDebug) {
+ for (PDAThread thread : fThreads.values()) {
+ int pc = thread.fCurrentFrame.fPC;
+ // Suspend for breakpoint if:
+ // - the VM is not yet set to suspend, for e.g. as a result of step end,
+ // - the thread is not yet suspended and is not performing an evaluation
+ // - the breakpoints table contains a breakpoint for the given line.
+ if (fSuspendVM == null &&
+ thread.fSuspend == null && !thread.fPerformingEval &&
+ fBreakpoints.containsKey(pc))
+ {
+ if (fBreakpoints.get(pc)) {
+ fSuspendVM = thread.fID + " breakpoint " + pc;
+ } else {
+ thread.fSuspend = "breakpoint " + pc;
+ thread.fStep = thread.fStepReturn = false;
+ sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * After each instruction, we check the debug command channel for control input. If
+ * there are commands, process them.
+ */
+ void yieldToDebug(boolean allThreadsSuspended) {
+ if (fDebug) {
+ String line = "";
+ try {
+ if (allThreadsSuspended || fCommandReceiveStream.ready()) {
+ line = fCommandReceiveStream.readLine();
+ processDebugCommand(line);
+ }
+ } catch (IOException e) {
+ System.err.println("Error: " + e);
+ System.exit(1);
+ }
+ }
+ }
+
+ /**
+ * Service the debugger commands while the VM is suspended
+ */
+ void debugUI() {
+ if (!fStarted) {
+ sendDebugEvent("vmsuspended " + fSuspendVM, false);
+ } else {
+ fStarted = false;
+ }
+
+ // Clear all stepping flags. In case the VM suspended while
+ // a step operation was being performed for the VM or some thread.
+ fStepVM = fStepReturnVM = false;
+ for (PDAThread thread : fThreads.values()) {
+ thread.fSuspend = null;
+ thread.fStep = thread.fStepReturn = thread.fPerformingEval = false;
+ }
+
+ while (fSuspendVM != null) {
+ String line = "";
+ try {
+ line = fCommandReceiveStream.readLine();
+ } catch (IOException e) {
+ System.err.println("Error: " + e);
+ System.exit(1);
+ return;
+ }
+ processDebugCommand(line);
+ }
+
+ if (fStepVM || fStepReturnVM) {
+ sendDebugEvent("vmresumed step", false);
+ } else {
+ sendDebugEvent("vmresumed client", false);
+ }
+ }
+
+ void processDebugCommand(String line) {
+ StringTokenizer tokenizer = new StringTokenizer(line.trim());
+ if (line.length() == 0) {
+ return;
+ }
+
+ String command = tokenizer.nextToken();
+ List<String> tokens = new LinkedList<String>();
+ while (tokenizer.hasMoreTokens()) {
+ tokens.add(tokenizer.nextToken());
+ }
+ Args args = new Args(tokens.toArray(new String[tokens.size()]));
+
+ if ("children".equals(command)) debugChildren(args);
+ else if ("clear".equals(command)) debugClearBreakpoint(args);
+ else if ("data".equals(command)) debugData(args);
+ else if ("drop".equals(command)) debugDropFrame(args);
+ else if ("eval".equals(command)) debugEval(args);
+ else if ("eventstop".equals(command)) debugEventStop(args);
+ else if ("exit".equals(command)) debugExit();
+ else if ("frame".equals(command)) debugFrame(args);
+ else if ("groups".equals(command)) debugGroups(args);
+ else if ("popdata".equals(command)) debugPop(args);
+ else if ("pushdata".equals(command)) debugPush(args);
+ else if ("registers".equals(command)) debugRegisters(args);
+ else if ("resume".equals(command)) debugResume(args);
+ else if ("set".equals(command)) debugSetBreakpoint(args);
+ else if ("setdata".equals(command)) debugSetData(args);
+ else if ("setvar".equals(command)) debugSetVariable(args);
+ else if ("stack".equals(command)) debugStack(args);
+ else if ("stackdepth".equals(command)) debugStackDepth(args);
+ else if ("state".equals(command)) debugState(args);
+ else if ("step".equals(command)) debugStep(args);
+ else if ("stepreturn".equals(command)) debugStepReturn(args);
+ else if ("suspend".equals(command)) debugSuspend(args);
+ else if ("threads".equals(command)) debugThreads();
+ else if ("var".equals(command)) debugVar(args);
+ else if ("vmresume".equals(command)) debugVMResume();
+ else if ("vmsuspend".equals(command)) debugVMSuspend();
+ else if ("watch".equals(command)) debugWatch(args);
+ else {
+ sendCommandResponse("error: invalid command\n");
+ }
+ }
+
+ void debugChildren(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ int sfnumber = args.getNextIntArg();
+ String var = args.getNextStringArg();
+
+ Frame frame = sfnumber >= thread.fFrames.size()
+ ? thread.fCurrentFrame : thread.fFrames.get(sfnumber);
+
+ String varDot = var + ".";
+ List<String> children = new ArrayList<String>();
+ for (String localVar : frame.fLocalVariables.keySet()) {
+ if (localVar.startsWith(varDot) && localVar.indexOf('.', varDot.length() + 1) == -1) {
+ children.add(localVar);
+ }
+ }
+
+ StringBuffer result = new StringBuffer();
+ for (String child : children) {
+ result.append(child);
+ result.append('|');
+ }
+ result.append('\n');
+
+ sendCommandResponse(result.toString());
+ }
+
+ void debugClearBreakpoint(Args args) {
+ int line = args.getNextIntArg();
+
+ fBreakpoints.remove(line);
+ sendCommandResponse("ok\n");
+ }
+
+ private static Pattern fPackPattern = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])");
+
+ void debugData(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ StringBuffer result = new StringBuffer();
+ for (Object val : thread.fStack) {
+ result.append(val);
+ result.append('|');
+ }
+ result.append('\n');
+ sendCommandResponse(result.toString());
+ }
+
+ void debugDropFrame(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ if (!thread.fFrames.isEmpty()) {
+ thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1);
+ }
+ thread.fCurrentFrame.fPC--;
+ sendCommandResponse("ok\n");
+ if (fSuspendVM != null) {
+ sendDebugEvent("vmresumed drop", false);
+ sendDebugEvent("vmsuspended " + thread.fID + " drop", false);
+ } else {
+ sendDebugEvent("resumed " + thread.fID + " drop", false);
+ sendDebugEvent("suspended " + thread.fID + " drop", false);
+ }
+ }
+
+ void debugEval(Args args) {
+ if (fSuspendVM != null) {
+ sendCommandResponse("error: cannot evaluate while vm is suspended\n");
+ return;
+ }
+
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ if (thread.fSuspend == null) {
+ sendCommandResponse("error: thread running\n");
+ return;
+ }
+
+ StringTokenizer tokenizer = new StringTokenizer(args.getNextStringArg(), "|");
+ tokenizer.countTokens();
+
+ int numEvalLines = tokenizer.countTokens();
+ thread.fThreadCode = new String[fCode.length + numEvalLines + 1];
+ System.arraycopy(fCode, 0, thread.fThreadCode, 0, fCode.length);
+ for (int i = 0; i < numEvalLines; i++) {
+ String line = tokenizer.nextToken();
+ StringBuffer lineBuf = new StringBuffer(line.length());
+ Matcher matcher = fPackPattern.matcher(line);
+ int lastMatchEnd = 0;
+ while (matcher.find()) {
+ lineBuf.append(line.substring(lastMatchEnd, matcher.start()));
+ String charCode = line.substring(matcher.start() + 1, matcher.start() + 3);
+ try {
+ lineBuf.append((char) Integer.parseInt(charCode, 16));
+ } catch (NumberFormatException e) {
+ }
+ lastMatchEnd = matcher.end();
+ }
+ if (lastMatchEnd < line.length()) {
+ lineBuf.append(line.substring(lastMatchEnd));
+ }
+ thread.fThreadCode[fCode.length + i] = lineBuf.toString();
+ }
+ thread.fThreadCode[fCode.length + numEvalLines] = "xyzzy";
+ thread.fThreadLabels = mapLabels(fCode);
+
+ thread.fSavedPC = thread.fCurrentFrame.fPC;
+ thread.fCurrentFrame.fPC = fCode.length;
+ thread.fPerformingEval = true;
+
+ thread.fSuspend = null;
+
+ sendCommandResponse("ok\n");
+
+ sendDebugEvent("resumed " + thread.fID + " eval", false);
+ }
+
+ void debugEventStop(Args args) {
+ String event = args.getNextStringArg();
+ int stop = args.getNextIntArg();
+ fEventStops.put(event, stop > 0);
+ sendCommandResponse("ok\n");
+ }
+
+ void debugExit() {
+ sendCommandResponse("ok\n");
+ sendDebugEvent("terminated", false);
+ System.exit(0);
+ }
+
+ void debugFrame(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ int sfnumber = args.getNextIntArg();
+ Frame frame = null;
+ if (sfnumber >= thread.fFrames.size()) {
+ frame = thread.fCurrentFrame;
+ } else {
+ frame = thread.fFrames.get(sfnumber);
+ }
+ sendCommandResponse(printFrame(frame) + "\n");
+ }
+
+ void debugGroups(Args args) {
+ TreeSet<String> groups = new TreeSet<String>();
+ for (Register reg : fRegisters.values()) {
+ groups.add(reg.fGroup);
+ }
+ StringBuffer response = new StringBuffer();
+ for (String group : groups) {
+ response.append(group);
+ response.append('|');
+ }
+ response.append('\n');
+ sendCommandResponse(response.toString());
+ }
+
+ void debugPop(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ thread.fStack.pop();
+ sendCommandResponse("ok\n");
+ }
+
+ void debugPush(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ Object val = args.getNextIntOrStringArg();
+ thread.fStack.push(val);
+ sendCommandResponse("ok\n");
+ }
+
+ void debugRegisters(Args args) {
+ String group = args.getNextStringArg();
+
+ StringBuffer response = new StringBuffer();
+ for (Register reg : fRegisters.values()) {
+ if (group.equals(reg.fGroup)) {
+ response.append(reg.fName);
+ response.append(' ');
+ response.append(reg.fIsWriteable);
+ for (BitField bitField : reg.fBitFields.values()) {
+ response.append('|');
+ response.append(bitField.fName);
+ response.append(' ');
+ response.append(bitField.fBitOffset);
+ response.append(' ');
+ response.append(bitField.fBitCount);
+ response.append(' ');
+ for (Map.Entry<String, Integer> mnemonicEntry : bitField.fMnemonics.entrySet()) {
+ response.append(mnemonicEntry.getKey());
+ response.append(' ');
+ response.append(mnemonicEntry.getValue());
+ response.append(' ');
+ }
+ }
+
+ response.append('#');
+ }
+ }
+ response.append('\n');
+ sendCommandResponse(response.toString());
+ }
+
+ void debugResume(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+ if (fSuspendVM != null) {
+ sendCommandResponse("error: cannot resume thread when vm is suspended\n");
+ return;
+ }
+ if (thread.fSuspend == null) {
+ sendCommandResponse("error: thread already running\n");
+ return;
+ }
+
+ thread.fSuspend = null;
+ sendDebugEvent("resumed " + thread.fID + " client", false);
+
+ sendCommandResponse("ok\n");
+ }
+
+ void debugSetBreakpoint(Args args) {
+ int line = args.getNextIntArg();
+ int stopVM = args.getNextIntArg();
+
+ fBreakpoints.put(line, stopVM != 0);
+ sendCommandResponse("ok\n");
+ }
+
+ void debugSetData(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ int offset = args.getNextIntArg();
+ Object val = args.getNextIntOrStringArg();
+
+ if (offset < thread.fStack.size()) {
+ thread.fStack.set(offset, val);
+ } else {
+ thread.fStack.add(0, val);
+ }
+ sendCommandResponse("ok\n");
+ }
+
+ void debugSetVariable(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ int sfnumber = args.getNextIntArg();
+ String var = args.getNextStringArg();
+ Object val = args.getNextIntOrStringArg();
+
+ if (sfnumber >= thread.fFrames.size()) {
+ thread.fCurrentFrame.set(var, val);
+ } else {
+ thread.fFrames.get(sfnumber).set(var, val);
+ }
+ sendCommandResponse("ok\n");
+ }
+
+ void debugStack(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ StringBuffer result = new StringBuffer();
+ for (Frame frame : thread.fFrames) {
+ result.append(printFrame(frame));
+ result.append('#');
+ }
+ result.append(printFrame(thread.fCurrentFrame));
+ result.append('\n');
+ sendCommandResponse(result.toString());
+ }
+
+ void debugStackDepth(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+ sendCommandResponse( Integer.toString(thread.fFrames.size() + 1) + "\n" );
+ }
+
+
+ /**
+ * The stack frame output is: frame # frame # frame ... where each frame is:
+ * filename | line number | function name | var | var | var | var ...
+ */
+ private String printFrame(Frame frame) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(fFilename);
+ buf.append('|');
+ buf.append(frame.fPC);
+ buf.append('|');
+ buf.append(frame.fFunction);
+ for (String var : frame.fLocalVariables.keySet()) {
+ if (var.indexOf('.') == -1) {
+ buf.append('|');
+ buf.append(var);
+ }
+ }
+ return buf.toString();
+ }
+
+ void debugState(Args args) {
+ PDAThread thread = args.getThreadArg();
+ String response = null;
+ if (thread == null) {
+ response = fSuspendVM == null ? "running" : fSuspendVM;
+ } else if (fSuspendVM != null) {
+ response = "vm";
+ } else {
+ response = thread.fSuspend == null ? "running" : thread.fSuspend;
+ }
+ sendCommandResponse(response + "\n");
+ }
+
+ void debugStep(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ // Set suspend to null to allow the debug loop to exit back to the
+ // instruction loop and thus run an instruction. However, we want to
+ // come back to the debug loop right away, so the step flag is set to
+ // true which will cause the suspend flag to get set to true when we
+ // get to the next instruction.
+ if (fSuspendVM != null) {
+ // All threads are suspended, so suspend all threads again when
+ // step completes.
+ fSuspendVM = null;
+ fStepVM = true;
+ // Also mark the thread that initiated the step to mark it as
+ // the triggering thread when suspending.
+ thread.fStep = true;
+ } else {
+ if (thread.fSuspend == null) {
+ sendCommandResponse("error: thread already running\n");
+ return;
+ }
+ thread.fSuspend = null;
+ thread.fStep = true;
+ sendDebugEvent("resumed " + thread.fID + " step", false);
+ }
+ sendCommandResponse("ok\n");
+ }
+
+ void debugStepReturn(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ if (fSuspendVM != null) {
+ fSuspendVM = null;
+ fStepReturnVM = true;
+ thread.fStepReturn = true;
+ } else {
+ if (thread.fSuspend == null) {
+ sendCommandResponse("error: thread running\n");
+ return;
+ }
+ thread.fSuspend = null;
+ thread.fStepReturn = true;
+ sendDebugEvent("resumed " + thread.fID + " step", false);
+ }
+ sendCommandResponse("ok\n");
+ }
+
+ void debugSuspend(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+ if (fSuspendVM != null) {
+ sendCommandResponse("error: vm already suspended\n");
+ return;
+ }
+ if (thread.fSuspend != null) {
+ sendCommandResponse("error: thread already suspended\n");
+ return;
+ }
+
+ thread.fSuspend = "client";
+ sendDebugEvent("suspended " + thread.fID + " client", false);
+ sendCommandResponse("ok\n");
+ }
+
+ void debugThreads() {
+ StringBuffer response = new StringBuffer();
+ for (int threadId : fThreads.keySet()) {
+ response.append(threadId);
+ response.append(' ');
+ }
+ sendCommandResponse(response.toString().trim() + "\n");
+ }
+
+ void debugVar(Args args) {
+ PDAThread thread = args.getThreadArg();
+ if (thread == null) {
+ sendCommandResponse("error: invalid thread\n");
+ return;
+ }
+
+ int sfnumber = args.getNextIntArg();
+ String var = args.getNextStringArg();
+
+ Frame frame = sfnumber >= thread.fFrames.size()
+ ? thread.fCurrentFrame : thread.fFrames.get(sfnumber);
+
+ Object val = frame.get(var);
+ if (val == null) {
+ sendCommandResponse("error: variable undefined\n");
+ } else {
+ sendCommandResponse(val.toString() + "\n");
+ }
+ }
+
+ void debugVMResume() {
+ if (fSuspendVM == null) {
+ sendCommandResponse("error: vm already running\n");
+ return;
+ }
+
+ fSuspendVM = null;
+ sendCommandResponse("ok\n");
+ }
+
+ void debugVMSuspend() {
+ if (fSuspendVM != null) {
+ sendCommandResponse("error: vm already suspended\n");
+ return;
+ }
+
+ fSuspendVM = "client";
+ sendCommandResponse("ok\n");
+ }
+
+ void debugWatch(Args args) {
+ String funcAndVar = args.getNextStringArg();
+ int flags = args.getNextIntArg();
+ fWatchpoints.put(funcAndVar, flags);
+ sendCommandResponse("ok\n");
+ }
+
+ void iAdd(PDAThread thread, Args args) {
+ Object val1 = thread.fStack.pop();
+ Object val2 = thread.fStack.pop();
+ if (val1 instanceof Integer && val2 instanceof Integer) {
+ int intVal1 = ((Integer) val1).intValue();
+ int intVal2 = ((Integer) val2).intValue();
+ thread.fStack.push(intVal1 + intVal2);
+ } else {
+ thread.fStack.push(-1);
+ }
+ }
+
+ void iBranchNotZero(PDAThread thread, Args args) {
+ Object val = thread.fStack.pop();
+ if (val instanceof Integer && ((Integer) val).intValue() != 0) {
+ String label = args.getNextStringArg();
+ if (thread.fThreadLabels.containsKey(label)) {
+ thread.fCurrentFrame.fPC = thread.fThreadLabels.get(label);
+ } else {
+ sendDebugEvent("no such label " + label, true);
+ if (fEventStops.get("nosuchlabel")) {
+ fSuspendVM = thread.fID + " event nosuchlabel";
+ thread.fStack.push(val);
+ thread.fCurrentFrame.fPC--;
+ }
+ }
+ }
+ }
+
+ void iCall(PDAThread thread, Args args) {
+ String label = args.getNextStringArg();
+ if (thread.fThreadLabels.containsKey(label)) {
+ thread.fFrames.add(thread.fCurrentFrame);
+ thread.fCurrentFrame = new Frame(label, thread.fThreadLabels.get(label));
+ } else {
+ sendDebugEvent("no such label " + label, true);
+ if (fEventStops.get("nosuchlabel")) {
+ fSuspendVM = thread.fID + " event nosuchlabel";
+ thread.fCurrentFrame.fPC--;
+ }
+ }
+ }
+
+ void iDec(PDAThread thread, Args args) {
+ Object val = thread.fStack.pop();
+ if (val instanceof Integer) {
+ val = new Integer(((Integer) val).intValue() - 1);
+ }
+ thread.fStack.push(val);
+ }
+
+ void iDef(PDAThread thread, Args args) {
+ String type = args.getNextStringArg();
+
+ String name = args.getNextStringArg();
+ String regName = getRegisterPartOfName(name);
+ String bitFieldName = getBitFieldPartOfName(name);
+
+ if ("register".equals(type)) {
+ Register reg = new Register(regName);
+ reg.fGroup = args.getNextStringArg();
+ fRegisters.put(regName, reg);
+ reg.fIsWriteable = args.getNextBooleanArg();
+ } else if ("bitfield".equals(type)) {
+ Register reg = fRegisters.get(regName);
+ if (reg == null) return;
+ BitField bitField = new BitField(bitFieldName);
+ bitField.fBitOffset = args.getNextIntArg();
+ bitField.fBitCount = args.getNextIntArg();
+ reg.fBitFields.put(bitFieldName, bitField);
+ } else if ("mnemonic".equals(type)) {
+ Register reg = fRegisters.get(regName);
+ if (reg == null) return;
+ BitField bitField = reg.fBitFields.get(bitFieldName);
+ if (bitField == null) return;
+ bitField.fMnemonics.put(args.getNextStringArg(), args.getNextIntArg());
+ }
+ sendDebugEvent("registers", false);
+ }
+
+ private String getRegisterPartOfName(String name) {
+ if (name.startsWith("$")) {
+ int end = name.indexOf('.');
+ end = end != -1 ? end : name.length();
+ return name.substring(1, end);
+ }
+ return null;
+ }
+
+ private String getBitFieldPartOfName(String name) {
+ int start = name.indexOf('.');
+ if (name.startsWith("$") && start != -1) {
+ return name.substring(start + 1, name.length());
+ }
+ return null;
+ }
+
+ void iDup(PDAThread thread, Args args) {
+ Object val = thread.fStack.pop();
+ thread.fStack.push(val);
+ thread.fStack.push(val);
+ }
+
+ void iExec(PDAThread thread, Args args) {
+ String label = args.getNextStringArg();
+ if (fLabels.containsKey(label)) {
+ int id = fNextThreadId++;
+ fThreads.put(id, new PDAThread(id, label, fLabels.get(label)));
+ sendDebugEvent("started " + id, false);
+ } else {
+ sendDebugEvent("no such label " + label, true);
+ if (fEventStops.get("nosuchlabel")) {
+ thread.fSuspend = "event nosuchlabel";
+ thread.fCurrentFrame.fPC--;
+ }
+ }
+ }
+
+ void iHalt(PDAThread thread, Args args) {
+ thread.fRun = false;
+ }
+
+ void iOutput(PDAThread thread, Args args) {
+ System.out.println(thread.fStack.pop());
+ }
+
+ void iPop(PDAThread thread, Args args) {
+ String arg = args.getNextStringArg();
+ if (arg.startsWith("$")) {
+ String var = arg.substring(1);
+ thread.fCurrentFrame.set(var, thread.fStack.pop());
+ String key = thread.fCurrentFrame.fFunction + "::" + var;
+ if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 2) != 0) {
+ fSuspendVM = thread.fID + " watch write " + key;
+ }
+ } else {
+ thread.fStack.pop();
+ }
+ }
+
+ void iPush(PDAThread thread, Args args) {
+ String arg = args.getNextStringArg();
+ while (arg.length() != 0) {
+ if (arg.startsWith("$")) {
+ String var = arg.substring(1);
+ Object val = thread.fCurrentFrame.get(var);
+ if (val == null) val = "<undefined>";
+ thread.fStack.push(val);
+ String key = thread.fCurrentFrame.fFunction + "::" + var;
+ if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 1) != 0) {
+ fSuspendVM = thread.fID + " watch read " + key;
+ }
+ } else {
+ Object val = arg;
+ try {
+ val = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ }
+ thread.fStack.push(val);
+ }
+
+ arg = args.getNextStringArg();
+ }
+ }
+
+ void iReturn(PDAThread thread, Args args) {
+ if (!thread.fFrames.isEmpty()) {
+ thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1);
+ } else {
+ // Execution returned from the top frame, which means this thread
+ // should exit.
+ thread.fRun = false;
+ }
+ }
+
+ void iVar(PDAThread thread, Args args) {
+ String var = args.getNextStringArg();
+ thread.fCurrentFrame.set(var, 0);
+ }
+
+ void iInternalEndEval(PDAThread thread, Args args) {
+ Object result = thread.fStack.pop();
+ thread.fThreadCode = fCode;
+ thread.fThreadLabels = fLabels;
+ thread.fCurrentFrame.fPC = thread.fSavedPC;
+ sendDebugEvent("evalresult " + result, false);
+ thread.fSuspend = "eval";
+ thread.fPerformingEval = false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest10.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest10.pda
new file mode 100644
index 00000000000..837277f5ff3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest10.pda
@@ -0,0 +1,38 @@
+def register $reg1 group1 true
+def register $reg2 group1 false
+def register $reg3 group2 true
+def bitfield $reg1.field1 0 2
+def bitfield $reg1.field2 2 2
+def mnemonic $reg1.field2 zero 0
+def mnemonic $reg1.field2 one 1
+def mnemonic $reg1.field2 two 2
+def mnemonic $reg1.field2 three 3
+push 1
+pop $$reg1
+push $$reg1
+output
+push 2
+pop $$reg1.field1
+push $$reg1.field1
+output
+push 4
+pop $$reg1.field1
+push $$reg1.field1
+output
+push 1
+pop $$reg1.field2
+push $$reg1
+output
+push zero
+pop $$reg1.field2
+push $$reg1.field2
+output
+push $$reg1
+output
+push 2
+pop $$reg1.field2
+push $$reg1.field2
+output
+push $$reg1
+output
+halt \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest2.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest2.pda
new file mode 100644
index 00000000000..95a35f04ffb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest2.pda
@@ -0,0 +1,48 @@
+push 6
+push 7
+push 8
+push 9
+push 10
+call sub1
+output
+call sub3
+call sub5
+push 3
+halt
+:sub2
+push 27
+return
+:sub1
+var m
+var n
+call sub2
+pop $n
+pop $m
+push $n
+push $m
+return
+# zero-based line 23
+:sub3
+push 1
+call sub4
+push 2
+call sub4
+push 3
+return
+:sub4
+push 4
+return
+# zero-based line 34
+:sub5
+var a
+var b
+var c
+pop $c
+pop $b
+call sub6
+push $a
+return
+:sub6
+var b
+pop $b
+return
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest3.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest3.pda
new file mode 100644
index 00000000000..5aecdc5e6e0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest3.pda
@@ -0,0 +1,13 @@
+push 1
+push 2
+push 3
+foobar swish
+push 4
+add
+add
+call zippy
+add
+output
+push 1
+branch_not_zero swishy
+halt
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest6.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest6.pda
new file mode 100644
index 00000000000..d90a960cf38
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest6.pda
@@ -0,0 +1,31 @@
+var a
+var b
+push 1
+pop $a
+push 2
+pop $b
+push 3
+push 4
+#
+call inner
+#
+push $a
+push 2
+add
+pop $b
+output
+#
+halt
+#
+:inner
+var a
+var c
+pop $a
+pop $c
+push $a
+push $a
+add
+return
+:other
+push 15
+return \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest8.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest8.pda
new file mode 100644
index 00000000000..7729409c279
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest8.pda
@@ -0,0 +1,14 @@
+var a
+call inner
+push 1
+output
+halt
+:inner
+var b
+call inner2
+push 2
+return
+:inner2
+var c
+push 3
+return
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest9.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest9.pda
new file mode 100644
index 00000000000..336a251d9ab
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest9.pda
@@ -0,0 +1,23 @@
+push 5
+:thread_create
+exec foo
+dec
+dup
+branch_not_zero thread_create
+push finished
+output
+halt
+:foo
+push thread_created
+output
+call inner
+halt
+:inner
+var b
+call inner2
+push 2
+return
+:inner2
+var c
+push 3
+return
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest_children.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest_children.pda
new file mode 100644
index 00000000000..b0bbd163d7d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/pdavm/tests/vmtest_children.pda
@@ -0,0 +1,8 @@
+var a
+var a.b
+var a.c
+push 1
+pop $a.b
+push $a.b
+output
+halt
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/plugin.xml b/dsf/org.eclipse.cdt.examples.dsf.pda/plugin.xml
new file mode 100644
index 00000000000..71a16a26b32
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/plugin.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.0"?>
+<plugin>
+ <extension
+ point="org.eclipse.core.variables.valueVariables">
+ <variable
+ description="Path to Perl executable in the local file system"
+ name="dsfPerlExecutable"
+ initialValue="/usr/bin/perl"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.launchConfigurationTypes">
+ <launchConfigurationType
+ sourceLocatorId="org.eclipse.cdt.examples.dsf.pda.sourceLocator"
+ delegate="org.eclipse.cdt.examples.dsf.pda.launch.PDALaunchDelegate"
+ sourcePathComputerId="org.eclipse.cdt.examples.pda.dsf.sourcePathComputer"
+ name="DSF PDA Application"
+ id="org.eclipse.cdt.examples.dsf.pda.launchType"
+ modes="run, debug"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.sourceLocators">
+ <sourceLocator
+ class="org.eclipse.cdt.examples.dsf.pda.sourcelookup.PDASourceLookupDirector"
+ name="DSF PDA Source Locator"
+ id="org.eclipse.cdt.examples.dsf.pda.sourceLocator"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.sourcePathComputers">
+ <sourcePathComputer
+ class="org.eclipse.cdt.examples.dsf.pda.sourcelookup.PDASourcePathComputerDelegate"
+ id="org.eclipse.cdt.examples.dsf.pda.sourcePathComputer"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.breakpoints">
+ <breakpoint
+ class="org.eclipse.cdt.examples.dsf.pda.breakpoints.PDALineBreakpoint"
+ name="DSF PDA Line Breakpoints"
+ markerType="org.eclipse.cdt.examples.dsf.pda.markerType.lineBreakpoint"
+ id="org.eclipse.cdt.examples.dsf.pda.lineBreakpoint"/>
+ <breakpoint
+ class="org.eclipse.cdt.examples.dsf.pda.breakpoints.PDAWatchpoint"
+ name="DSF PDA Watchpoints"
+ markerType="org.eclipse.cdt.examples.dsf.pda.markerType.watchpoint"
+ id="org.eclipse.cdt.examples.dsf.pda.watchpoint"/>
+ </extension>
+ <extension
+ id="markerType.lineBreakpoint"
+ name="PDA Line Breakpoint Marker"
+ point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.debug.core.lineBreakpointMarker"/>
+ <persistent value="true"/>
+ </extension>
+ <extension
+ id="org.eclipse.cdt.examples.dsf.pda.markerType.watchpoint"
+ name="DD PDA Watchpoint Marker"
+ point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.cdt.examples.dsf.pda.markerType.lineBreakpoint"/>
+ <persistent value="true"/>
+ </extension>
+
+
+ <extension
+ point="org.eclipse.debug.core.logicalStructureTypes">
+ <logicalStructureType
+ class="org.eclipse.debug.examples.core.pda.model.WordStructureDelegate"
+ description="Words"
+ id="pda.wordStructure"
+ modelIdentifier="org.eclipse.cdt.examples.dsf.pda.debugModel"/>
+ </extension>
+</plugin>
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/readme.html b/dsf/org.eclipse.cdt.examples.dsf.pda/readme.html
new file mode 100644
index 00000000000..c8858def16d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/readme.html
@@ -0,0 +1,11 @@
+<h1>Debug Examples ReadMe Notes</h1>
+<h2>PDA Debugger Example</h2>
+<p>In order to actually run the PDA debugger example, you will need a Perl interpreter.
+ Linux&reg;&#8482; comes with Perl. For Microsoft&reg; Windows&reg;, we use either
+ ActivePerl (<a href="http://www.activeperl.com/">http://www.activeperl.com/</a>) or Indigo Perl
+ (<a href="http://www.indigostar.com/">http://www.indigostar.com/</a>). You also
+ have to set the string substitution variable named &#8220;dsfPerlExecutable&#8221;
+ to the complete path to your Perl interpreter. (For example, ours was C:\perl\bin\perl.exe)
+ To set a string substitution variable, use the Windows &gt; Preferences &gt;
+ Run/Debug &gt; String Substitution preferences page.<br>
+</p>
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/counter.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/counter.pda
new file mode 100644
index 00000000000..9b2b731006b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/counter.pda
@@ -0,0 +1,11 @@
+push 0
+:main
+var n
+pop $n
+push $n
+push 1
+add
+dup
+push $n
+output
+branch_not_zero main \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/drop.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/drop.pda
new file mode 100644
index 00000000000..84f60fee035
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/drop.pda
@@ -0,0 +1,12 @@
+call one
+:one
+call two
+:two
+call three
+:three
+call four
+:four
+push DONE
+output
+
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/example.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/example.pda
new file mode 100644
index 00000000000..a95886358c2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/example.pda
@@ -0,0 +1,35 @@
+push "hello"
+output
+call foobar
+push 3
+:label
+dup
+push 4
+push 5
+add
+add
+output
+dec
+dup
+branch_not_zero label
+call foobar
+push "end"
+output
+halt
+:foobar
+var a
+var b
+call barfoo
+push "first"
+push "second"
+pop $a
+pop $b
+push $a
+push $b
+output
+output
+return
+:barfoo
+push "barfoo"
+output
+return
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/fibonacci.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/fibonacci.pda
new file mode 100644
index 00000000000..e39595a9811
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/fibonacci.pda
@@ -0,0 +1,32 @@
+push 6
+call fibonacci
+output
+halt
+#
+# f(n) = f(n-1) + f(n-2)
+# f(0) = 1
+# f(1) = 1
+#
+:fibonacci
+var n
+pop $n
+push $n
+branch_not_zero gt0
+push 1
+return
+:gt0
+push $n
+dec
+branch_not_zero gt1
+push 1
+return
+:gt1
+push $n
+dec
+call fibonacci
+push $n
+dec
+dec
+call fibonacci
+add
+return
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/registers.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/registers.pda
new file mode 100644
index 00000000000..97fd8d4094d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/registers.pda
@@ -0,0 +1,72 @@
+def register $pc General true
+def register $sp General true
+def register $status General true
+def bitfield $status.BITS_00_07 0 8
+def bitfield $status.BITS_08_15 8 8
+def bitfield $status.BITS_16_23 16 8
+def bitfield $status.BITS_24_31 24 8
+def mnemonic $status.BITS_24_31 three 3
+def mnemonic $status.BITS_24_31 twelve 12
+def mnemonic $status.BITS_24_31 fourty_eight 48
+def mnemonic $status.BITS_24_31 one_nighty_two 192
+def register $stackdepth General true
+def register $stack[0] General true
+def register $stack[1] General true
+def register $stack[2] General true
+def register $stack[3] General true
+def register $stack[4] General true
+push 103
+pop $$pc
+push 306
+push 2
+pop $$sp
+push 400
+pop $$status
+push 5
+pop $$stackdepth
+push 12
+pop $$stack[0]
+push 45
+pop $$stack[1]
+push 146
+pop $$stack[2]
+push 215
+pop $$stack[3]
+push 251
+pop $$stack[4]
+push 306
+pop $$stack[5]
+def register $total-instructions Analysis false
+def register $add-instructions Analysis false
+def register $call-instructions Analysis false
+def register $dec-instructions Analysis false
+def register $dup-instructions Analysis false
+def register $halt-instructions Analysis false
+def register $output-instructions Analysis false
+def register $pop-instructions Analysis false
+def register $push-instructions Analysis false
+def register $return-instructions Analysis false
+def register $var-instructions Analysis false
+push 1046
+pop $$total-instructions
+push 12
+pop $$add-instructions
+push 24
+pop $$call-instructions
+push 36
+pop $$dec-instructions
+push 50
+pop $$dup-instructions
+push 62
+pop $$halt-instructions
+push 74
+pop $$output-instructions
+push 106
+pop $$pop-instructions
+push 120
+pop $$push-instructions
+push 132
+pop $$return-instructions
+push 144
+pop $$var-instructions
+halt \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/stack.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/stack.pda
new file mode 100644
index 00000000000..c7fa1628b9c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/stack.pda
@@ -0,0 +1,21 @@
+push 5
+:thread_create
+exec stack
+dec
+dup
+branch_not_zero thread_create
+push finished
+output
+halt
+:stack
+push 100
+:inner
+dup
+output
+dup
+branch_not_zero descend
+return
+:descend
+dec
+call inner
+return \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/samples/structures.pda b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/structures.pda
new file mode 100644
index 00000000000..b6f7cbf62ab
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/samples/structures.pda
@@ -0,0 +1,23 @@
+push one two three
+push 1 2 3
+push I II III
+var x
+var x.a
+var x.b
+var y
+var y.c
+var y.d
+var y.d.1
+var y.d.2
+var y.d.3
+pop $x
+pop $x.a
+pop $x.b
+pop $y
+pop $y.c
+pop $y.d
+pop $y.d.1
+pop $y.d.2
+pop $y.d.3
+push Done
+output \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/PDAPlugin.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/PDAPlugin.java
new file mode 100644
index 00000000000..39c74da633e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/PDAPlugin.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.examples.dsf.pda.launch.PDALaunch;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The main plugin class to be used in the desktop.
+ */
+public class PDAPlugin extends Plugin {
+
+ public static String PLUGIN_ID = "org.eclipse.cdt.examples.dsf.pda";
+
+ // Debugging flag
+ public static boolean DEBUG = false;
+
+ //The shared instance.
+ private static PDAPlugin plugin;
+
+ //Resource bundle.
+ private ResourceBundle resourceBundle;
+
+ // Bundle context used in registering and retrieving DSF (OSGi) services.
+ private static BundleContext fContext;
+
+ /**
+ * Unique identifier for the PDA debug model (value
+ * <code>pda.debugModel</code>).
+ */
+ public static final String ID_PDA_DEBUG_MODEL = "org.eclipse.cdt.examples.dsf.pda.debugModel";
+
+ /**
+ * Name of the string substitution variable that resolves to the
+ * location of a local Perl executable (value <code>perlExecutable</code>).
+ */
+ public static final String VARIALBE_PERL_EXECUTABLE = "dsfPerlExecutable";
+
+ /**
+ * Launch configuration attribute key. Value is a path to a perl
+ * program. The path is a string representing a full path
+ * to a perl program in the workspace.
+ */
+ public static final String ATTR_PDA_PROGRAM = ID_PDA_DEBUG_MODEL + ".ATTR_PDA_PROGRAM";
+
+ /**
+ * Identifier for the PDA launch configuration type
+ * (value <code>pda.launchType</code>)
+ */
+ public static final String ID_PDA_LAUNCH_CONFIGURATION_TYPE = "org.eclipse.cdt.examples.dsf.pda.launchType";
+
+ /**
+ * The constructor.
+ */
+ public PDAPlugin() {
+ super();
+ plugin = this;
+ }
+
+ /**
+ * This method is called upon plug-in activation
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fContext = context;
+ DEBUG = "true".equals(Platform.getDebugOption(PLUGIN_ID + "/debug")); //$NON-NLS-1$//$NON-NLS-2$
+ super.start(context);
+ }
+
+ /**
+ * This method is called when the plug-in is stopped
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ shutdownActiveLaunches();
+ super.stop(context);
+ plugin = null;
+ resourceBundle = null;
+ fContext = context;
+ }
+
+ /**
+ * Returns the shared instance.
+ */
+ public static PDAPlugin getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the string from the plugin's resource bundle,
+ * or 'key' if not found.
+ */
+ public static String getResourceString(String key) {
+ ResourceBundle bundle = PDAPlugin.getDefault().getResourceBundle();
+ try {
+ return (bundle != null) ? bundle.getString(key) : key;
+ } catch (MissingResourceException e) {
+ return key;
+ }
+ }
+
+ /**
+ * Returns the plugin's resource bundle,
+ */
+ public ResourceBundle getResourceBundle() {
+ try {
+ if (resourceBundle == null)
+ resourceBundle = ResourceBundle.getBundle("org.eclipse.debug.examples.core.pda.DebugCorePluginResources");
+ } catch (MissingResourceException x) {
+ resourceBundle = null;
+ }
+ return resourceBundle;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fContext;
+ }
+
+ /**
+ * Return a <code>java.io.File</code> object that corresponds to the specified
+ * <code>IPath</code> in the plugin directory, or <code>null</code> if none.
+ */
+ public static File getFileInPlugin(IPath path) {
+ try {
+ URL installURL =
+ new URL(getDefault().getDescriptor().getInstallURL(), path.toString());
+ URL localURL = Platform.asLocalURL(installURL);
+ return new File(localURL.getFile());
+ } catch (IOException ioe) {
+ return null;
+ }
+ }
+
+ /**
+ * Shuts down any active launches. We must shutdown any active sessions
+ * and services associated with this plugin before this plugin is stopped.
+ * Any attempts to use the plugins {@link BundleContext} after the plugin
+ * is shut down will result in exceptions.
+ */
+ private void shutdownActiveLaunches() {
+ for (ILaunch launch : DebugPlugin.getDefault().getLaunchManager().getLaunches()) {
+ if (launch instanceof PDALaunch && !((PDALaunch)launch).isShutDown()) {
+ final PDALaunch pdaLaunch = (PDALaunch)launch;
+
+ Query<Object> launchShutdownQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ pdaLaunch.shutdownServices(rm);
+ }
+ };
+
+ try {
+ pdaLaunch.getSession().getExecutor().execute(launchShutdownQuery);
+ } catch (RejectedExecutionException e) {
+ // We can get this exception if the session is shutdown concurrently
+ // to this method running.
+ break;
+ }
+
+ // The Query.get() method is a synchronous call which blocks until the
+ // query completes.
+ try {
+ launchShutdownQuery.get();
+ } catch (InterruptedException e) {
+ getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, "InterruptedException while shutting down PDA debugger launch " + pdaLaunch, e.getCause()));
+ } catch (ExecutionException e) {
+ getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, "Exception while shutting down PDA debugger launch " + pdaLaunch, e.getCause()));
+ }
+ }
+ }
+ }
+
+
+ public static void failRequest(RequestMonitor rm, int code, String message) {
+ rm.setStatus(new Status(IStatus.ERROR, PLUGIN_ID, code, message, null));
+ rm.done();
+ }
+
+ public static void debug(String debugString) {
+ if (DEBUG) {
+ System.out.println(debugString);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDALineBreakpoint.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDALineBreakpoint.java
new file mode 100644
index 00000000000..8b75267be10
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDALineBreakpoint.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.breakpoints;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.LineBreakpoint;
+
+
+/**
+ * PDA line breakpoint
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.
+ * </p>
+ */
+public class PDALineBreakpoint extends LineBreakpoint {
+
+ /**
+ * Default constructor is required for the breakpoint manager
+ * to re-create persisted breakpoints. After instantiating a breakpoint,
+ * the <code>setMarker(...)</code> method is called to restore
+ * this breakpoint's attributes.
+ */
+ public PDALineBreakpoint() {
+ }
+
+ /**
+ * Constructs a line breakpoint on the given resource at the given
+ * line number. The line number is 1-based (i.e. the first line of a
+ * file is line number 1). The PDA VM uses 0-based line numbers,
+ * so this line number translation is done at breakpoint install time.
+ *
+ * @param resource file on which to set the breakpoint
+ * @param lineNumber 1-based line number of the breakpoint
+ * @throws CoreException if unable to create the breakpoint
+ */
+ public PDALineBreakpoint(final IResource resource, final int lineNumber) throws CoreException {
+ IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarker marker = resource.createMarker("org.eclipse.cdt.examples.dsf.pda.markerType.lineBreakpoint");
+ setMarker(marker);
+ marker.setAttribute(IBreakpoint.ENABLED, Boolean.TRUE);
+ marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
+ marker.setAttribute(IBreakpoint.ID, getModelIdentifier());
+ marker.setAttribute(IMarker.MESSAGE, "Line Breakpoint: " + resource.getName() + " [line: " + lineNumber + "]");
+ }
+ };
+ run(getMarkerRule(resource), runnable);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IBreakpoint#getModelIdentifier()
+ */
+ public String getModelIdentifier() {
+ return PDAPlugin.ID_PDA_DEBUG_MODEL;
+ }
+
+ /**
+ * Returns whether this breakpoint is a run-to-line breakpoint
+ *
+ * @return whether this breakpoint is a run-to-line breakpoint
+ */
+ public boolean isRunToLineBreakpoint() {
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDAWatchpoint.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDAWatchpoint.java
new file mode 100644
index 00000000000..a49b96ae37a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/breakpoints/PDAWatchpoint.java
@@ -0,0 +1,173 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.breakpoints;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.eclipse.debug.core.model.IWatchpoint;
+
+
+/**
+ * A watchpoint.
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.
+ * </p>
+ */
+public class PDAWatchpoint extends PDALineBreakpoint implements IWatchpoint {
+
+ // 'read' or 'write' depending on what caused the last suspend for this watchpoint
+ private String fLastSuspendType;
+
+ // marker attributes
+ public static final String ACCESS = "ACCESS";
+ public static final String MODIFICATION = "MODIFICATION";
+ public static final String FUNCTION_NAME = "FUNCTION_NAME";
+ public static final String VAR_NAME = "VAR_NAME";
+
+ /**
+ * Default constructor is required for the breakpoint manager
+ * to re-create persisted breakpoints. After instantiating a breakpoint,
+ * the <code>setMarker(...)</code> method is called to restore
+ * this breakpoint's attributes.
+ */
+ public PDAWatchpoint() {
+ }
+ /**
+ * Constructs a line breakpoint on the given resource at the given
+ * line number. The line number is 1-based (i.e. the first line of a
+ * file is line number 1). The PDA VM uses 0-based line numbers,
+ * so this line number translation is done at breakpoint install time.
+ *
+ * @param resource file on which to set the breakpoint
+ * @param lineNumber 1-based line number of the breakpoint
+ * @param functionName function name the variable is defined in
+ * @param varName variable name that watchpoint is set on
+ * @param access whether this is an access watchpoint
+ * @param modification whether this in a modification watchpoint
+ * @throws CoreException if unable to create the watchpoint
+ */
+ public PDAWatchpoint(final IResource resource, final int lineNumber, final String functionName, final String varName, final boolean access, final boolean modification) throws CoreException {
+ IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarker marker = resource.createMarker("org.eclipse.cdt.examples.dsf.pda.markerType.watchpoint");
+ setMarker(marker);
+ setEnabled(true);
+ ensureMarker().setAttribute(IMarker.LINE_NUMBER, lineNumber);
+ ensureMarker().setAttribute(IBreakpoint.ID, getModelIdentifier());
+ setAccess(access);
+ setModification(modification);
+ setVariable(functionName, varName);
+ marker.setAttribute(IMarker.MESSAGE, "Watchpoint: " + resource.getName() + " [line: " + lineNumber + "]");
+ }
+ };
+ run(getMarkerRule(resource), runnable);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#isAccess()
+ */
+ public boolean isAccess() throws CoreException {
+ return getMarker().getAttribute(ACCESS, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#setAccess(boolean)
+ */
+ public void setAccess(boolean access) throws CoreException {
+ setAttribute(ACCESS, access);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#isModification()
+ */
+ public boolean isModification() throws CoreException {
+ return getMarker().getAttribute(MODIFICATION, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#setModification(boolean)
+ */
+ public void setModification(boolean modification) throws CoreException {
+ setAttribute(MODIFICATION, modification);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#supportsAccess()
+ */
+ public boolean supportsAccess() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IWatchpoint#supportsModification()
+ */
+ public boolean supportsModification() {
+ return true;
+ }
+
+ /**
+ * Sets the variable and function names the watchpoint is set on.
+ *
+ * @param functionName function name
+ * @param variableName variable name
+ * @throws CoreException if an exception occurrs setting marker attribtues
+ */
+ protected void setVariable(String functionName, String variableName) throws CoreException {
+ setAttribute(VAR_NAME, variableName);
+ setAttribute(FUNCTION_NAME, functionName);
+ }
+
+ /**
+ * Returns the name of the variable this watchpoint is set on.
+ *
+ * @return the name of the variable this watchpoint is set on
+ * @throws CoreException if unable to access the attribute
+ */
+ public String getVariableName() throws CoreException {
+ return getMarker().getAttribute(VAR_NAME, (String)null);
+ }
+
+ /**
+ * Returns the name of the function the variable associted with this watchpoint is defined in.
+ *
+ * @return the name of the function the variable associted with this watchpoint is defined in
+ * @throws CoreException if unable to access the attribute
+ */
+ public String getFunctionName() throws CoreException {
+ return getMarker().getAttribute(FUNCTION_NAME, (String)null);
+ }
+
+ /**
+ * Sets the type of event that causes the last suspend event.
+ *
+ * @param description one of 'read' or 'write'
+ */
+ public void setSuspendType(String description) {
+ fLastSuspendType = description;
+ }
+
+ /**
+ * Returns the type of event that caused the last suspend.
+ *
+ * @return 'read', 'write', or <code>null</code> if undefined
+ */
+ public String getSuspendType() {
+ return fLastSuspendType;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunch.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunch.java
new file mode 100644
index 00000000000..87ff4b8362a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunch.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.launch;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.PDATerminatedEvent;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.Launch;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.model.ITerminate;
+
+/**
+ * The PDA launch object. In general, a DSF-based debugger has to override
+ * the base launch class in order to supply its own content providers for the
+ * debug view. Additionally, the PDA launch is used to monitor the state of the
+ * PDA debugger and to shutdown the DSF services and session belonging to the
+ * launch.
+ * <p>
+ * The PDA launch class mostly contains methods and fields that can be accessed
+ * on any thread. However, some fields and methods used for managing the DSF
+ * session need to be synchronized using the DSF executor.
+ * </p>
+ */
+@ThreadSafe
+public class PDALaunch extends Launch
+implements ITerminate
+{
+ // DSF executor and session. Both are created and shutdown by the launch.
+ private final DefaultDsfExecutor fExecutor;
+ private final DsfSession fSession;
+
+ // Objects used to track the status of the DSF session.
+ private boolean fInitialized = false;
+ private boolean fShutDown = false;
+
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ private Sequence fInitializationSequence = null;
+
+ /**
+ * Launch constructor creates the launch for given parameters. The
+ * constructor also creates a DSF session and an executor, so that
+ * {@link #getSession()} returns a valid value, however no services
+ * are initialized yet.
+ *
+ * @see Launch
+ */
+ public PDALaunch(ILaunchConfiguration launchConfiguration, String mode, ISourceLocator locator) {
+ super(launchConfiguration, mode, locator);
+
+ // Create the dispatch queue to be used by debugger control and services
+ // that belong to this launch
+ final DefaultDsfExecutor dsfExecutor = new DefaultDsfExecutor(PDAPlugin.ID_PDA_DEBUG_MODEL);
+ dsfExecutor.prestartCoreThread();
+ fExecutor = dsfExecutor;
+ fSession = DsfSession.startSession(fExecutor, PDAPlugin.ID_PDA_DEBUG_MODEL);
+ }
+
+ /**
+ * Returns the DSF services session that belongs to this launch. This
+ * method will always return a DsfSession object, however if the debugger
+ * is shut down, the session will no longer active.
+ */
+ public DsfSession getSession() { return fSession; }
+
+ /**
+ * Initializes the DSF services using the specified parameters. This
+ * method has to be called on the executor thread in order to avoid
+ * synchronization issues.
+ */
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ public void initializeServices(String program, final RequestMonitor rm)
+ {
+ // Double-check that we're being called in the correct thread.
+ assert fExecutor.isInExecutorThread();
+
+ // Check if shutdownServices() was called already, which would be
+ // highly unusual, but if so we don't need to do anything except set
+ // the initialized flag.
+ synchronized(this) {
+ if (fShutDown) {
+ fInitialized = true;
+ return;
+ }
+ }
+
+ // Register the launch as listener for services events.
+ fSession.addServiceEventListener(PDALaunch.this, null);
+
+ // The initialization sequence is stored in a field to allow it to be
+ // canceled if shutdownServices() is called before the sequence
+ // completes.
+ fInitializationSequence = new PDAServicesInitSequence(
+ getSession(), this, program,
+ new RequestMonitor(ImmediateExecutor.getInstance(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Set the initialized flag and check whether the
+ // shutdown flag is set. Access the flags in a
+ // synchronized section as these flags can be accessed
+ // on any thread.
+ boolean doShutdown = false;
+ synchronized (this) {
+ fInitialized = true;
+ fInitializationSequence = null;
+ if (fShutDown) {
+ doShutdown = true;
+ }
+ }
+
+ if (doShutdown) {
+ // If shutdownServices() was already called, start the
+ // shutdown sequence now.
+ doShutdown(rm);
+ } else {
+ // If there was an error in the startup sequence,
+ // report the error to the client.
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ rm.setStatus(getStatus());
+ }
+ rm.done();
+ }
+ fireChanged();
+ }
+ });
+
+ // Finally, execute the sequence.
+ getSession().getExecutor().execute(fInitializationSequence);
+ }
+
+ /**
+ * Event handler for a debugger terminated event.
+ */
+ @DsfServiceEventHandler
+ public void eventDispatched(PDATerminatedEvent event) {
+ shutdownServices(new RequestMonitor(ImmediateExecutor.getInstance(), null));
+ }
+
+ /**
+ * Returns whether the DSF service initialization sequence has completed yet.
+ */
+ public synchronized boolean isInitialized() {
+ return fInitialized;
+ }
+
+ /**
+ * Returns whether the DSF services have been set to shut down.
+ * @return
+ */
+ public synchronized boolean isShutDown() {
+ return fShutDown;
+ }
+
+ @Override
+ public boolean canTerminate() {
+ return super.canTerminate() && isInitialized() && !isShutDown();
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return super.isTerminated() || isShutDown();
+ }
+
+
+ @Override
+ public void terminate() throws DebugException {
+ if (isShutDown()) return;
+ super.terminate();
+ }
+
+ /**
+ * Shuts down the services, the session and the executor associated with
+ * this launch.
+ * <p>
+ * Note: The argument request monitor to this method should NOT use the
+ * executor that belongs to this launch. By the time the shutdown is
+ * complete, this executor will not be dispatching anymore and the
+ * request monitor will never be invoked. Instead callers should use
+ * the {@link ImmediateExecutor}.
+ * </p>
+ * @param rm The request monitor invoked when the shutdown is complete.
+ */
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ public void shutdownServices(final RequestMonitor rm) {
+ // Check initialize and shutdown flags to determine if the shutdown
+ // sequence can be called yet.
+ boolean doShutdown = false;
+ synchronized (this) {
+ if (!fInitialized && fInitializationSequence != null) {
+ // Launch has not yet initialized, try to cancel the
+ // shutdown sequence.
+ fInitializationSequence.cancel(false);
+ } else {
+ doShutdown = !fShutDown && fInitialized;
+ }
+ fShutDown = true;
+ }
+
+ if (doShutdown) {
+ doShutdown(rm);
+ } else {
+ rm.done();
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession().getExecutor()")
+ private void doShutdown(final RequestMonitor rm) {
+ fExecutor.execute( new PDAServicesShutdownSequence(
+ fExecutor, fSession.getId(),
+ new RequestMonitor(fSession.getExecutor(), rm) {
+ @Override
+ public void handleCompleted() {
+ fSession.removeServiceEventListener(PDALaunch.this);
+ if (!isSuccess()) {
+ PDAPlugin.getDefault().getLog().log(new MultiStatus(
+ PDAPlugin.PLUGIN_ID, -1, new IStatus[]{getStatus()}, "Session shutdown failed", null)); //$NON-NLS-1$
+ }
+ // Last order of business, shutdown the dispatch queue.
+ DsfSession.endSession(fSession);
+ // endSession takes a full dispatch to distribute the
+ // session-ended event, finish step only after the dispatch.
+ fExecutor.shutdown();
+ fireTerminate();
+
+ rm.setStatus(getStatus());
+ rm.done();
+ }
+ }) );
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getAdapter(Class adapter) {
+ // Force adapters to be loaded. Otherwise the adapter manager may not find
+ // the model proxy adapter for DSF-based debug elements.
+ Platform.getAdapterManager().loadAdapter(this, adapter.getName());
+ return super.getAdapter(adapter);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunchDelegate.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunchDelegate.java
new file mode 100644
index 00000000000..a555c94eefd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDALaunchDelegate.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.launch;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABackend;
+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.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.IPersistableSourceLocator;
+import org.eclipse.debug.core.model.ISourceLocator;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+import org.eclipse.debug.core.sourcelookup.IPersistableSourceLocator2;
+
+
+/**
+ * Launches PDA program on a PDA interpretter written in Perl
+ */
+public class PDALaunchDelegate extends LaunchConfigurationDelegate {
+
+ @Override
+ public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+ // Need to configure the source locator before creating the launch
+ // because once the launch is created and added to launch manager,
+ // the adapters will be created for the whole session, including
+ // the source lookup adapter.
+ ISourceLocator locator = getSourceLocator(configuration);
+
+ return new PDALaunch(configuration, mode, locator);
+ }
+
+ @Override
+ public boolean buildForLaunch(ILaunchConfiguration configuration, String mode, IProgressMonitor monitor) throws CoreException {
+ // PDA programs do not require building.
+ return false;
+ }
+
+ /**
+ * Returns a source locator created based on the attributes in the launch configuration.
+ */
+ private ISourceLocator getSourceLocator(ILaunchConfiguration configuration) throws CoreException {
+ String type = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String)null);
+ if (type == null) {
+ type = configuration.getType().getSourceLocatorId();
+ }
+ if (type != null) {
+ IPersistableSourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type);
+ String memento = configuration.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String)null);
+ if (memento == null) {
+ locator.initializeDefaults(configuration);
+ } else {
+ if(locator instanceof IPersistableSourceLocator2)
+ ((IPersistableSourceLocator2)locator).initializeFromMemento(memento, configuration);
+ else
+ locator.initializeFromMemento(memento);
+ }
+ return locator;
+ }
+ return null;
+ }
+
+ public void launch(ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor) throws CoreException {
+ String program = configuration.getAttribute(PDAPlugin.ATTR_PDA_PROGRAM, (String)null);
+ if (program == null) {
+ abort("Perl program unspecified.", null);
+ }
+
+ PDALaunch pdaLaunch = (PDALaunch)launch;
+ initServices(pdaLaunch, program);
+ createProcess(pdaLaunch);
+ }
+
+ /**
+ * Calls the launch to initialize DSF services for this launch.
+ */
+ private void initServices(final PDALaunch pdaLaunch, final String program)
+ throws CoreException
+ {
+ // Synchronization object to use when waiting for the services initialization.
+ Query<Object> initQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ pdaLaunch.initializeServices(program, rm);
+ }
+ };
+
+ // Submit the query to the executor.
+ pdaLaunch.getSession().getExecutor().execute(initQuery);
+ try {
+ // Block waiting for query results.
+ initQuery.get();
+ } catch (InterruptedException e1) {
+ throw new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Interrupted Exception in dispatch thread", e1)); //$NON-NLS-1$
+ } catch (ExecutionException e1) {
+ throw new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Error in launch sequence", e1.getCause())); //$NON-NLS-1$
+ }
+ }
+
+ private void createProcess(final PDALaunch pdaLaunch) throws CoreException {
+ // Synchronization object to use when waiting for the services initialization.
+ Query<Object[]> initQuery = new Query<Object[]>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object[]> rm) {
+ DsfServicesTracker tracker = new DsfServicesTracker(PDAPlugin.getBundleContext(), pdaLaunch.getSession().getId());
+ PDABackend backend = tracker.getService(PDABackend.class);
+ if (backend == null) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "PDA Backend service not available");
+ return;
+ }
+ Object[] retVal = new Object[] { backend.getProcess(), backend.getProcessName() };
+ rm.setData(retVal);
+ rm.done();
+ }
+ };
+
+ // Submit the query to the executor.
+ pdaLaunch.getSession().getExecutor().execute(initQuery);
+ try {
+ // Block waiting for query results.
+ Object[] processData = initQuery.get();
+ DebugPlugin.newProcess(pdaLaunch, (Process)processData[0], (String)processData[1]);
+ } catch (InterruptedException e1) {
+ throw new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR, "Interrupted Exception in dispatch thread", e1)); //$NON-NLS-1$
+ } catch (ExecutionException e1) {
+ throw new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Error in launch sequence", e1.getCause())); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Throws an exception with a new status containing the given
+ * message and optional exception.
+ *
+ * @param message error message
+ * @param e underlying exception
+ * @throws CoreException
+ */
+ private void abort(String message, Throwable e) throws CoreException {
+ throw new CoreException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, 0, message, e));
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java
new file mode 100644
index 00000000000..d993cf54276
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesInitSequence.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.launch;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABackend;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABreakpointAttributeTranslator;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABreakpoints;
+import org.eclipse.cdt.examples.dsf.pda.service.PDACommandControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAExpressions;
+import org.eclipse.cdt.examples.dsf.pda.service.PDARegisters;
+import org.eclipse.cdt.examples.dsf.pda.service.PDARunControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAStack;
+
+/**
+ * The initialization sequence for PDA debugger services. This sequence contains
+ * the series of steps that are executed to properly initialize the PDA-DSF debug
+ * session. If any of the individual steps fail, the initialization will abort.
+ * <p>
+ * The order in which services are initialized is important. Some services depend
+ * on other services and they assume that they will be initialized only if those
+ * services are active. Also the service events are prioritized and their priority
+ * depends on the order in which the services were initialized.
+ * </p>
+ */
+public class PDAServicesInitSequence extends Sequence {
+
+ Step[] fSteps = new Step[] {
+ new Step()
+ {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start PDA back end debugger service.
+ new PDABackend(fSession, fLaunch, fProgram).initialize(requestMonitor);
+ }
+ },
+ new Step()
+ {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start PDA command control service.
+ fCommandControl = new PDACommandControl(fSession);
+ fCommandControl.initialize(requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start the run control service.
+ fRunControl = new PDARunControl(fSession);
+ fRunControl.initialize(requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(final RequestMonitor requestMonitor) {
+ // Start the low-level breakpoint service
+ new PDABreakpoints(fSession).initialize(new RequestMonitor(getExecutor(), requestMonitor));
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(final RequestMonitor requestMonitor) {
+ // Create the breakpoint mediator and start tracking PDA breakpoints.
+
+ final BreakpointsMediator bpmService = new BreakpointsMediator(
+ fSession, new PDABreakpointAttributeTranslator());
+ bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ bpmService.startTrackingBreakpoints(fCommandControl.getContext(), requestMonitor);
+ }
+ });
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start the stack service.
+ new PDAStack(fSession).initialize(requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start the service to track expressions.
+ new PDAExpressions(fSession).initialize(requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Start the service to track expressions.
+ new PDARegisters(fSession).initialize(requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fRunControl.resume(fCommandControl.getContext(), requestMonitor);
+ }
+ },
+ };
+
+ // Sequence input parameters, used in initializing services.
+ private PDALaunch fLaunch;
+ private DsfSession fSession;
+ private String fProgram;
+
+ // Service references, initialized when created and used in initializing other services.
+ private PDACommandControl fCommandControl;
+ private PDARunControl fRunControl;
+
+ public PDAServicesInitSequence(DsfSession session, PDALaunch launch, String program, RequestMonitor rm)
+ {
+ super(session.getExecutor(), rm);
+ fLaunch = launch;
+ fSession = session;
+ fProgram = program;
+ }
+
+ @Override
+ public Step[] getSteps() {
+ return fSteps;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesShutdownSequence.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesShutdownSequence.java
new file mode 100644
index 00000000000..aadd229547e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/launch/PDAServicesShutdownSequence.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.launch;
+
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABreakpoints;
+import org.eclipse.cdt.examples.dsf.pda.service.PDACommandControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAExpressions;
+import org.eclipse.cdt.examples.dsf.pda.service.PDARegisters;
+import org.eclipse.cdt.examples.dsf.pda.service.PDARunControl;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAStack;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * The shutdown sequence for PDA debugger services. This sequence contains
+ * the series of steps that are executed to properly shutdown the PDA-DSF debug
+ * session. If any of the individual steps fail, the shutdown will abort.
+ * <p>
+ * Services are shut down in the reverse order of initialization.
+ * </p>
+ */
+public class PDAServicesShutdownSequence extends Sequence {
+
+ private final Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Initialize services tracker.
+ assert PDAPlugin.getBundleContext() != null;
+ fTracker = new DsfServicesTracker(PDAPlugin.getBundleContext(), fSessionId);
+ requestMonitor.done();
+ }
+
+ @Override
+ public void rollBack(RequestMonitor requestMonitor) {
+ // In case the shutdown sequence aborts, ensure that the
+ // tracker is properly disposed.
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDAExpressions.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDARegisters.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDAStack.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(BreakpointsMediator.class, requestMonitor);
+ }
+ }, new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDABreakpoints.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDARunControl.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(PDACommandControl.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ private String fSessionId;
+ private DsfServicesTracker fTracker;
+
+ public PDAServicesShutdownSequence(DsfExecutor executor, String sessionId, RequestMonitor requestMonitor) {
+ super(executor, requestMonitor);
+ fSessionId = sessionId;
+ }
+
+ @Override
+ public Step[] getSteps() {
+ return fSteps;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void shutdownService(Class clazz, final RequestMonitor requestMonitor) {
+ IDsfService service = (IDsfService)fTracker.getService(clazz);
+ if (service != null) {
+ service.shutdown(new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleCompleted() {
+ if (!isSuccess()) {
+ PDAPlugin.getDefault().getLog().log(getStatus());
+ }
+ requestMonitor.done();
+ }
+ });
+ } else {
+ requestMonitor.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR,
+ "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$
+ requestMonitor.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABackend.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABackend.java
new file mode 100644
index 00000000000..b391190894b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABackend.java
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation.
+ * All rights reserved. This fProgram 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:
+ * Nokia - initial version. Sep 28, 2008
+ *******************************************************************************/
+
+package org.eclipse.cdt.examples.dsf.pda.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.Sequence.Step;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.Launch;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Service that manages the backend process: starting the process
+ * and monitoring for its shutdown.
+ */
+public class PDABackend extends AbstractDsfService {
+
+ private int fRequestPort;
+ private int fEventPort;
+
+ @ThreadSafe
+ private OutputStream fRequestOutputStream;
+ @ThreadSafe
+ private InputStream fRequestInputStream;
+ @ThreadSafe
+ private InputStream fEventInputStream;
+
+ private String fProgram;
+ private Process fBackendProcess;
+ private String fBackendProcessName;
+
+ /**
+ *
+ * @param session
+ * @param launch - can be null, e.g. for JUnit test.
+ * @param program - can be a full path or a workspace resource path, must denote an existing file.
+ */
+ public PDABackend(DsfSession session, Launch launch, String program) {
+ super(session);
+
+ fProgram = program;
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ public Process getProcess() {
+ return fBackendProcess;
+ }
+
+ public String getProcessName() {
+ return fBackendProcessName;
+ }
+
+ public String getPorgramName() {
+ return fProgram;
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ super.initialize(new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }
+ });
+ }
+
+ private void doInitialize(final RequestMonitor requestMonitor) {
+
+ final Sequence.Step[] initializeSteps = new Sequence.Step[] {
+ new Step() {
+ // Launch the back end debugger process.
+
+ @Override
+ public void execute(final RequestMonitor rm) {
+
+ new Job("Start PDA Virtual Machine") {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ fBackendProcess = launchPDABackendDebugger();
+ } catch (CoreException e) {
+ rm.setStatus(e.getStatus());
+ }
+ rm.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ @Override
+ public void rollBack(RequestMonitor rm) {
+ if (fBackendProcess != null)
+ fBackendProcess.destroy();
+
+ rm.done();
+ }
+
+ },
+ new Step() {
+ @Override
+ public void execute(final RequestMonitor rm) {
+
+ // To avoid blocking the DSF dispatch thread use a job to initialize communication sockets.
+ new Job("PDA Socket Initialize") {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ // give interpreter a chance to start
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ Socket socket = new Socket("localhost", fRequestPort);
+ fRequestOutputStream = socket.getOutputStream();
+ fRequestInputStream = socket.getInputStream();
+ // give interpreter a chance to open next socket
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
+ socket = new Socket("localhost", fEventPort);
+ fEventInputStream = socket.getInputStream();
+
+ } catch (UnknownHostException e) {
+ rm.setStatus(new Status(
+ IStatus.ERROR, PDAPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to connect to PDA VM", e));
+ } catch (IOException e) {
+ rm.setStatus(new Status(
+ IStatus.ERROR, PDAPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to connect to PDA VM", e));
+ }
+ rm.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+ },
+
+ new Step() { // register the service
+ @Override
+ public void execute(RequestMonitor rm) {
+ // Register this service
+ register(new String[] { PDABackend.class.getName() },
+ new Hashtable<String, String>());
+
+ rm.done();
+ }
+ },
+ };
+
+ Sequence startupSequence = new Sequence(getExecutor(), requestMonitor) {
+ @Override public Step[] getSteps() { return initializeSteps; }
+ };
+ getExecutor().execute(startupSequence);
+ }
+
+ /**
+ * Returns a free port number on localhost, or -1 if unable to find a free port.
+ */
+ public static int findFreePort() {
+ ServerSocket socket= null;
+ try {
+ socket= new ServerSocket(0);
+ return socket.getLocalPort();
+ } catch (IOException e) {
+ } finally {
+ if (socket != null) {
+ try {
+ socket.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ return -1;
+ }
+
+ private void abort(String message, Throwable e) throws CoreException {
+ throw new CoreException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, 0, message, e));
+ }
+
+ private Process launchPDABackendDebugger() throws CoreException {
+
+ List<String> commandList = new ArrayList<String>();
+
+ // Get Java VM path
+ String javaVMHome = System.getProperty("java.home");
+ String javaVMExec = javaVMHome + File.separatorChar + "bin" + File.separatorChar + "java";
+ if (File.separatorChar == '\\') {
+ javaVMExec += ".exe";
+ }
+ File exe = new File(javaVMExec);
+ if (!exe.exists()) {
+ abort(MessageFormat.format("Specified java VM executable {0} does not exist.", new Object[]{javaVMExec}), null);
+ }
+
+ fBackendProcessName = javaVMExec;
+
+ commandList.add(javaVMExec);
+
+ commandList.add("-cp");
+ commandList.add(File.pathSeparator + PDAPlugin.getFileInPlugin(new Path("bin")));
+
+ commandList.add("org.eclipse.cdt.examples.pdavm.PDAVirtualMachine");
+
+ String absolutePath = fProgram;
+
+ // check if fProgram is already a full path of an existing file
+ // Note if "fProgram" is workspace resource path like /ProjectName/file.pda, we should not
+ // change it to absolute path, otherwise the breakpoints in the PDA file won't work.
+ // See PDABreakpoints.doInsertBreakpoint() for more.
+ File f = new File(fProgram);
+ if (! f.exists()) {
+ // Try to locate it in workspace
+ IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(fProgram));
+ if (file.exists())
+ absolutePath = file.getLocation().toPortableString();
+ else
+ abort(MessageFormat.format("PDA program {0} does not exist.", new Object[] {file.getFullPath().toPortableString()}), null);
+ }
+
+ commandList.add(absolutePath);
+
+ fRequestPort = findFreePort();
+ fEventPort = findFreePort();
+
+ if (fRequestPort == -1 || fEventPort == -1) {
+ abort("Unable to find free port", null);
+ }
+
+ // Add debug arguments - i.e. '-debug fRequestPort fEventPort'
+ commandList.add("-debug");
+ commandList.add("" + fRequestPort);
+ commandList.add("" + fEventPort);
+
+ // Launch the perl process.
+ String[] commandLine = commandList.toArray(new String[commandList.size()]);
+
+ PDAPlugin.debug("Start PDA Virtual Machine:\n" + commandList);
+
+ Process process = DebugPlugin.exec(commandLine, null);
+
+ return process;
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ fBackendProcess.destroy();
+
+ try {
+ if (fRequestInputStream != null)
+ fRequestInputStream.close();
+ if (fRequestOutputStream != null)
+ fRequestOutputStream.close();
+ if (fEventInputStream != null)
+ fEventInputStream.close();
+ } catch (IOException e) {
+ // ignore
+ }
+
+ unregister();
+ rm.done();
+ }
+
+ /*
+ * =========== Following are PDA debugger specific ====================
+ *
+ * Caller should make sure these are called after the PDABackend is initialized.
+ */
+ public OutputStream getRequestOutputStream() {
+ return fRequestOutputStream;
+ }
+
+ public InputStream getRequestInputStream() {
+ return fRequestInputStream;
+ }
+
+ public InputStream getEventInputStream() {
+ return fEventInputStream;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java
new file mode 100644
index 00000000000..7bdb29b3887
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpointAttributeTranslator.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.debug.service.BreakpointsMediator;
+import org.eclipse.cdt.dsf.debug.service.IBreakpointAttributeTranslator;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDALineBreakpoint;
+import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDAWatchpoint;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+/**
+ * Translator between {@link PDALineBreakpoint} object attributes and
+ * attributes used by the {@link PDABreakpoints} service.
+ * <p>
+ * The attribute translator is used by the standard {@link BreakpointsMediator}
+ * service to map between platform breakpoint attributes and target-side DSF
+ * breakpoint attributes. Thus, this object encapsulates the model-specific
+ * functionality of synchronizing target side and IDE-side breakpoint objects.
+ * </p>
+ */
+public class PDABreakpointAttributeTranslator implements IBreakpointAttributeTranslator {
+
+ // Arrays of common attributes between the two breakpoint types. These
+ // attributes can be copied directly without translation.
+ private static final String[] fgPDALineBreakpointAttributes = {
+ IBreakpoint.ENABLED,
+ IMarker.LINE_NUMBER,
+ };
+ private static final String[] fgPDAWatchpointAttributes = {
+ IBreakpoint.ENABLED,
+ PDAWatchpoint.FUNCTION_NAME,
+ PDAWatchpoint.VAR_NAME,
+ PDAWatchpoint.ACCESS,
+ PDAWatchpoint.MODIFICATION
+ };
+
+ // PDA breakpoints translator doesn't keep any state and it doesn't
+ // need to initialize or clean up.
+ public void initialize(BreakpointsMediator mediator) {
+ }
+
+ public void dispose() {
+ }
+
+ public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint bp, boolean bpManagerEnabled)
+ throws CoreException
+ {
+ Map<String, Object> attrs = new HashMap<String, Object>();
+
+ // Check that the marker exists and retrieve its attributes.
+ // Due to accepted race conditions, the breakpiont marker may become null
+ // while this method is being invoked. In this case throw an exception
+ // and let the caller handle it.
+ IMarker marker = bp.getMarker();
+ if (marker == null || !marker.exists()) {
+ throw new DebugException(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, DebugException.REQUEST_FAILED, "Breakpoint marker does not exist", null));
+ }
+ // Suppress cast warning: platform is still on Java 1.3
+ @SuppressWarnings("unchecked")
+ Map<String, Object> platformBpAttrs = marker.getAttributes();
+
+ // Copy breakpoint attributes.
+ if (bp instanceof PDAWatchpoint) {
+ attrs.put(PDABreakpoints.ATTR_BREAKPOINT_TYPE, PDABreakpoints.PDA_WATCHPOINT);
+
+ copyAttributes(platformBpAttrs, attrs, fgPDAWatchpointAttributes);
+ } else if (bp instanceof PDALineBreakpoint) {
+ attrs.put(PDABreakpoints.ATTR_BREAKPOINT_TYPE, PDABreakpoints.PDA_LINE_BREAKPOINT);
+ attrs.put(PDABreakpoints.ATTR_PROGRAM_PATH, marker.getResource().getFullPath().toString());
+
+ copyAttributes(platformBpAttrs, attrs, fgPDALineBreakpointAttributes);
+ }
+
+ // If the breakpoint manager is disabled, override the enabled attribute.
+ if (!bpManagerEnabled) {
+ attrs.put(IBreakpoint.ENABLED, false);
+ }
+
+ // The breakpoint mediator allows for multiple target-side breakpoints
+ // to be created for each IDE breakpoint. Although in case of PDA this
+ // feature is never used, we still have to return a list of attributes.
+ List<Map<String, Object>> retVal = new ArrayList<Map<String, Object>>(1);
+ retVal.add(attrs);
+ return retVal;
+ }
+
+ private void copyAttributes(Map<String, Object> srcMap, Map<String, Object> destMap, String[] attrs) {
+ for (String attr : attrs) {
+ if (srcMap.containsKey(attr)) {
+ destMap.put(attr, srcMap.get(attr));
+ }
+ }
+ }
+
+ public boolean canUpdateAttributes(IBreakpointDMContext bp, Map<String, Object> delta) {
+ // PDA debugger only allows updating of the action property of the watchpoint.
+ // All other breakpoint updates will require a re-installation.
+ if (bp instanceof PDAWatchpoint) {
+ Map<String, Object> deltaCopy = new HashMap<String, Object>(delta);
+ deltaCopy.remove(PDAWatchpoint.ACCESS);
+ deltaCopy.remove(PDAWatchpoint.MODIFICATION);
+ return !deltaCopy.isEmpty();
+ }
+ return false;
+ }
+
+ public boolean supportsBreakpoint(IBreakpoint bp) {
+ return bp.getModelIdentifier().equals(PDAPlugin.ID_PDA_DEBUG_MODEL);
+ }
+
+ public void updateBreakpointStatus(IBreakpoint bp) {
+ // PDA breakpoints do not support status reporting
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpoints.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpoints.java
new file mode 100644
index 00000000000..0b219c95106
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDABreakpoints.java
@@ -0,0 +1,403 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Ericsson 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:
+ * Ericsson - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.examples.dsf.pda.service;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.breakpoints.PDAWatchpoint;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAClearBreakpointCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDASetBreakpointCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAWatchCommand;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Initial breakpoint service implementation.
+ * Implements the IBreakpoints interface.
+ */
+public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
+{
+ /**
+ * Context representing a PDA line breakpoint. In PDA debugger, since there is only
+ * one file being debugged at a time, a breakpoint is uniquely identified using the
+ * line number only.
+ */
+ @Immutable
+ private static class BreakpointDMContext extends AbstractDMContext implements IBreakpointDMContext {
+
+ final Integer fLine;
+
+ public BreakpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, Integer line) {
+ super(sessionId, new IDMContext[] { commandControlCtx });
+ fLine = line;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return baseEquals(obj) && (fLine.equals(((BreakpointDMContext) obj).fLine));
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + fLine.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".breakpoint(" + fLine + ")"; //$NON-NLS-1$//$NON-NLS-2$*/
+ }
+ }
+
+ /**
+ * Context representing a watch point. In PDA debugger, a watchpoint is
+ * uniquely identified using the function and variable.
+ */
+ @Immutable
+ private static class WatchpointDMContext extends AbstractDMContext implements IBreakpointDMContext {
+ final String fFunction;
+ final String fVariable;
+
+ public WatchpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, String function,
+ String variable)
+ {
+ super(sessionId, new IDMContext[] { commandControlCtx });
+ fFunction = function;
+ fVariable = variable;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (baseEquals(obj)) {
+ WatchpointDMContext watchpointCtx = (WatchpointDMContext)obj;
+ return fFunction.equals(watchpointCtx.fFunction) && fVariable.equals(watchpointCtx.fVariable);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + fFunction.hashCode() + fVariable.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".watchpoint(" + fFunction + "::" + fVariable + ")";
+ }
+ }
+
+ // Attribute names
+ public static final String ATTR_BREAKPOINT_TYPE = PDAPlugin.PLUGIN_ID + ".pdaBreakpointType"; //$NON-NLS-1$
+ public static final String PDA_LINE_BREAKPOINT = "breakpoint"; //$NON-NLS-1$
+ public static final String PDA_WATCHPOINT = "watchpoint"; //$NON-NLS-1$
+ public static final String ATTR_PROGRAM_PATH = PDAPlugin.PLUGIN_ID + ".pdaProgramPath"; //$NON-NLS-1$
+
+ // Services
+ private PDACommandControl fCommandControl;
+
+ // Breakpoints currently installed
+ private Set<IBreakpointDMContext> fBreakpoints = new HashSet<IBreakpointDMContext>();
+
+ /**
+ * The service constructor
+ *
+ * @param session The debugging session this service belongs to.
+ */
+ public PDABreakpoints(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ super.initialize(new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }
+ });
+ }
+
+ private void doInitialize(final RequestMonitor rm) {
+ // Get the services references
+ fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+
+ // Register this service
+ register(new String[] { IBreakpoints.class.getName(), PDABreakpoints.class.getName() },
+ new Hashtable<String, String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ unregister();
+ rm.done();
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor<IBreakpointDMContext[]> rm) {
+ // Validate the context
+ if (!fCommandControl.getContext().equals(context)) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context");
+ return;
+ }
+
+ rm.setData(fBreakpoints.toArray(new IBreakpointDMContext[fBreakpoints.size()]));
+ rm.done();
+ }
+
+ public void getBreakpointDMData(IBreakpointDMContext dmc, DataRequestMonitor<IBreakpointDMData> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Retrieving breakpoint data is not supported");
+ }
+
+ public void insertBreakpoint(IBreakpointsTargetDMContext context, Map<String, Object> attributes,
+ DataRequestMonitor<IBreakpointDMContext> rm)
+ {
+ Boolean enabled = (Boolean)attributes.get(IBreakpoint.ENABLED);
+ if (enabled != null && !enabled.booleanValue()) {
+ // If the breakpoint is disabled, just fail the request.
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint is disabled");
+ } else {
+ String type = (String) attributes.get(ATTR_BREAKPOINT_TYPE);
+
+ if (PDA_LINE_BREAKPOINT.equals(type)) {
+ // Retrieve the PDA program context from the context given in the
+ // argument. This service is typically only called by the
+ // breakpoints mediator, which was called with the program context
+ // in the services initialization sequence. So checking if
+ // programCtx != null is mostly a formality.
+ PDAVirtualMachineDMContext programCtx = DMContexts.getAncestorOfType(context, PDAVirtualMachineDMContext.class);
+ if (programCtx != null) {
+ doInsertBreakpoint(programCtx, attributes, rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown breakpoint type");
+ }
+ }
+ else if (PDA_WATCHPOINT.equals(type)) {
+ doInsertWatchpoint(attributes, rm);
+ }
+ else {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Unknown breakpoint type");
+ }
+ }
+ }
+
+ private void doInsertBreakpoint(PDAVirtualMachineDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm)
+ {
+ // Compare the program path in the breakpoint with the path in the PDA
+ // program context. Only insert the breakpoint if the program matches.
+ String program = (String)attributes.get(ATTR_PROGRAM_PATH);
+ if (!programCtx.getProgram().equals(program)) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Invalid file name");
+ return;
+ }
+
+ // Retrieve the line.
+ Integer line = (Integer)attributes.get(IMarker.LINE_NUMBER);
+ if (line == null) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "No breakpoint line specified");
+ return;
+ }
+
+ // Create a new breakpoint context object and check that it's not
+ // installed already. PDA can only track a single breakpoint at a
+ // given line, attempting to set the second breakpoint should fail.
+ final BreakpointDMContext breakpointCtx =
+ new BreakpointDMContext(getSession().getId(), fCommandControl.getContext(), line);
+ if (fBreakpoints.contains(breakpointCtx)) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set");
+ return;
+ }
+
+ // Add the new breakpoint context to the list of known breakpoints.
+ // Adding it here, before the set command is completed will prevent
+ // a possibility of a second breakpoint being installed in the same
+ // location while this breakpoint is being processed. It will also
+ // allow the breakpoint to be removed or updated even while it is
+ // still being processed here.
+ fBreakpoints.add(breakpointCtx);
+ fCommandControl.queueCommand(
+ new PDASetBreakpointCommand(fCommandControl.getContext(), line, false),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(breakpointCtx);
+ rm.done();
+ }
+
+ @Override
+ protected void handleFailure() {
+ // If inserting of the breakpoint failed, remove it from
+ // the set of installed breakpoints.
+ fBreakpoints.remove(breakpointCtx);
+ super.handleFailure();
+ }
+ });
+ }
+
+ private void doInsertWatchpoint(final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm)
+ {
+ String function = (String)attributes.get(PDAWatchpoint.FUNCTION_NAME);
+ if (function == null) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "No function specified");
+ return;
+ }
+
+ String variable = (String)attributes.get(PDAWatchpoint.VAR_NAME);
+ if (variable == null) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "No variable specified");
+ return;
+ }
+
+ Boolean isAccess = (Boolean)attributes.get(PDAWatchpoint.ACCESS);
+ isAccess = isAccess != null ? isAccess : Boolean.FALSE;
+
+ Boolean isModification = (Boolean)attributes.get(PDAWatchpoint.MODIFICATION);
+ isModification = isModification != null ? isModification : Boolean.FALSE;
+
+ // Create a new watchpoint context object and check that it's not
+ // installed already. PDA can only track a single watchpoint for a given
+ // function::variable, attempting to set the second breakpoint should fail.
+ final WatchpointDMContext watchpointCtx =
+ new WatchpointDMContext(getSession().getId(), fCommandControl.getContext(), function, variable);
+ if (fBreakpoints.contains(watchpointCtx)) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Watchpoint already set");
+ return;
+ }
+
+ // Determine the watch operation to perform.
+ PDAWatchCommand.WatchOperation watchOperation = PDAWatchCommand.WatchOperation.NONE;
+ if (isAccess && isModification) {
+ watchOperation = PDAWatchCommand.WatchOperation.BOTH;
+ } else if (isAccess) {
+ watchOperation = PDAWatchCommand.WatchOperation.READ;
+ } else if (isModification) {
+ watchOperation = PDAWatchCommand.WatchOperation.WRITE;
+ }
+
+ // Add the new breakpoint context to the list of known breakpoints.
+ // Adding it here, before the set command is completed will prevent
+ // a possibility of a second breakpoint being installed in the same
+ // location while this breakpoint is being processed. It will also
+ // allow the breakpoint to be removed or updated even while it is
+ // still being processed here.
+ fBreakpoints.add(watchpointCtx);
+ fCommandControl.queueCommand(
+ new PDAWatchCommand(fCommandControl.getContext(), function, variable, watchOperation),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(watchpointCtx);
+ rm.done();
+ }
+
+ @Override
+ protected void handleFailure() {
+ // Since the command failed, we need to remove the breakpoint from
+ // the existing breakpoint set.
+ fBreakpoints.remove(watchpointCtx);
+ super.handleFailure();
+ }
+ });
+ }
+
+ public void removeBreakpoint(IBreakpointDMContext bpCtx, RequestMonitor rm) {
+ if (!fBreakpoints.contains(bpCtx)) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already removed");
+ return;
+ }
+
+ if (bpCtx instanceof BreakpointDMContext) {
+ doRemoveBreakpoint((BreakpointDMContext)bpCtx, rm);
+ } else if (bpCtx instanceof WatchpointDMContext) {
+ doRemoveWatchpoint((WatchpointDMContext)bpCtx, rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoint");
+ }
+ }
+
+ private void doRemoveBreakpoint(BreakpointDMContext bpCtx, RequestMonitor rm) {
+ // Remove the breakpoint from the table right away, so that even when
+ // the remove is being processed, a new breakpoint can be created at the same
+ // location.
+ fBreakpoints.remove(bpCtx);
+
+ fCommandControl.queueCommand(
+ new PDAClearBreakpointCommand(fCommandControl.getContext(), bpCtx.fLine),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));
+ }
+
+ private void doRemoveWatchpoint(WatchpointDMContext bpCtx, RequestMonitor rm) {
+ fBreakpoints.remove(bpCtx);
+
+ // Watchpoints are cleared using the same command, but with a "no watch" operation
+ fCommandControl.queueCommand(
+ new PDAWatchCommand(
+ fCommandControl.getContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));
+ }
+
+ public void updateBreakpoint(final IBreakpointDMContext bpCtx, Map<String, Object> attributes, final RequestMonitor rm) {
+ if (!fBreakpoints.contains(bpCtx)) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint not installed");
+ return;
+ }
+
+ if (bpCtx instanceof BreakpointDMContext) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Modifying PDA breakpoints is not supported");
+ } else if (bpCtx instanceof WatchpointDMContext) {
+ WatchpointDMContext wpCtx = (WatchpointDMContext)bpCtx;
+ if (!wpCtx.fFunction.equals(attributes.get(PDAWatchpoint.FUNCTION_NAME)) ||
+ !wpCtx.fVariable.equals(attributes.get(PDAWatchpoint.VAR_NAME)) )
+ {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Cannot modify watchpoint function or variable");
+ return;
+ }
+
+ // PDA debugger can only track one watchpoint in the same location,
+ // so we can simply remove the existing context from the set and
+ // call insert again.
+ fBreakpoints.remove(bpCtx);
+ doInsertWatchpoint(
+ attributes,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // The inserted watchpoint context will equal the
+ // current context.
+ assert bpCtx.equals(getData());
+ rm.done();
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoint");
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDACommandControl.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDACommandControl.java
new file mode 100644
index 00000000000..bfa653ba01a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDACommandControl.java
@@ -0,0 +1,520 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.debug.service.command.ICommand;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
+import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.AbstractPDACommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAExitCommand;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * Service that handles communication with a PDA debugger back end.
+ */
+public class PDACommandControl extends AbstractDsfService implements ICommandControlService {
+
+ // Structure used to store command information in services internal queues.
+ private static class CommandHandle {
+ final private ICommandToken fToken;
+ final private AbstractPDACommand<PDACommandResult> fCommand;
+ final private DataRequestMonitor<PDACommandResult> fRequestMonitor;
+
+ CommandHandle(ICommandToken token, AbstractPDACommand<PDACommandResult> c, DataRequestMonitor<PDACommandResult> rm) {
+ fToken = token;
+ fCommand = c;
+ fRequestMonitor = rm;
+ }
+ }
+
+ private PDABackend fBackend;
+
+ // Queue of commands waiting to be sent to the debugger. As long as commands
+ // are in this queue, they can still be removed by clients.
+ private final List<CommandHandle> fCommandQueue = new LinkedList<CommandHandle>();
+
+ // Queue of commands that are being sent to the debugger. This queue is read
+ // by the send job, so as soon as commands are inserted into this queue, they can
+ // be considered as sent.
+ @ThreadSafe
+ private final BlockingQueue<CommandHandle> fTxCommands = new LinkedBlockingQueue<CommandHandle>();
+
+ // Flag indicating that the PDA debugger started
+ private boolean fStarted = false;
+
+ // Flag indicating that the PDA debugger has been disconnected
+ @ThreadSafe
+ private boolean fTerminated = false;
+
+ // Data Model context of this command control.
+ private PDAVirtualMachineDMContext fDMContext;
+
+ // Synchronous listeners for commands and events.
+ private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>();
+ private final List<IEventListener> fEventListeners = new ArrayList<IEventListener>();
+
+ // Sockets for communicating with PDA debugger
+ @ThreadSafe
+ private PrintWriter fRequestWriter;
+ @ThreadSafe
+ private BufferedReader fRequestReader;
+ @ThreadSafe
+ private BufferedReader fEventReader;
+
+ // Jobs servicing the sockets.
+ private EventDispatchJob fEventDispatchJob;
+ private CommandSendJob fCommandSendJob;
+
+ /**
+ * Command control constructor.
+ * @param session The DSF session that this service is a part of.
+ */
+ public PDACommandControl(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ // Call the super-class to perform initialization first.
+ super.initialize( new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }
+ });
+ }
+
+ private void doInitialize(final RequestMonitor rm) {
+ fBackend = getServicesTracker().getService(PDABackend.class);
+
+ // Create the control's data model context.
+ fDMContext = new PDAVirtualMachineDMContext(getSession().getId(), fBackend.getPorgramName());
+
+ // Add a listener for PDA events to track the started/terminated state.
+ addEventListener(new IEventListener() {
+ public void eventReceived(Object output) {
+ if ("started 1".equals(output)) {
+ setStarted();
+ } else if ("terminated".equals(output)) {
+ setTerminated();
+ }
+ }
+ });
+
+ // Get intput/output streams from the backend service.
+ //
+ fRequestWriter = new PrintWriter(fBackend.getRequestOutputStream());
+ fRequestReader = new BufferedReader(new InputStreamReader(fBackend.getRequestInputStream()));
+ fEventReader = new BufferedReader(new InputStreamReader(fBackend.getEventInputStream()));
+
+ fEventDispatchJob = new EventDispatchJob();
+ fEventDispatchJob.schedule();
+
+ fCommandSendJob = new CommandSendJob();
+ fCommandSendJob.schedule();
+
+ // Register the service with OSGi as the last step in initialization of
+ // the service.
+ register(
+ new String[]{ ICommandControl.class.getName(), PDACommandControl.class.getName() },
+ new Hashtable<String,String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor requestMonitor) {
+ // Unregister the service first, so that clients may no longer gain access to it.
+ unregister();
+
+ if (!isTerminated()) {
+ // If the debugger is still connected, send it the exit command.
+ terminate(new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleCompleted() {
+ // Mark the command control as terminated.
+ setTerminated();
+
+ // Ignore any error resulting from the exit command.
+ // Errors will most likely result if the PDA process is
+ // already terminated.
+ requestMonitor.done();
+ }
+ });
+ } else {
+ requestMonitor.done();
+ }
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ /**
+ * Job that services the send command queue.
+ */
+ private class CommandSendJob extends Job {
+ CommandSendJob() {
+ super("PDA Command Send");
+ setSystem(true);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ while (!isTerminated()) {
+ synchronized (fTxCommands) {
+ try {
+ // Remove command from send queue.
+ final CommandHandle commandHandle = fTxCommands.take();
+
+ // Send the request to PDA
+ fRequestWriter.println(commandHandle.fCommand.getRequest());
+ fRequestWriter.flush();
+
+ try {
+ // wait for reply
+ final String response = fRequestReader.readLine();
+
+ // Process the reply in the executor thread.
+ try {
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ processCommandDone(commandHandle, response);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Acceptable race condition may see the session shut down
+ // while we're waiting for command response. Still complete
+ // the request monitor.
+ assert isTerminated();
+ assert isTerminated();
+ PDAPlugin.failRequest(commandHandle.fRequestMonitor, REQUEST_FAILED, "Command control shut down.");
+ }
+ } catch (final IOException e) {
+ // Process error it in the executor thread
+ try {
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ processCommandException(commandHandle, e);
+ }
+ });
+ } catch (RejectedExecutionException re) {
+ // Acceptable race condition... see above
+ assert isTerminated();
+ PDAPlugin.failRequest(commandHandle.fRequestMonitor, REQUEST_FAILED, "Command control shut down.");
+ }
+ }
+ } catch (InterruptedException e) {
+ break; // Shutting down.
+ }
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ }
+
+ /**
+ * Job that services the PDA event socket.
+ */
+ class EventDispatchJob extends Job {
+
+ public EventDispatchJob() {
+ super("PDA Event Listner");
+ setSystem(true);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ while (!isTerminated()) {
+ try {
+ // Wait for an event.
+ final String event = fEventReader.readLine();
+ if (event != null) {
+ try {
+ // Process the event in executor thread.
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ processEventReceived(event);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ } else {
+ break;
+ }
+ } catch (IOException e) {
+ break;
+ }
+ }
+ if (!isTerminated()) {
+ // Exception from the event socket is an indicator that the PDA debugger
+ // has exited. Call setTerminated() in executor thread.
+ try {
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ setTerminated();
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+ return Status.OK_STATUS;
+ }
+
+ }
+
+ public <V extends ICommandResult> ICommandToken queueCommand(final ICommand<V> command, DataRequestMonitor<V> rm) {
+ ICommandToken token = new ICommandToken() {
+ public ICommand<?> getCommand() {
+ return command;
+ }
+ };
+
+ if (command instanceof AbstractPDACommand<?>) {
+ // Cast from command with "<V extends ICommandResult>" to a more concrete
+ // type to use internally in the command control.
+ @SuppressWarnings("unchecked")
+ AbstractPDACommand<PDACommandResult> pdaCommand = (AbstractPDACommand<PDACommandResult>)command;
+
+ // Similarly, cast the request monitor to a more concrete type.
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<PDACommandResult> pdaRM = (DataRequestMonitor<PDACommandResult>)rm;
+
+ // Add the command to the queue and notify command listeners.
+ fCommandQueue.add( new CommandHandle(token, pdaCommand, pdaRM) );
+ for (ICommandListener listener : fCommandListeners) {
+ listener.commandQueued(token);
+ }
+
+ // In a separate dispatch cycle. This allows command listeners to respond to the
+ // command queued event.
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ processQueues();
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INTERNAL_ERROR, "Unrecognized command: " + command);
+ }
+ return token;
+ }
+
+ public void removeCommand(ICommandToken token) {
+ // Removes given command from the queue and notify the listeners
+ for (Iterator<CommandHandle> itr = fCommandQueue.iterator(); itr.hasNext();) {
+ CommandHandle handle = itr.next();
+ if (token.equals(handle.fToken)) {
+ itr.remove();
+ for (ICommandListener listener : fCommandListeners) {
+ listener.commandRemoved(token);
+ }
+ }
+ }
+ }
+
+ public void addCommandListener(ICommandListener processor) {
+ fCommandListeners.add(processor);
+ }
+
+ public void removeCommandListener(ICommandListener processor) {
+ fCommandListeners.remove(processor);
+ }
+
+ public void addEventListener(IEventListener processor) {
+ fEventListeners.add(processor);
+ }
+
+ public void removeEventListener(IEventListener processor) {
+ fEventListeners.remove(processor);
+ }
+
+ private void processCommandDone(CommandHandle handle, String response) {
+ // Trace to debug output.
+ PDAPlugin.debug("R: " + response);
+
+ PDACommandResult result = null;
+
+ if (response.startsWith("error:")) {
+ // Create a generic result with the error response
+ result = new PDACommandResult(response);
+
+ // Set the error status to the request monitor.
+ handle.fRequestMonitor.setStatus(new Status(
+ IStatus.ERROR, PDAPlugin.PLUGIN_ID,
+ IDsfStatusConstants.REQUEST_FAILED, response, null));
+ } else {
+ // Given the PDA response string, create the result using the command
+ // that was sent.
+ result = handle.fCommand.createResult(response);
+
+ // Set the result to the request monitor and return to sender.
+ // Note: as long as PDA sends some response, a PDA command will never
+ // return an error.
+ handle.fRequestMonitor.setData(result);
+ }
+ handle.fRequestMonitor.done();
+
+ // Notify listeners of the response
+ for (ICommandListener listener : fCommandListeners) {
+ listener.commandDone(handle.fToken, result);
+ }
+
+ // Process next command in queue.
+ processQueues();
+ }
+
+
+ private void processCommandException(CommandHandle handle, Throwable exception) {
+
+ // If sending a command resulted in an exception, notify the client.
+ handle.fRequestMonitor.setStatus(new Status(
+ IStatus.ERROR, PDAPlugin.PLUGIN_ID, REQUEST_FAILED, "Exception reading request response", exception));
+ handle.fRequestMonitor.done();
+
+ // Notify listeners also.
+ for (ICommandListener listener : fCommandListeners) {
+ listener.commandDone(handle.fToken, null);
+ }
+ }
+
+ private void processEventReceived(String event) {
+ // Notify the listeners only.
+ PDAPlugin.debug("E: " + event);
+ for (IEventListener listener : fEventListeners) {
+ listener.eventReceived(event);
+ }
+ }
+
+ private synchronized void processQueues() {
+ if (isTerminated()) {
+ // If the PDA debugger is terminated. Return all submitted commands
+ // with an error.
+ for (CommandHandle handle : fCommandQueue) {
+ handle.fRequestMonitor.setStatus(new Status(
+ IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_STATE, "Command control is terminated", null));
+ handle.fRequestMonitor.done();
+ }
+ fCommandQueue.clear();
+ } else if (fStarted && fTxCommands.isEmpty() && !fCommandQueue.isEmpty()) {
+ // Process the queues if:
+ // - the PDA debugger has started,
+ // - there are no pending commands in the send queue,
+ // - and there are commands waiting to be sent.
+ CommandHandle handle = fCommandQueue.remove(0);
+ fTxCommands.add(handle);
+ PDAPlugin.debug("C: " + handle.fCommand.getRequest());
+ for (ICommandListener listener : fCommandListeners) {
+ listener.commandSent(handle.fToken);
+ }
+ }
+ }
+
+ /**
+ * Return the PDA Debugger top-level Data Model context.
+ * @see PDAVirtualMachineDMContext
+ */
+ @ThreadSafe
+ public PDAVirtualMachineDMContext getContext() {
+ return fDMContext;
+ }
+
+ public String getId() {
+ return fBackend.getPorgramName();
+ }
+
+ private void setStarted() {
+ // Mark the command control as started and ready to process commands.
+ fStarted = true;
+
+ // Process any commands which may have been queued before the
+ processQueues();
+
+ // Issue a data model event.
+ getSession().dispatchEvent(new PDAStartedEvent(getContext()), getProperties());
+ }
+
+ /**
+ * Returns whether the PDA debugger has started and is processing commands.
+ */
+ public boolean isActive() {
+ return fStarted && !isTerminated();
+ }
+
+
+ @ThreadSafe
+ private synchronized void setTerminated() {
+ // Set terminated may be called more than once: by event listener thread,
+ // by the terminate command, etc, so protect against sending events multiple
+ // times.
+ if (!fTerminated) {
+ fTerminated = true;
+
+ // Process any waiting commands, they all should return with an error.
+ processQueues();
+
+ // Issue a data model event.
+ getSession().dispatchEvent(new PDATerminatedEvent(getContext()), getProperties());
+ }
+ }
+
+ /**
+ * Returns whether the PDA debugger has been terminated.
+ */
+ @ThreadSafe
+ public synchronized boolean isTerminated() {
+ return fTerminated;
+ }
+
+ /**
+ * Sends a command to PDA debugger to terminate.
+ */
+ public void terminate(RequestMonitor rm) {
+ if (!isTerminated()) {
+ queueCommand(
+ new PDAExitCommand(fDMContext),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));
+ } else {
+ // If already terminated, indicate success.
+ rm.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java
new file mode 100644
index 00000000000..d7991483bc7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAExpressions.java
@@ -0,0 +1,554 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IRegisters.IRegisterDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAChildrenCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAListResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDASetVarCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAVarCommand;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+public class PDAExpressions extends AbstractDsfService implements ICachingService, IExpressions {
+
+ @Immutable
+ private static class ExpressionDMContext extends AbstractDMContext implements IExpressionDMContext {
+
+ final private String fExpression;
+
+ ExpressionDMContext(String sessionId, IFrameDMContext frameDmc, String expressin) {
+ super(sessionId, new IDMContext[] { frameDmc });
+ fExpression = expressin;
+ }
+
+ public String getExpression() {
+ return fExpression;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return super.baseEquals(other) && ((ExpressionDMContext)other).fExpression.equals(fExpression);
+ }
+
+ @Override
+ public int hashCode() {
+ return super.baseHashCode() + fExpression.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".expression(" + fExpression + ")";
+ }
+ }
+
+ /**
+ * PDA expressions are simply variables. Only the variable name
+ * is relevant for its data.
+ */
+ @Immutable
+ private static class ExpressionDMData implements IExpressionDMData {
+
+ final private String fExpression;
+
+ public ExpressionDMData(String expression) {
+ fExpression = expression;
+ }
+
+ public BasicType getBasicType() {
+ return BasicType.basic;
+ }
+
+ public String getEncoding() {
+ return null;
+ }
+
+ public Map<String, Integer> getEnumerations() {
+ return null;
+ }
+
+ public String getName() {
+ return fExpression;
+ }
+
+ public IRegisterDMContext getRegister() {
+ return null;
+ }
+
+ public String getStringValue() {
+ return null;
+ }
+
+ public String getTypeId() {
+ return null;
+ }
+
+ public String getTypeName() {
+ return null;
+ }
+
+ }
+
+ // @see #createExpression()
+ @Immutable
+ private static class InvalidExpressionDMContext extends AbstractDMContext implements IExpressionDMContext {
+ final private String fExpression;
+
+ public InvalidExpressionDMContext(String sessionId, IDMContext parent, String expr) {
+ super(sessionId, new IDMContext[] { parent });
+ fExpression = expr;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return super.baseEquals(other) &&
+ fExpression == null
+ ? ((InvalidExpressionDMContext) other).getExpression() == null
+ : fExpression.equals(((InvalidExpressionDMContext) other).getExpression());
+ }
+
+ @Override
+ public int hashCode() {
+ return fExpression == null ? super.baseHashCode() : super.baseHashCode() ^ fExpression.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".invalid_expr[" + fExpression + "]";
+ }
+
+ public String getExpression() {
+ return fExpression;
+ }
+ }
+
+ @Immutable
+ private static class ExpressionChangedDMEvent extends AbstractDMEvent<IExpressionDMContext>
+ implements IExpressionChangedDMEvent
+ {
+ ExpressionChangedDMEvent(IExpressionDMContext expression) {
+ super(expression);
+ }
+ }
+
+
+ private PDACommandControl fCommandControl;
+ private PDAStack fStack;
+
+ private CommandCache fCommandCache;
+
+ public PDAExpressions(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }});
+ }
+
+ private void doInitialize(final RequestMonitor rm) {
+ fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+ fStack = getServicesTracker().getService(PDAStack.class);
+ fCommandCache = new CommandCache(getSession(), fCommandControl);
+
+ getSession().addServiceEventListener(this, null);
+
+ register(new String[]{IExpressions.class.getName(), PDAExpressions.class.getName()}, new Hashtable<String,String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ getSession().removeServiceEventListener(this);
+ fCommandCache.reset();
+ super.shutdown(rm);
+ }
+
+ public void canWriteExpression(IExpressionDMContext expressionContext, DataRequestMonitor<Boolean> rm) {
+ rm.setData(true);
+ rm.done();
+ }
+
+ public IExpressionDMContext createExpression(IDMContext ctx, String expression) {
+ // Create an expression based on the given context and string expression.
+ PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class);
+ if (threadCtx != null) {
+ // The PDA debugger can only evaluate variables as expressions and only
+ // in context of a frame, so if a frame is not given, create a top-level frame.
+ IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);
+ if (frameCtx == null) {
+ frameCtx = fStack.getFrameDMContext(threadCtx, 0);
+ }
+
+ return new ExpressionDMContext(getSession().getId(), frameCtx, expression);
+ }
+
+ // If the thread cannot be found in context, return an "invalid"
+ // expression context, because a null return value is not allowed.
+ // Evaluating an invalid expression context will always yield an
+ // error.
+ return new InvalidExpressionDMContext(getSession().getId(), ctx, expression);
+ }
+
+ public void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor<IExpressionDMContext[]> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Not supported");
+ }
+
+ public void getExpressionAddressData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMAddress> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Not supported");
+ }
+
+ public void getExpressionData(final IExpressionDMContext exprCtx, final DataRequestMonitor<IExpressionDMData> rm) {
+ // Since expression data doesn't contain any more information than the
+ // context, it doesn't require any debugger commmands.
+ if (exprCtx instanceof ExpressionDMContext) {
+ rm.setData(new ExpressionDMData(exprCtx.getExpression()));
+ rm.done();
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid expression context " + exprCtx);
+ }
+ }
+
+ public void getSubExpressionCount(final IExpressionDMContext exprCtx, final DataRequestMonitor<Integer> rm) {
+ if (exprCtx instanceof ExpressionDMContext) {
+ final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
+ final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
+
+ // First retrieve the stack depth, needed to properly calculate
+ // the frame index that is used by the PDAVarCommand.
+ fStack.getStackDepth(
+ frameCtx, 0,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Calculate the frame index.
+ int frameId = getData() - frameCtx.getLevel() - 1;
+
+ // Send the command to evaluate the variable.
+ fCommandCache.execute(
+ new PDAChildrenCommand(threadCtx, frameId, exprCtx.getExpression()),
+ new DataRequestMonitor<PDAListResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData().fValues.length);
+ rm.done();
+ }
+ });
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context");
+ }
+ }
+
+ public void getSubExpressions(IExpressionDMContext exprCtx, DataRequestMonitor<IExpressionDMContext[]> rm) {
+ getSubExpressions(exprCtx, -1, -1, rm);
+ }
+
+ public void getSubExpressions(final IExpressionDMContext exprCtx, final int startIndexArg, final int lengthArg,
+ final DataRequestMonitor<IExpressionDMContext[]> rm)
+ {
+ if (exprCtx instanceof ExpressionDMContext) {
+ final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
+ final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
+
+ // First retrieve the stack depth, needed to properly calculate
+ // the frame index that is used by the PDAVarCommand.
+ fStack.getStackDepth(
+ frameCtx, 0,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Calculate the frame index.
+ int frameId = getData() - frameCtx.getLevel() - 1;
+
+ // Send the command to evaluate the variable.
+ fCommandCache.execute(
+ new PDAChildrenCommand(threadCtx, frameId, exprCtx.getExpression()),
+ new DataRequestMonitor<PDAListResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ int start = startIndexArg > 0 ? startIndexArg : 0;
+ int end = lengthArg > 0 ? (start + lengthArg) : getData().fValues.length;
+ IExpressionDMContext[] contexts = new IExpressionDMContext[end - start];
+ for (int i = start; i < end && i < getData().fValues.length; i++) {
+ contexts[i] = new ExpressionDMContext(
+ getSession().getId(), frameCtx, getData().fValues[i]);
+ }
+ rm.setData(contexts);
+ rm.done();
+ }
+ });
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context");
+ }
+ }
+
+ public void getAvailableFormats(IFormattedDataDMContext dmc, final DataRequestMonitor<String[]> rm) {
+ getFormattedExpressionValue(
+ new FormattedValueDMContext(this, dmc, NATURAL_FORMAT),
+ new DataRequestMonitor<FormattedValueDMData>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ try {
+ Integer.parseInt(getData().getFormattedValue());
+ rm.setData(new String[] { NATURAL_FORMAT, STRING_FORMAT, HEX_FORMAT, DECIMAL_FORMAT, OCTAL_FORMAT, BINARY_FORMAT });
+ rm.done();
+ } catch (NumberFormatException e) {
+ rm.setData(new String[] { NATURAL_FORMAT, STRING_FORMAT });
+ rm.done();
+ }
+ }
+
+ @Override
+ protected void handleErrorOrWarning() {
+ rm.setData(new String[] { NATURAL_FORMAT, STRING_FORMAT });
+ rm.done();
+ }
+ });
+ }
+
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext exprCtx, String formatId) {
+ // Creates a context that can be used to retrieve a formatted value.
+ return new FormattedValueDMContext(this, exprCtx, formatId);
+ }
+
+ public void getFormattedExpressionValue(FormattedValueDMContext formattedCtx,
+ final DataRequestMonitor<FormattedValueDMData> rm)
+ {
+ final String formatId = formattedCtx.getFormatID();
+ final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class);
+ if (exprCtx != null) {
+ final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
+ final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
+
+ // First retrieve the stack depth, needed to properly calculate
+ // the frame index that is used by the PDAVarCommand.
+ fStack.getStackDepth(
+ frameCtx, 0,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Calculate the frame index.
+ int frameId = getData() - frameCtx.getLevel() - 1;
+
+ // Send the command to evaluate the variable.
+ fCommandCache.execute(
+ new PDAVarCommand(threadCtx, frameId, exprCtx.getExpression()),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ if (NATURAL_FORMAT.equals(formatId) || STRING_FORMAT.equals(formatId)) {
+ rm.setData(new FormattedValueDMData(getData().fResponseText));
+ rm.done();
+ } else {
+ int result;
+ try {
+ int intResult = Integer.parseInt(getData().fResponseText);
+ String formattedResult = "";
+ if (HEX_FORMAT.equals(formatId)) {
+ formattedResult = Integer.toHexString(intResult);
+ StringBuffer prefix = new StringBuffer("0x");
+ for (int i = 0; i < 8 - formattedResult.length(); i++) {
+ prefix.append('0');
+ }
+ prefix.append(formattedResult);
+ formattedResult = prefix.toString();
+ } else if (OCTAL_FORMAT.equals(formatId)) {
+ formattedResult = Integer.toOctalString(intResult);
+ StringBuffer prefix = new StringBuffer("0c");
+ for (int i = 0; i < 16 - formattedResult.length(); i++) {
+ prefix.append('0');
+ }
+ prefix.append(formattedResult);
+ formattedResult = prefix.toString();
+ } else if (BINARY_FORMAT.equals(formatId)) {
+ formattedResult = Integer.toBinaryString(intResult);
+ StringBuffer prefix = new StringBuffer("0b");
+ for (int i = 0; i < 32 - formattedResult.length(); i++) {
+ prefix.append('0');
+ }
+ prefix.append(formattedResult);
+ formattedResult = prefix.toString();
+ } else if (DECIMAL_FORMAT.equals(formatId)) {
+ formattedResult = Integer.toString(intResult);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid format");
+ }
+ rm.setData(new FormattedValueDMData(formattedResult));
+ rm.done();
+ } catch (NumberFormatException e) {
+ PDAPlugin.failRequest(rm, REQUEST_FAILED, "Cannot format value");
+ }
+ }
+ }
+ });
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid expression context " + formattedCtx);
+ }
+ }
+
+
+ public void writeExpression(final IExpressionDMContext exprCtx, final String exprValue, String formatId,
+ final RequestMonitor rm)
+ {
+ writeExpression(exprCtx, exprValue, formatId, true, rm);
+ }
+
+ /**
+ * Method to write an expression, with an additional parameter to suppress
+ * issuing of the expression changed event.
+ * @see IExpressions#writeExpression(org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext, String, String, RequestMonitor)
+ */
+ public void writeExpression(final IExpressionDMContext exprCtx, String formattedExprValue, String formatId,
+ final boolean sendEvent, final RequestMonitor rm)
+ {
+ String value = null;
+ try {
+ int intValue = 0;
+ if (HEX_FORMAT.equals(formatId)) {
+ if (formattedExprValue.startsWith("0x")) formattedExprValue = formattedExprValue.substring(2);
+ value = Integer.toString( Integer.parseInt(formattedExprValue, 16) );
+ } else if (DECIMAL_FORMAT.equals(formatId)) {
+ value = Integer.toString( Integer.parseInt(formattedExprValue, 10) );
+ } else if (OCTAL_FORMAT.equals(formatId)) {
+ if (formattedExprValue.startsWith("0c")) formattedExprValue = formattedExprValue.substring(2);
+ value = Integer.toString( Integer.parseInt(formattedExprValue, 8) );
+ } else if (BINARY_FORMAT.equals(formatId)) {
+ if (formattedExprValue.startsWith("0b")) formattedExprValue = formattedExprValue.substring(2);
+ value = Integer.toString( Integer.parseInt(formattedExprValue, 2) );
+ }
+ } catch (NumberFormatException e) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Value not formatted properly");
+ return;
+ }
+
+ final String exprValue = value != null ? value : formattedExprValue;
+
+
+ if (exprCtx instanceof ExpressionDMContext) {
+ final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
+ final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
+
+ // Similarly to retrieving the variable, retrieve the
+ // stack depth first.
+ fStack.getStackDepth(
+ frameCtx, 0,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Calculate the frame index.
+ int frameId = getData() - frameCtx.getLevel() - 1;
+
+ // Send the "write" command to PDA debugger
+ fCommandCache.execute(
+ new PDASetVarCommand( threadCtx, frameId, exprCtx.getExpression(), exprValue),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ if (sendEvent) {
+ getSession().dispatchEvent(new ExpressionChangedDMEvent(exprCtx), getProperties());
+ }
+ // An expression changed, clear the cache corresponding to
+ // this event. Since the var evaluate commands, use the thread
+ // context, we have to clear all the cache entries for that thread.
+ fCommandCache.reset(DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class));
+ rm.done();
+ }
+ });
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid expression context " + exprCtx);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Deprecated
+ public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+ if (dmc instanceof IExpressionDMContext) {
+ getExpressionData((IExpressionDMContext) dmc, (DataRequestMonitor<IExpressionDMData>) rm);
+ } else if (dmc instanceof FormattedValueDMContext) {
+ getFormattedExpressionValue((FormattedValueDMContext) dmc, (DataRequestMonitor<FormattedValueDMData>) rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type");
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IResumedDMEvent e) {
+ // Mark the cache as not available, so that data retrieval commands
+ // will fail. Also reset the cache unless it was a step command.
+ fCommandCache.setContextAvailable(e.getDMContext(), false);
+ if (!e.getReason().equals(StateChangeReason.STEP)) {
+ fCommandCache.reset(e.getDMContext());
+ }
+ }
+
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ISuspendedDMEvent e) {
+ // Enable sending commands to target and clear the cache.
+ fCommandCache.setContextAvailable(e.getDMContext(), true);
+ fCommandCache.reset(e.getDMContext());
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ExpressionChangedDMEvent e) {
+ // An expression changed, clear the cache corresponding to
+ // this event. Since the var evaluate commands, use the thread
+ // context, we have to clear all the cache entries for that thread.
+ fCommandCache.reset(DMContexts.getAncestorOfType(e.getDMContext(), PDAThreadDMContext.class));
+ }
+
+ public void flushCache(IDMContext context) {
+ fCommandCache.reset(context);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARegisters.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARegisters.java
new file mode 100644
index 00000000000..6a1132a08b1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARegisters.java
@@ -0,0 +1,556 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IRegisters;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
+import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDABitField;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAGroupsCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAListResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegister;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegistersCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDARegistersCommandResult;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+public class PDARegisters extends AbstractDsfService
+ implements IRegisters, IEventListener, ICachingService
+{
+
+ private static class RegisterGroupDMContext extends AbstractDMContext implements IRegisterGroupDMContext {
+ final private String fName;
+
+ public RegisterGroupDMContext(String sessionId, PDAVirtualMachineDMContext dmc, String groupName) {
+ super(sessionId, new IDMContext[] { dmc });
+ fName = groupName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return ((super.baseEquals(other)) &&
+ (((RegisterGroupDMContext) other).fName.equals(fName)));
+ }
+
+ @Override
+ public int hashCode() { return super.baseHashCode() + fName.hashCode(); }
+
+ @Override
+ public String toString() { return baseToString() + ".group[" + fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private static class RegisterDMContext extends AbstractDMContext implements IRegisterDMContext {
+ final private PDARegister fRegister;
+
+ public RegisterDMContext(String sessionId, PDAThreadDMContext thread, RegisterGroupDMContext group, PDARegister reg) {
+ super(sessionId, new IDMContext[] { thread, group });
+ fRegister = reg;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return ((super.baseEquals(other)) &&
+ (((RegisterDMContext) other).fRegister.fName.equals(fRegister.fName)));
+ }
+
+ @Override
+ public int hashCode() { return super.baseHashCode() + fRegister.fName.hashCode(); }
+ @Override
+ public String toString() { return baseToString() + ".register[" + fRegister.fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /*
+ * Support class used to construct BitField DMCs.
+ */
+ private static class BitFieldDMContext extends AbstractDMContext implements IBitFieldDMContext {
+
+ final private PDABitField fBitField;
+
+ public BitFieldDMContext(String sessionId, RegisterDMContext reg, PDABitField bitField) {
+ super(sessionId, new IDMContext[] { reg });
+
+ fBitField = bitField;
+ }
+
+ /*
+ * Required common manipulation routines.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof BitFieldDMContext) {
+ BitFieldDMContext dmc = (BitFieldDMContext) other;
+ return( (super.baseEquals(other)) &&
+ (dmc.fBitField.fName.equals(fBitField.fName)));
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() { return super.baseHashCode() + fBitField.fName.hashCode(); }
+
+ @Override
+ public String toString() { return baseToString() + ".bitfield[" + fBitField.fName + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private static class RegisterGroupDMData implements IRegisterGroupDMData {
+
+ final private String fName;
+
+ public RegisterGroupDMData(String name) {
+ fName = name;
+ }
+ public String getName() { return fName; }
+ public String getDescription() { return "Description of the " + fName + " register group"; }
+ }
+
+ private static class RegisterDMData implements IRegisterDMData {
+
+ final private PDARegister fRegister;
+
+ public RegisterDMData(PDARegister reg) {
+ fRegister = reg;
+ }
+
+ public boolean isReadable() { return true; }
+ public boolean isReadOnce() { return false; }
+ public boolean isWriteable() { return fRegister.fWritable; }
+ public boolean isWriteOnce() { return false; }
+ public boolean hasSideEffects() { return false; }
+ public boolean isVolatile() { return true; }
+
+ public boolean isFloat() { return false; }
+ public String getName() { return fRegister.fName; }
+ public String getDescription() { return "Description of the " + fRegister.fName + " register"; }
+ }
+
+ private static class Mnemonic implements IMnemonic {
+ Mnemonic(String name, String value, int numBits) {
+ fName = name;
+ fValue = new BigInteger(value);
+ fNumBits = numBits;
+ }
+ final private String fName;
+ final private BigInteger fValue;
+ final private int fNumBits;
+
+ public String getShortName() { return fName; }
+ public String getLongName() { return fName; }
+
+ public BigInteger getValue() { return fValue; }
+ public int getBitCount() { return fNumBits; }
+
+ @Override
+ public boolean equals( Object element ) {
+ if ( element instanceof Mnemonic ) {
+ Mnemonic mnem = (Mnemonic) element;
+ return ( mnem.fName.equals( fName ) ) &&
+ ( mnem.fValue.equals( fValue ) ) &&
+ ( mnem.fNumBits == fNumBits );
+ }
+ return false ;
+ }
+ }
+
+ private class BitFieldDMData implements IBitFieldDMData {
+
+ final private PDABitField fBitField;
+ final private IBitGroup[] fBitGroups;
+ final private Mnemonic[] fMnemonics;
+ final private BigInteger fValue;
+ final private Mnemonic fMnemonicValue;
+
+ public BitFieldDMData(PDABitField bitField, String value) {
+ fBitField = bitField;
+ fValue = new BigInteger(value);
+
+ fBitGroups = new IBitGroup[] {
+ new IBitGroup() {
+ public int startBit() { return fBitField.fOffset; }
+ public int bitCount() { return fBitField.fCount; }
+ }
+ };
+
+ fMnemonics = new Mnemonic[fBitField.fMnemonics.size()];
+ Mnemonic mnemonicValue = null;
+ int i = 0;
+ for (Map.Entry<String, String> mnemonicEntry : fBitField.fMnemonics.entrySet()) {
+ fMnemonics[i] = new Mnemonic(mnemonicEntry.getKey(), mnemonicEntry.getValue(), fBitField.fCount);
+ if (fValue.equals(fMnemonics[i].fValue)) {
+ mnemonicValue = fMnemonics[i];
+ }
+ i++;
+ }
+ fMnemonicValue = mnemonicValue;
+ }
+
+
+ public IBitGroup[] getBitGroup() { return fBitGroups; }
+ public IMnemonic[] getMnemonics() { return fMnemonics; }
+
+ public boolean isZeroBasedNumbering() { return true; }
+ public boolean isZeroBitLeftMost() { return true; }
+ public boolean isReadable() { return true; }
+ public boolean isReadOnce() { return false; }
+ public boolean isWriteable() { return true; }
+ public boolean isWriteOnce() { return false; }
+ public boolean hasSideEffects() { return false; }
+ public boolean isFloat() { return false; }
+
+ public String getName() { return fBitField.fName; }
+ public String getDescription() { return "Description of the " + fBitField.fName + " bit field"; }
+
+ public IMnemonic getCurrentMnemonicValue() { return fMnemonicValue; }
+ }
+
+ private static class RegisterChangedDMEvent extends AbstractDMEvent<IRegisterDMContext> implements IRegisterChangedDMEvent {
+ RegisterChangedDMEvent(IRegisterDMContext registerDmc) {
+ super(registerDmc);
+ }
+ }
+
+ private PDACommandControl fCommandControl;
+ private PDAExpressions fExpressions;
+ private CommandCache fNamesCache;
+
+ public PDARegisters(DsfSession session)
+ {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext()
+ {
+ return PDAPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+
+ fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+ fExpressions = getServicesTracker().getService(PDAExpressions.class);
+
+ // Create the cache to store the register definitions. This cache
+ // only needs to be reset upon the "registers" event and is available
+ // all the time.
+ fNamesCache = new CommandCache(getSession(), fCommandControl);
+ fNamesCache.setContextAvailable(fCommandControl.getContext(), true);
+
+ // Add the register service as a listener to PDA events, to catch
+ // the "registers" events from the command control.
+ fCommandControl.addEventListener(this);
+
+ // Sign up so we see events. We use these events to decide how to manage
+ // any local caches we are providing as well as the lower level register
+ // cache we create to get/set registers on the target.
+ getSession().addServiceEventListener(this, null);
+
+ // Make ourselves known so clients can use us.
+ register(new String[]{IRegisters.class.getName(), PDARegisters.class.getName()}, new Hashtable<String,String>());
+
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor)
+ {
+ unregister();
+ fCommandControl.removeEventListener(this);
+ getSession().removeServiceEventListener(this);
+ super.shutdown(requestMonitor);
+ }
+
+ public void getRegisterGroups(IDMContext ctx, final DataRequestMonitor<IRegisterGroupDMContext[]> rm ) {
+ final PDAVirtualMachineDMContext dmc = DMContexts.getAncestorOfType(ctx, PDAVirtualMachineDMContext.class);
+ if (dmc == null) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Container context not found"); //$NON-NLS-1$
+ return;
+ }
+
+ fNamesCache.execute(
+ new PDAGroupsCommand(dmc),
+ new DataRequestMonitor<PDAListResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ IRegisterGroupDMContext[] groups = new IRegisterGroupDMContext[getData().fValues.length];
+ for (int i = 0; i < getData().fValues.length; i++) {
+ groups[i] = new RegisterGroupDMContext(getSession().getId(), dmc, getData().fValues[i]);
+ }
+ rm.setData(groups);
+ rm.done();
+ };
+ });
+ }
+
+ public void getRegisters(final IDMContext ctx, final DataRequestMonitor<IRegisterDMContext[]> rm) {
+ final PDAThreadDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class);
+ if ( execDmc == null ) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE , "Thread context not found"); //$NON-NLS-1$
+ return;
+ }
+
+ final RegisterGroupDMContext groupDmc = DMContexts.getAncestorOfType(ctx, RegisterGroupDMContext.class);
+ if ( groupDmc == null ) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE , "Group context not found"); //$NON-NLS-1$
+ return;
+ }
+
+ fNamesCache.execute(
+ new PDARegistersCommand(execDmc, groupDmc != null ? groupDmc.fName : null),
+ new DataRequestMonitor<PDARegistersCommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ IRegisterDMContext[] groups = new IRegisterDMContext[getData().fRegisters.length];
+ for (int i = 0; i < getData().fRegisters.length; i++) {
+ groups[i] = new RegisterDMContext(getSession().getId(), execDmc, groupDmc, getData().fRegisters[i]);
+ }
+ rm.setData(groups);
+ rm.done();
+ };
+ });
+
+ }
+
+ public void getBitFields( IDMContext dmc , DataRequestMonitor<IBitFieldDMContext[]> rm ) {
+
+ RegisterDMContext registerDmc = DMContexts.getAncestorOfType(dmc, RegisterDMContext.class);
+
+ if ( registerDmc == null ) {
+ PDAPlugin.failRequest(rm,INVALID_HANDLE, "No register in context: " + dmc) ; //$NON-NLS-1$
+ return;
+ }
+
+ PDABitField[] bitFields = registerDmc.fRegister.fBitFields;
+ BitFieldDMContext[] bitFieldDMCs = new BitFieldDMContext[bitFields.length];
+
+ for (int i = 0; i < bitFields.length; i++) {
+ bitFieldDMCs[i] = new BitFieldDMContext(getSession().getId(), registerDmc, bitFields[i]);
+ }
+
+ rm.setData(bitFieldDMCs) ;
+ rm.done();
+ }
+
+ public void writeRegister(final IRegisterDMContext regCtx, String regValue, String formatId, final RequestMonitor rm) {
+ if (regCtx instanceof RegisterDMContext) {
+ IExpressionDMContext exprCtx = createRegisterExpressionDmc( (RegisterDMContext)regCtx );
+ fExpressions.writeExpression(
+ exprCtx, regValue, formatId, false,
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ generateRegisterChangedEvent( (RegisterDMContext)regCtx );
+ rm.done();
+ }
+ });
+
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$
+ }
+
+ }
+
+ public void writeBitField(final IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, final RequestMonitor rm) {
+ if (bitFieldCtx instanceof BitFieldDMContext) {
+ IExpressionDMContext exprCtx = createBitFieldExpressionDmc( (BitFieldDMContext)bitFieldCtx );
+ fExpressions.writeExpression(
+ exprCtx, bitFieldValue, formatId, false,
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ generateRegisterChangedEvent(
+ DMContexts.getAncestorOfType(bitFieldCtx, RegisterDMContext.class) );
+ rm.done();
+ }
+ });
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$
+ }
+ }
+
+ public void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm) {
+ if (mnemonic instanceof Mnemonic) {
+ writeBitField(bitFieldCtx, ((Mnemonic)mnemonic).fValue.toString(), NATURAL_FORMAT, rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid mnemonic"); //$NON-NLS-1$
+ }
+ }
+
+ public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm) {
+ IExpressionDMContext exprCtx = null;
+ if ( dmc instanceof RegisterDMContext ) {
+ exprCtx = createRegisterExpressionDmc((RegisterDMContext)dmc);
+ } else if ( dmc instanceof BitFieldDMContext ) {
+ exprCtx = createBitFieldExpressionDmc((BitFieldDMContext)dmc);
+ }
+ if (exprCtx != null) {
+ fExpressions.getAvailableFormats(exprCtx, rm);
+ } else {
+ throw new IllegalArgumentException("Invalid register/bit field context " + dmc);
+ }
+ }
+
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId) {
+ IExpressionDMContext exprCtx = null;
+ if ( dmc instanceof RegisterDMContext ) {
+ exprCtx = createRegisterExpressionDmc((RegisterDMContext)dmc);
+ } else if ( dmc instanceof BitFieldDMContext ) {
+ exprCtx = createBitFieldExpressionDmc((BitFieldDMContext)dmc);
+ }
+ if (exprCtx != null) {
+ return fExpressions.getFormattedValueContext(exprCtx, formatId);
+ } else {
+ throw new IllegalArgumentException("Invalid register/bit field context " + dmc);
+ }
+ }
+
+ public void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$
+ }
+
+ public void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$
+ }
+
+ public void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm) {
+ PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Finding context not supported"); //$NON-NLS-1$
+ }
+
+ @SuppressWarnings("unchecked")
+ public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+ /*
+ * This is the method which is called when actual results need to be returned. We
+ * can be called either with a service DMC for which we return ourselves or we can
+ * be called with the DMC's we have handed out. If the latter is the case then we
+ * data mine by talking to the Debug Engine.
+ */
+
+ if (dmc instanceof RegisterGroupDMContext) {
+ getRegisterGroupData((RegisterGroupDMContext)dmc, (DataRequestMonitor<IRegisterGroupDMData>)rm);
+ } else if (dmc instanceof RegisterDMContext) {
+ getRegisterData((RegisterDMContext)dmc, (DataRequestMonitor<IRegisterDMData>)rm);
+ } else if (dmc instanceof BitFieldDMContext) {
+ getBitFieldData((BitFieldDMContext) dmc, (DataRequestMonitor<IBitFieldDMData>)rm);
+ } else if (dmc instanceof FormattedValueDMContext) {
+ getFormattedExpressionValue((FormattedValueDMContext)dmc, (DataRequestMonitor<FormattedValueDMData>)rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type"); //$NON-NLS-1$
+ }
+ }
+
+ public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm) {
+ fExpressions.getFormattedExpressionValue(dmc, rm);
+ }
+
+ public void getRegisterGroupData(IRegisterGroupDMContext regGroupDmc, DataRequestMonitor<IRegisterGroupDMData> rm) {
+ if (regGroupDmc instanceof RegisterGroupDMContext) {
+ rm.setData(new RegisterGroupDMData( ((RegisterGroupDMContext)regGroupDmc).fName ));
+ rm.done();
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$
+ }
+ }
+
+ public void getRegisterData(IRegisterDMContext regDmc , DataRequestMonitor<IRegisterDMData> rm) {
+ if (regDmc instanceof RegisterDMContext) {
+ rm.setData(new RegisterDMData( ((RegisterDMContext)regDmc).fRegister ));
+ rm.done();
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$
+ }
+ }
+
+ public void getBitFieldData(IBitFieldDMContext dmc, final DataRequestMonitor<IBitFieldDMData> rm) {
+ if ( !(dmc instanceof BitFieldDMContext) ) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid context"); //$NON-NLS-1$
+ }
+ final BitFieldDMContext bitFieldDmc = (BitFieldDMContext) dmc;
+
+ IExpressionDMContext bitFieldExprDmc = createBitFieldExpressionDmc(bitFieldDmc);
+ FormattedValueDMContext formattedBitFieldDmc =
+ fExpressions.getFormattedValueContext(bitFieldExprDmc, NATURAL_FORMAT);
+ fExpressions.getFormattedExpressionValue(
+ formattedBitFieldDmc,
+ new DataRequestMonitor<FormattedValueDMData>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(new BitFieldDMData(bitFieldDmc.fBitField, getData().getFormattedValue()));
+ rm.done();
+ }
+ });
+ }
+
+ private IExpressionDMContext createRegisterExpressionDmc(RegisterDMContext dmc) {
+ return fExpressions.createExpression(dmc, "$" + dmc.fRegister.fName);
+ }
+
+ private IExpressionDMContext createBitFieldExpressionDmc(BitFieldDMContext dmc) {
+ RegisterDMContext regDmc = DMContexts.getAncestorOfType(dmc, RegisterDMContext.class);
+ return fExpressions.createExpression(dmc, "$" + regDmc.fRegister.fName + "." + dmc.fBitField.fName);
+ }
+
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.IResumedDMEvent e) {
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(
+ IRunControl.ISuspendedDMEvent e) {
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final IRegisters.IRegisterChangedDMEvent e) {
+ }
+
+ private void generateRegisterChangedEvent(RegisterDMContext dmc ) {
+ getSession().dispatchEvent(new RegisterChangedDMEvent(dmc), getProperties());
+ }
+
+ public void eventReceived(Object output) {
+ if (!(output instanceof String)) return;
+ if ("registers".equals(output)) {
+ fNamesCache.reset();
+ }
+ }
+
+ public void flushCache(IDMContext context) {
+ fExpressions.flushCache(context);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARunControl.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARunControl.java
new file mode 100644
index 00000000000..29772539cdb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDARunControl.java
@@ -0,0 +1,672 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ * Ericsson AB - Modified for handling of multiple threads
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.service;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.AbstractPDACommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAResumeCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStepCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStepReturnCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAVMResumeCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAVMSuspendCommand;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * Service for monitoring and controlling execution state of the DPA
+ * program.
+ * <p>
+ * This service depends on the {@link PDACommandControl} service.
+ * It must be initialized before this service is initialized.
+ * </p>
+ */
+public class PDARunControl extends AbstractDsfService
+ implements IRunControl, IEventListener
+{
+ // Implementation note about tracking execution state:
+ // This class implements event handlers for the events that are generated by
+ // this service itself. When the event is dispatched, these handlers will
+ // be called first, before any of the clients. These handlers update the
+ // service's internal state information to make them consistent with the
+ // events being issued. Doing this in the handlers as opposed to when
+ // the events are generated, guarantees that the state of the service will
+ // always be consistent with the events.
+ // The purpose of this pattern is to allow clients that listen to service
+ // events and track service state, to be perfectly in sync with the service
+ // state.
+
+ static final private IExecutionDMContext[] EMPTY_TRIGGERING_CONTEXTS_ARRAY = new IExecutionDMContext[0];
+
+ @Immutable
+ private static class ThreadResumedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IResumedDMEvent
+ {
+ private final StateChangeReason fReason;
+
+ ThreadResumedEvent(PDAThreadDMContext ctx, StateChangeReason reason) {
+ super(ctx);
+ fReason = reason;
+ }
+
+ public StateChangeReason getReason() {
+ return fReason;
+ }
+
+ @Override
+ public String toString() {
+ return "THREAD RESUMED: " + getDMContext() + " (" + fReason + ")";
+ }
+ }
+
+ @Immutable
+ private static class VMResumedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IContainerResumedDMEvent
+ {
+ private final StateChangeReason fReason;
+
+ VMResumedEvent(PDAVirtualMachineDMContext ctx, StateChangeReason reason) {
+ super(ctx);
+ fReason = reason;
+ }
+
+ public StateChangeReason getReason() {
+ return fReason;
+ }
+
+ public IExecutionDMContext[] getTriggeringContexts() {
+ return EMPTY_TRIGGERING_CONTEXTS_ARRAY;
+ }
+
+ @Override
+ public String toString() {
+ return "VM RESUMED: (" + fReason + ")";
+ }
+ }
+
+ @Immutable
+ private static class ThreadSuspendedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements ISuspendedDMEvent
+ {
+ private final StateChangeReason fReason;
+
+ ThreadSuspendedEvent(PDAThreadDMContext ctx, StateChangeReason reason) {
+ super(ctx);
+ fReason = reason;
+ }
+
+ public StateChangeReason getReason() {
+ return fReason;
+ }
+
+ @Override
+ public String toString() {
+ return "THREAD SUSPENDED: " + getDMContext() + " (" + fReason + ")";
+ }
+ }
+
+ @Immutable
+ private static class VMSuspendedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IContainerSuspendedDMEvent
+ {
+ private final StateChangeReason fReason;
+
+ final private IExecutionDMContext[] fTriggeringThreads;
+
+ VMSuspendedEvent(PDAVirtualMachineDMContext ctx, PDAThreadDMContext threadCtx, StateChangeReason reason) {
+ super(ctx);
+ fReason = reason;
+ if (threadCtx != null) {
+ fTriggeringThreads = new IExecutionDMContext[] { threadCtx };
+ } else {
+ fTriggeringThreads = EMPTY_TRIGGERING_CONTEXTS_ARRAY;
+ }
+ }
+
+ public StateChangeReason getReason() {
+ return fReason;
+ }
+
+ public IExecutionDMContext[] getTriggeringContexts() {
+ return fTriggeringThreads;
+ }
+
+
+ @Override
+ public String toString() {
+ return "THREAD SUSPENDED: " + getDMContext() +
+ " (" + fReason +
+ ", trigger = " + Arrays.asList(fTriggeringThreads) +
+ ")";
+ }
+ }
+
+ @Immutable
+ private static class ExecutionDMData implements IExecutionDMData {
+ private final StateChangeReason fReason;
+ ExecutionDMData(StateChangeReason reason) {
+ fReason = reason;
+ }
+ public StateChangeReason getStateChangeReason() { return fReason; }
+ }
+
+ private static class ThreadStartedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IStartedDMEvent
+ {
+ ThreadStartedEvent(PDAThreadDMContext threadCtx) {
+ super(threadCtx);
+ }
+ }
+
+ private static class ThreadExitedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IExitedDMEvent
+ {
+ ThreadExitedEvent(PDAThreadDMContext threadCtx) {
+ super(threadCtx);
+ }
+ }
+
+ // Services
+ private PDACommandControl fCommandControl;
+
+ // Reference to the virtual machine data model context
+ private PDAVirtualMachineDMContext fDMContext;
+
+ // VM state flags
+ private boolean fVMSuspended = true;
+ private boolean fVMResumePending = false;
+ private boolean fVMSuspendPending = false;
+ private boolean fVMStepping = false;
+ private StateChangeReason fVMStateChangeReason;
+
+ // Threads' state data
+ private static class ThreadInfo {
+ final PDAThreadDMContext fContext;
+ boolean fSuspended = false;
+ boolean fResumePending = false;
+ boolean fSuspendPending = false;
+ boolean fStepping = false;
+ StateChangeReason fStateChangeReason = StateChangeReason.UNKNOWN;
+
+ ThreadInfo(PDAThreadDMContext context) {
+ fContext = context;
+ }
+
+ @Override
+ public String toString() {
+ return fContext.toString() + " (" +
+ (fSuspended ? "SUSPENDED, " : "SUSPENDED, ") +
+ fStateChangeReason +
+ (fResumePending ? ", RESUME_PENDING, " : "") +
+ (fSuspendPending ? ", SUSPEND_PENDING, " : "") +
+ (fStepping ? ", SUSPEND_PENDING, " : "") +
+ ")";
+
+ }
+ }
+
+ private Map<Integer, ThreadInfo> fThreads = new LinkedHashMap<Integer, ThreadInfo>();
+
+
+ public PDARunControl(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }});
+ }
+
+ private void doInitialize(final RequestMonitor rm) {
+ // Cache a reference to the command control and the virtual machine context
+ fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+ fDMContext = fCommandControl.getContext();
+
+ // Create the main thread context.
+ fThreads.put(
+ 1,
+ new ThreadInfo(new PDAThreadDMContext(getSession().getId(), fDMContext, 1)));
+
+ // Add the run control service as a listener to PDA events, to catch
+ // suspended/resumed/started/exited events from the command control.
+ fCommandControl.addEventListener(this);
+
+ // Add the run control service as a listener to service events as well,
+ // in order to process our own suspended/resumed/started/exited events.
+ getSession().addServiceEventListener(this, null);
+
+ // Register the service with OSGi
+ register(new String[]{IRunControl.class.getName(), PDARunControl.class.getName()}, new Hashtable<String,String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ fCommandControl.removeEventListener(this);
+ getSession().removeServiceEventListener(this);
+ super.shutdown(rm);
+ }
+
+ @Deprecated
+ @SuppressWarnings("unchecked")
+ public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+ // The getModelData() is deprecated and clients are expected to switch
+ // to getExecutionData() and other data retrieve methods directly.
+ // However the UI cache still uses it for now.
+ if (dmc instanceof IExecutionDMContext) {
+ getExecutionData((IExecutionDMContext)dmc, (DataRequestMonitor<IExecutionDMData>)rm);
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type");
+ }
+ }
+
+ public void eventReceived(Object output) {
+ if (!(output instanceof String)) return;
+ String event = (String)output;
+
+ int nameEnd = event.indexOf(' ');
+ nameEnd = nameEnd == -1 ? event.length() : nameEnd;
+ String eventName = event.substring(0, nameEnd);
+
+ PDAThreadDMContext thread = null;
+ StateChangeReason reason = StateChangeReason.UNKNOWN;
+ if (event.length() > nameEnd + 1) {
+ if ( Character.isDigit(event.charAt(nameEnd + 1)) ) {
+ int threadIdEnd = event.indexOf(' ', nameEnd + 1);
+ threadIdEnd = threadIdEnd == -1 ? event.length() : threadIdEnd;
+ try {
+ int threadId = Integer.parseInt(event.substring(nameEnd + 1, threadIdEnd));
+ if (fThreads.containsKey(threadId)) {
+ thread = fThreads.get(threadId).fContext;
+ } else {
+ // In case where a suspended event follows directly a
+ // started event, a thread may not be in the list of
+ // known threads yet. In this case create the
+ // thread context based on the ID.
+ thread = new PDAThreadDMContext(getSession().getId(), fDMContext, threadId);
+ }
+ } catch (NumberFormatException e) {}
+ if (threadIdEnd + 1 < event.length()) {
+ reason = parseStateChangeReason(event.substring(threadIdEnd + 1));
+ }
+ } else {
+ reason = parseStateChangeReason(event.substring(nameEnd + 1));
+ }
+ }
+
+ // Handle PDA debugger suspended/resumed events and issue the
+ // corresponding Data Model events. Do not update the state
+ // information until we start dispatching the service events.
+ IDMEvent<?> dmEvent = null;
+ if (eventName.equals("suspended") && thread != null) {
+ dmEvent = new ThreadSuspendedEvent(thread, reason);
+ } else if (eventName.equals("resumed") && thread != null) {
+ dmEvent = new ThreadResumedEvent(thread, reason);
+ } else if (event.startsWith("vmsuspended")) {
+ dmEvent = new VMSuspendedEvent(fDMContext, thread, reason);
+ } else if (event.startsWith("vmresumed")) {
+ dmEvent = new VMResumedEvent(fDMContext, reason);
+ } else if (event.startsWith("started") && thread != null) {
+ dmEvent = new ThreadStartedEvent(thread);
+ } else if (event.startsWith("exited") && thread != null) {
+ dmEvent = new ThreadExitedEvent(thread);
+ }
+
+ if (dmEvent != null) {
+ getSession().dispatchEvent(dmEvent, getProperties());
+ }
+ }
+
+ private StateChangeReason parseStateChangeReason(String reasonString) {
+ if (reasonString.startsWith("breakpoint") || reasonString.startsWith("watch")) {
+ return StateChangeReason.BREAKPOINT;
+ } else if (reasonString.equals("step") || reasonString.equals("drop")) {
+ return StateChangeReason.STEP;
+ } else if (reasonString.equals("client")) {
+ return StateChangeReason.USER_REQUEST;
+ } else if (reasonString.startsWith("event")) {
+ return StateChangeReason.SIGNAL;
+ } else {
+ return StateChangeReason.UNKNOWN;
+ }
+
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ThreadResumedEvent e) {
+ ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID());
+ if (info != null) {
+ info.fSuspended = false;
+ info.fResumePending = false;
+ info.fStateChangeReason = e.getReason();
+ info.fStepping = e.getReason().equals(StateChangeReason.STEP);
+ }
+ }
+
+
+ @DsfServiceEventHandler
+ public void eventDispatched(VMResumedEvent e) {
+ fVMSuspended = false;
+ fVMResumePending = false;
+ fVMStateChangeReason = e.getReason();
+ fVMStepping = e.getReason().equals(StateChangeReason.STEP);
+ for (ThreadInfo info : fThreads.values()) {
+ info.fSuspended = false;
+ info.fStateChangeReason = StateChangeReason.CONTAINER;
+ info.fStepping = false;
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ThreadSuspendedEvent e) {
+ ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID());
+ if (info != null) {
+ info.fSuspended = true;
+ info.fSuspendPending = false;
+ info.fStateChangeReason = e.getReason();
+ info.fStepping = e.getReason().equals(StateChangeReason.STEP);
+ }
+ }
+
+
+ @DsfServiceEventHandler
+ public void eventDispatched(VMSuspendedEvent e) {
+ fVMStateChangeReason = e.getReason();
+ fVMSuspendPending = false;
+ fVMSuspended = true;
+ fVMStepping = false;
+ List<IExecutionDMContext> triggeringContexts = Arrays.asList(e.getTriggeringContexts());
+ for (ThreadInfo info : fThreads.values()) {
+ info.fSuspended = true;
+ info.fStateChangeReason = triggeringContexts.contains(info.fContext)
+ ? StateChangeReason.STEP : StateChangeReason.CONTAINER;
+ info.fStepping = false;
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ThreadStartedEvent e) {
+ PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext();
+ fThreads.put(threadCtx.getID(), new ThreadInfo(threadCtx));
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ThreadExitedEvent e) {
+ PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext();
+ fThreads.remove(threadCtx.getID());
+ }
+
+ public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
+ rm.setData(doCanResume(context));
+ rm.done();
+ }
+
+ private boolean doCanResume(IExecutionDMContext context) {
+ if (context instanceof PDAThreadDMContext) {
+ PDAThreadDMContext threadContext = (PDAThreadDMContext)context;
+ // Threads can be resumed only if the VM is not suspended.
+ if (!fVMSuspended) {
+ ThreadInfo state = fThreads.get(threadContext.getID());
+ if (state != null) {
+ return state.fSuspended && !state.fResumePending;
+ }
+ }
+ } else {
+ return fVMSuspended && !fVMResumePending;
+ }
+ return false;
+ }
+
+ private boolean doCanStep(IExecutionDMContext context, StepType stepType) {
+ if (stepType == StepType.STEP_OVER || stepType == StepType.STEP_RETURN) {
+ if (context instanceof PDAThreadDMContext) {
+ PDAThreadDMContext threadContext = (PDAThreadDMContext)context;
+ // Only threads can be stepped. But they can be stepped
+ // while the VM is suspended or when just the thread is suspended.
+ ThreadInfo state = fThreads.get(threadContext.getID());
+ if (state != null) {
+ return state.fSuspended && !state.fResumePending;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
+ rm.setData(doCanSuspend(context));
+ rm.done();
+ }
+
+ private boolean doCanSuspend(IExecutionDMContext context) {
+ if (context instanceof PDAThreadDMContext) {
+ PDAThreadDMContext threadContext = (PDAThreadDMContext)context;
+ // Threads can be resumed only if the VM is not suspended.
+ if (!fVMSuspended) {
+ ThreadInfo state = fThreads.get(threadContext.getID());
+ if (state != null) {
+ return !state.fSuspended && state.fSuspendPending;
+ }
+ }
+ } else {
+ return !fVMSuspended && !fVMSuspendPending;
+ }
+ return false;
+ }
+
+ public boolean isSuspended(IExecutionDMContext context) {
+ if (context instanceof PDAThreadDMContext) {
+ PDAThreadDMContext threadContext = (PDAThreadDMContext)context;
+ // Threads can be resumed only if the VM is not suspended.
+ if (!fVMSuspended) {
+ ThreadInfo state = fThreads.get(threadContext.getID());
+ if (state != null) {
+ return state.fSuspended;
+ }
+ }
+ }
+ return fVMSuspended;
+ }
+
+ public boolean isStepping(IExecutionDMContext context) {
+ if (!isSuspended(context)) {
+ if (context instanceof PDAThreadDMContext) {
+ PDAThreadDMContext threadContext = (PDAThreadDMContext)context;
+ // Threads can be resumed only if the VM is not suspended.
+ if (!fVMStepping) {
+ ThreadInfo state = fThreads.get(threadContext.getID());
+ if (state != null) {
+ return state.fStepping;
+ }
+ }
+ }
+ return fVMStepping;
+ }
+ return false;
+ }
+
+ public void resume(IExecutionDMContext context, final RequestMonitor rm) {
+ assert context != null;
+
+ if (doCanResume(context)) {
+ if (context instanceof PDAThreadDMContext) {
+ final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+ fThreads.get(threadCtx.getID()).fResumePending = true;
+ fCommandControl.queueCommand(
+ new PDAResumeCommand(threadCtx),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ ThreadInfo threadState = fThreads.get(threadCtx.getID());
+ if (threadState != null) {
+ threadState.fResumePending = false;
+ }
+ super.handleFailure();
+ }
+ }
+ );
+ } else {
+ fVMResumePending = true;
+ fCommandControl.queueCommand(
+ new PDAVMResumeCommand(fDMContext),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ fVMResumePending = false;
+ super.handleFailure();
+ }
+ }
+ );
+ }
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running.");
+ }
+ }
+
+ public void suspend(IExecutionDMContext context, final RequestMonitor rm){
+ assert context != null;
+
+ if (doCanSuspend(context)) {
+ if (context instanceof PDAThreadDMContext) {
+ final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+ fThreads.get(threadCtx.getID()).fSuspendPending = true;
+ fCommandControl.queueCommand(
+ new PDAVMSuspendCommand(fDMContext),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ ThreadInfo threadState = fThreads.get(threadCtx.getID());
+ if (threadState != null) {
+ threadState.fSuspendPending = false;
+ }
+ super.handleFailure();
+ }
+ }
+ );
+ } else {
+ fVMSuspendPending = true;
+ fCommandControl.queueCommand(
+ new PDAVMSuspendCommand(fDMContext),
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ fVMSuspendPending = false;
+ super.handleFailure();
+ }
+ }
+ );
+ }
+ } else {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "Given context: " + context + ", is already suspended.");
+ }
+ }
+
+ public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
+ rm.setData(doCanStep(context, stepType));
+ rm.done();
+ }
+
+ public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
+ assert context != null;
+
+ if (doCanStep(context, stepType)) {
+ final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+ final boolean vmWasSuspneded = fVMSuspended;
+
+ if (vmWasSuspneded) {
+ fVMResumePending = true;
+ } else {
+ fThreads.get(threadCtx.getID()).fResumePending = true;
+ }
+
+ AbstractPDACommand<PDACommandResult> stepCommand =
+ stepType == StepType.STEP_RETURN
+ ? new PDAStepReturnCommand(threadCtx)
+ : new PDAStepCommand(threadCtx);
+
+
+ fCommandControl.queueCommand(
+ stepCommand,
+ new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleFailure() {
+ // If the step command failed, we no longer
+ // expect to receive a resumed event.
+ if (vmWasSuspneded) {
+ fVMResumePending = false;
+ } else {
+ ThreadInfo threadState = fThreads.get(threadCtx.getID());
+ if (threadState != null) {
+ threadState.fResumePending = false;
+ }
+ }
+ }
+ });
+
+ } else {
+ PDAPlugin.failRequest(rm, INVALID_STATE, "Cannot resume context");
+ return;
+ }
+ }
+
+ public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor<IExecutionDMContext[]> rm) {
+ IExecutionDMContext[] threads = new IExecutionDMContext[fThreads.size()];
+ int i = 0;
+ for (ThreadInfo info : fThreads.values()) {
+ threads[i++] = info.fContext;
+ }
+ rm.setData(threads);
+ rm.done();
+ }
+
+ public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm) {
+ if (dmc instanceof PDAThreadDMContext) {
+ ThreadInfo info = fThreads.get(((PDAThreadDMContext)dmc).getID());
+ if (info == null) {
+ PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type");
+ return;
+ }
+ rm.setData( new ExecutionDMData(info.fStateChangeReason) );
+ } else {
+ rm.setData( new ExecutionDMData(fVMStateChangeReason) );
+ }
+ rm.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java
new file mode 100644
index 00000000000..8e2058bf162
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStack.java
@@ -0,0 +1,478 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.ICachingService;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack2;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAFrame;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAFrameCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAFrameCommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStackCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStackCommandResult;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStackDepthCommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDAStackDepthCommandResult;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Service for retrieving PDA debugger stack data.
+ * <p>
+ * This service depends on the {@link PDACommandControl} service and the
+ * {@link IRunControl} service. These services must be initialized before
+ * this service is initialized.
+ * </p>
+ */
+public class PDAStack extends AbstractDsfService implements IStack2, ICachingService {
+
+ /**
+ * PDA stack frame contains only the stack frame level. It is only
+ * used as an index into the frame data returned by the PDA debugger.
+ */
+ @Immutable
+ private static class FrameDMContext extends AbstractDMContext implements IFrameDMContext {
+
+ final private int fLevel;
+
+ FrameDMContext(String sessionId, PDAThreadDMContext execDmc, int level) {
+ super(sessionId, new IDMContext[] { execDmc });
+ fLevel = level;
+ }
+
+ public int getLevel() { return fLevel; }
+
+ @Override
+ public boolean equals(Object other) {
+ return super.baseEquals(other) && ((FrameDMContext)other).fLevel == fLevel;
+ }
+
+ @Override
+ public int hashCode() {
+ return super.baseHashCode() ^ fLevel;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".frame[" + fLevel + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * Frame data based on the PDAFrame object returned by the PDA debugger.
+ */
+ @Immutable
+ private static class FrameDMData implements IFrameDMData {
+
+ final private PDAFrame fFrame;
+
+ FrameDMData(PDAFrame frame) {
+ fFrame = frame;
+ }
+
+ public String getFile() {
+ return fFrame.fFilePath.lastSegment();
+ }
+
+ public String getFunction() {
+ return fFrame.fFunction;
+ }
+
+ public int getLine() {
+ return fFrame.fLine + 1;
+ }
+
+ public int getColumn() {
+ return 0;
+ }
+
+ public IAddress getAddress() {
+ return null;
+ }
+ }
+
+ /**
+ * Context representing a variable in a given stack frame.
+ */
+ @Immutable
+ private static class VariableDMContext extends AbstractDMContext implements IVariableDMContext {
+
+ final private String fVariable;
+
+ VariableDMContext(String sessionId, FrameDMContext frameCtx, String variable) {
+ super(sessionId, new IDMContext[] { frameCtx });
+ fVariable = variable;
+ }
+
+ String getVariable() { return fVariable; }
+
+ @Override
+ public boolean equals(Object other) {
+ return super.baseEquals(other) && ((VariableDMContext)other).fVariable.equals(fVariable);
+ }
+
+ @Override
+ public int hashCode() {
+ return super.baseHashCode() + fVariable.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".variable(" + fVariable + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ /**
+ * PDA variable data, only supports returning the variable name.
+ */
+ @Immutable
+ private static class VariableDMData implements IVariableDMData {
+
+ final private String fVariable;
+
+ VariableDMData(String variable) {
+ fVariable = variable;
+ }
+
+ public String getName() {
+ return fVariable;
+ }
+
+ public String getValue() {
+ return null;
+ }
+ }
+
+ // Services that this service depends on.
+ private PDACommandControl fCommandControl;
+ private IRunControl fRunControl;
+
+ // Command cache
+ private CommandCache fCommandCache;
+
+ public PDAStack(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return PDAPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }});
+ }
+
+ private void doInitialize(final RequestMonitor rm) {
+ // Initialize service references that stack service depends on
+ fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+ fRunControl = getServicesTracker().getService(IRunControl.class);
+
+ // Create the commands cache
+ fCommandCache = new CommandCache(getSession(), fCommandControl);
+
+ // Register to listen for run control events, to clear cache accordingly.
+ getSession().addServiceEventListener(this, null);
+
+ // Register stack service with OSGi
+ register(new String[]{IStack.class.getName(), PDAStack.class.getName()}, new Hashtable<String,String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ getSession().removeServiceEventListener(this);
+ fCommandCache.reset();
+ super.shutdown(rm);
+ }
+
+
+ public void getArguments(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.NOT_SUPPORTED, "PDA debugger does not support function arguments.");
+ }
+
+ public void getFrameData(final IFrameDMContext frameCtx, final DataRequestMonitor<IFrameDMData> rm) {
+ final PDAThreadDMContext threadCtx =
+ DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class);
+
+ if (threadCtx == null) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null));
+ rm.done();
+ return;
+ }
+
+ getStackDepth(
+ threadCtx, -1,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // PDAFrame array is ordered highest to lowest. We need to
+ // calculate the index based on frame level.
+ int frameNum = getData() - frameCtx.getLevel() - 1;
+ if (frameNum < 0) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid frame level " + frameCtx);
+ return;
+ }
+
+ // Execute the PDA stack command, or retrieve the result from cache if already available.
+ fCommandCache.execute(
+ new PDAFrameCommand(threadCtx, frameNum),
+ new DataRequestMonitor<PDAFrameCommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Create the frame data object based on the corresponding PDAFrame
+ rm.setData(new FrameDMData(getData().fFrame));
+ rm.done();
+ }
+ });
+ }
+ });
+ }
+
+
+ public void getFrames(IDMContext context, final DataRequestMonitor<IFrameDMContext[]> rm) {
+ // Can only create stack frames for an execution context as a parent,
+ // however the argument context is a generic context type, so it could
+ // be an execution context, a frame, a variable, etc. Search the
+ // hierarchy of the argument context to find the execution one.
+ final PDAThreadDMContext threadCtx =
+ DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+
+ if (threadCtx == null) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+ rm.done();
+ return;
+ }
+
+ // Execute the stack command and create the corresponding frame contexts.
+ getStackDepth(
+ context, -1,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ IFrameDMContext[] frameCtxs = new IFrameDMContext[getData()];
+ for (int i = 0; i < getData(); i++) {
+ frameCtxs[i] = new FrameDMContext(getSession().getId(), threadCtx, i);
+ }
+ rm.setData(frameCtxs);
+ rm.done();
+ }
+ });
+ }
+
+ public void getFrames(IDMContext context, final int startIndex, final int endIndex, final DataRequestMonitor<IFrameDMContext[]> rm) {
+ // Validate index range.
+ assert startIndex >=0 && (endIndex < 0 || startIndex <= endIndex);
+
+ final PDAThreadDMContext threadCtx =
+ DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+
+ if (threadCtx == null) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+ rm.done();
+ return;
+ }
+
+ // Execute the stack command and create the corresponding frame contexts.
+ getStackDepth(
+ context, -1,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ int numFrames = endIndex < 0
+ ? (getData() - startIndex)
+ : Math.min(endIndex + 1, getData()) - startIndex;
+ IFrameDMContext[] frameCtxs = new IFrameDMContext[numFrames];
+ for (int i = 0; i < numFrames; i++) {
+ frameCtxs[i] = new FrameDMContext(getSession().getId(), threadCtx, startIndex + i);
+ }
+ rm.setData(frameCtxs);
+ rm.done();
+ }
+ });
+ }
+
+ public void getLocals(IFrameDMContext context, final DataRequestMonitor<IVariableDMContext[]> rm) {
+ if (!(context instanceof FrameDMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+ rm.done();
+ return;
+ }
+ final FrameDMContext frameCtx = (FrameDMContext)context;
+
+ final PDAThreadDMContext threadCtx =
+ DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class);
+
+ if (threadCtx == null) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null));
+ rm.done();
+ return;
+ }
+
+ fCommandCache.execute(
+ new PDAStackCommand(threadCtx),
+ new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ // Find the correct PDAFrame
+ int frameId = getData().fFrames.length - frameCtx.getLevel() - 1;
+ if (frameId < 0) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid frame level " + frameCtx);
+ return;
+ }
+ PDAFrame pdaFrame = getData().fFrames[frameId];
+
+ // Create variable contexts for all variables in frame.
+ IVariableDMContext[] variableCtxs = new IVariableDMContext[pdaFrame.fVariables.length];
+ for (int i = 0; i < pdaFrame.fVariables.length; i++) {
+ variableCtxs[i] = new VariableDMContext(getSession().getId(), frameCtx, pdaFrame.fVariables[i]);
+ }
+ rm.setData(variableCtxs);
+ rm.done();
+ }
+ });
+
+ }
+
+ public void getStackDepth(IDMContext context, final int maxDepth, final DataRequestMonitor<Integer> rm) {
+ final PDAThreadDMContext threadCtx =
+ DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+
+ if (threadCtx == null) {
+ rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+ rm.done();
+ return;
+ }
+
+ // Execute stack command and return the data's size.
+ fCommandCache.execute(
+ new PDAStackDepthCommand(threadCtx),
+ new DataRequestMonitor<PDAStackDepthCommandResult>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ int depth= getData().fDepth;
+ if (maxDepth > 0 && maxDepth < depth) {
+ depth = maxDepth;
+ }
+ rm.setData(depth);
+ rm.done();
+ }
+ });
+ }
+
+ public void getTopFrame(IDMContext context, final DataRequestMonitor<IFrameDMContext> rm) {
+ // Can only create stack frames for an execution context as a parent,
+ // however the argument context is a generic context type, so it could
+ // be an execution context, a frame, a variable, etc. Search the
+ // hierarchy of the argument context to find the execution one.
+ final PDAThreadDMContext execCtx = DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+ if (execCtx == null) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context);
+ return;
+ }
+
+ // Since the frame context only contain the level, there's no need to
+ // call the PDA debugger. Simply create a context for level 0.
+ rm.setData(new FrameDMContext(getSession().getId(), execCtx, 0));
+ rm.done();
+ }
+
+ public void getVariableData(IVariableDMContext variableCtx, DataRequestMonitor<IVariableDMData> rm) {
+ if ( !(variableCtx instanceof VariableDMContext) ) {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + variableCtx);
+ return;
+ }
+
+ // The variable data doen't contain a value. So there's no need to
+ // go to the back end to retrieve it.
+ String variable = ((VariableDMContext)variableCtx).getVariable();
+
+ rm.setData(new VariableDMData(variable));
+ rm.done();
+ }
+
+ public boolean isStackAvailable(IDMContext context) {
+ // Stack is available if the program is suspended or stepping.
+ IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
+ return execCtx != null && (fRunControl.isSuspended(execCtx) || (fRunControl.isStepping(execCtx)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Deprecated
+ public void getModelData(IDMContext dmc, DataRequestMonitor<?> rm) {
+ // The getModelData() is deprecated and clients are expected to switch
+ // to getExecutionData() and other data retrieve methods directly.
+ // However the UI cache still uses it for now.
+ if (dmc instanceof IFrameDMContext) {
+ getFrameData((IFrameDMContext)dmc, (DataRequestMonitor<IFrameDMData>)rm);
+ } else if (dmc instanceof IVariableDMContext) {
+ getVariableData((IVariableDMContext)dmc, (DataRequestMonitor<IVariableDMData>)rm);
+ } else {
+ PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Unknown context type");
+ }
+ }
+
+ /**
+ * Returns a frame context for the given thread and level;
+ */
+ public IFrameDMContext getFrameDMContext(PDAThreadDMContext thread, int level) {
+ return new FrameDMContext(getSession().getId(), thread, level);
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IResumedDMEvent e) {
+ // Mark the cache as not available, so that stack commands will
+ // fail. Also reset the cache unless it was a step command.
+ fCommandCache.setContextAvailable(e.getDMContext(), false);
+ if (!e.getReason().equals(StateChangeReason.STEP)) {
+ fCommandCache.reset(e.getDMContext());
+ }
+ }
+
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ISuspendedDMEvent e) {
+ // Enable sending commands to target and clear the cache.
+ fCommandCache.setContextAvailable(e.getDMContext(), true);
+ fCommandCache.reset(e.getDMContext());
+ }
+
+ public void flushCache(IDMContext context) {
+ fCommandCache.reset(context);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStartedEvent.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStartedEvent.java
new file mode 100644
index 00000000000..36af8dc52ff
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAStartedEvent.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
+
+/**
+ * Event issued when the PDA debugger is started.
+ */
+public class PDAStartedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IStartedDMEvent
+{
+ PDAStartedEvent(PDAVirtualMachineDMContext context) {
+ super(context);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDATerminatedEvent.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDATerminatedEvent.java
new file mode 100644
index 00000000000..cd17e2c7da0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDATerminatedEvent.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
+
+/**
+ * Event issued when the PDA debugger exits.
+ */
+public class PDATerminatedEvent extends AbstractDMEvent<IExecutionDMContext>
+ implements IExitedDMEvent
+{
+ PDATerminatedEvent(PDAVirtualMachineDMContext context) {
+ super(context);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAThreadDMContext.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAThreadDMContext.java
new file mode 100644
index 00000000000..c7fde0b2a76
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAThreadDMContext.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+/**
+ * Context representing a PDA thread.
+ */
+public class PDAThreadDMContext extends AbstractDMContext
+ implements IExecutionDMContext
+{
+ final private Integer fID;
+
+ public PDAThreadDMContext(String sessionId, PDAVirtualMachineDMContext vmCtx, int id) {
+ super(sessionId, new IDMContext[] { vmCtx });
+ fID = id;
+ }
+
+ public int getID() {
+ return fID;
+ }
+
+ @Override
+ public String toString() {
+ return super.baseToString() + ".thread[" + fID + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + fID.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return baseEquals(obj) && ((PDAThreadDMContext)obj).fID.equals(fID);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAVirtualMachineDMContext.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAVirtualMachineDMContext.java
new file mode 100644
index 00000000000..f42b286241b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/PDAVirtualMachineDMContext.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.examples.dsf.pda.service;
+
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Top-level Data Model context for the PDA debugger representing the while PDA
+ * virtual machine.
+ * <p>
+ * The PDA debugger is a single-threaded application. Therefore this
+ * top level context implements IExecutionDMContext directly, hence this
+ * context can be used to call the IRunControl service to perform run
+ * control opreations.
+ * </p>
+ * <p>
+ * Also, the PDA debugger allows setting breakpoints in scope of the
+ * whole program only, so this context can be used with the breakpoints
+ * service to install/remove breakpoints.
+ * </p>
+ * <p>
+ * Note: There should only be one instance of PDAVirtualMachineDMContext
+ * created by each PDA command control, so its equals method defaults to using
+ * instance comparison.
+ * </p>
+ */
+public class PDAVirtualMachineDMContext extends PlatformObject
+ implements ICommandControlDMContext, IContainerDMContext, IBreakpointsTargetDMContext
+{
+ final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0];
+
+ final private String fSessionId;
+ final private String fProgram;
+
+ public PDAVirtualMachineDMContext(String sessionId, String program) {
+ fSessionId = sessionId;
+ fProgram = program;
+ }
+
+ public String getSessionId() {
+ return fSessionId;
+ }
+
+ public String getProgram() {
+ return fProgram;
+ }
+
+ public IDMContext[] getParents() {
+ return EMPTY_PARENTS_ARRAY;
+ }
+
+ @Override
+ public String toString() {
+ return "pda[" + getSessionId() + "]";
+ }
+
+ public String getCommandControlId() {
+ return getProgram();
+ }
+
+ /**
+ * @see AbstractDMContext#getAdapter(Class)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapterType) {
+ Object retVal = null;
+ DsfSession session = DsfSession.getSession(fSessionId);
+ if (session != null) {
+ retVal = session.getModelAdapter(adapterType);
+ }
+ if (retVal == null) {
+ retVal = super.getAdapter(adapterType);
+ }
+ return retVal;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/AbstractPDACommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/AbstractPDACommand.java
new file mode 100644
index 00000000000..cd63bd8f7a6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/AbstractPDACommand.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.command.ICommand;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
+
+/**
+ * Base class for PDA commands. The PDA commands consist of a text request and
+ * a context. Since the PDA debugger protocol is stateless, the context is only
+ * needed to satisfy the ICommand interface.
+ */
+@Immutable
+abstract public class AbstractPDACommand<V extends PDACommandResult> implements ICommand<V> {
+
+ final private IDMContext fContext;
+ final private String fRequest;
+
+ public AbstractPDACommand(IDMContext context, String request) {
+ fContext = context;
+ fRequest = request;
+ }
+
+ public IDMContext getContext() {
+ return fContext;
+ }
+
+ public ICommand<? extends ICommandResult> coalesceWith(ICommand<? extends ICommandResult> command) {
+ return null;
+ }
+
+ /**
+ * Returns the request to be sent to PDA.
+ */
+ public String getRequest() {
+ return fRequest;
+ }
+
+ /**
+ * Returns the command result based on the given PDA response. This command
+ * uses the class type parameter as the return type to allow the compiler to
+ * enforce the correct command result. This class must be implemented by
+ * each command to create the concrete result type.
+ */
+ abstract public V createResult(String resultText);
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AbstractPDACommand) {
+ AbstractPDACommand<?> cmd = (AbstractPDACommand<?>)obj;
+ return fContext.equals(cmd.fContext) && fRequest.equals(cmd.fRequest);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return fContext.hashCode() + fRequest.hashCode();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDABitField.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDABitField.java
new file mode 100644
index 00000000000..6daee81d696
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDABitField.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Object representing a bit field in the stack command results.
+ *
+ * @see PDARegistersCommand
+ */
+@Immutable
+public class PDABitField {
+
+ final public String fName;
+ final public int fOffset;
+ final public int fCount;
+ final public Map<String, String> fMnemonics;
+
+ PDABitField(String bitFieldString) {
+ StringTokenizer st = new StringTokenizer(bitFieldString, " ");
+
+ fName = st.nextToken();
+ fOffset = Integer.parseInt(st.nextToken());
+ fCount = Integer.parseInt(st.nextToken());
+
+ fMnemonics = new LinkedHashMap<String, String>(0);
+ while (st.hasMoreTokens()) {
+ fMnemonics.put(st.nextToken(), st.nextToken());
+ }
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAChildrenCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAChildrenCommand.java
new file mode 100644
index 00000000000..fabfc7dd3bc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAChildrenCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves data stack information
+ *
+ * <pre>
+ * C: children {thread_id} {frame_id} {variable_name}
+ * R: {child variable 1}|{child variable 2}|{child variable 3}|...|
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAChildrenCommand extends AbstractPDACommand<PDAListResult> {
+
+ public PDAChildrenCommand(PDAThreadDMContext thread, int frameId, String name ) {
+ super(thread, "children " + thread.getID() + " " + frameId + " " + name);
+ }
+
+ @Override
+ public PDAListResult createResult(String resultText) {
+ return new PDAListResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAClearBreakpointCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAClearBreakpointCommand.java
new file mode 100644
index 00000000000..2550af75deb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAClearBreakpointCommand.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Clears any breakpoint set on given line
+ *
+ * <pre>
+ * C: clear {line}
+ * R: ok
+ * </pre>
+
+ */
+@Immutable
+public class PDAClearBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAClearBreakpointCommand(PDAVirtualMachineDMContext context, int line) {
+ super(context, "clear " + (line - 1));
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDACommandResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDACommandResult.java
new file mode 100644
index 00000000000..47fefea7c25
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDACommandResult.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.debug.service.command.ICommand;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
+
+
+/**
+ * Basic command result object. This command result simply allows access to the
+ * PDA response. Sub-classes may override to optionally parse the response text
+ * and return higher-level objects.
+ */
+@Immutable
+public class PDACommandResult implements ICommandResult {
+
+ final public String fResponseText;
+
+ public PDACommandResult(String response) {
+ fResponseText = response;
+ }
+
+ public <V extends ICommandResult> V getSubsetResult(ICommand<V> command) {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof PDACommandResult) {
+ PDACommandResult result = (PDACommandResult)obj;
+ return fResponseText.equals(result.fResponseText);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return fResponseText.hashCode();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADataCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADataCommand.java
new file mode 100644
index 00000000000..bc9adc3f500
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADataCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves data stack information
+ *
+ * <pre>
+ * C: data {thread_id}
+ * R: {value 1}|{value 2}|{value 3}|...|
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDADataCommand extends AbstractPDACommand<PDAListResult> {
+
+ public PDADataCommand(PDAThreadDMContext thread) {
+ super(thread, "data " + thread.getID());
+ }
+
+ @Override
+ public PDAListResult createResult(String resultText) {
+ return new PDAListResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADropFrameCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADropFrameCommand.java
new file mode 100644
index 00000000000..43566d175f7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDADropFrameCommand.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Returns from the current frame without executing the rest of instructions.
+ *
+ * <pre>
+ * If VM running:
+ * C: drop {thread_id}
+ * R: ok
+ * E: resumed {thread_id} drop
+ * E: suspended {thread_id} drop
+ *
+ * If VM suspended:
+ * C: drop {thread_id}
+ * R: ok
+ * E: vmresumed drop
+ * E: vmsuspended {thread_id} drop
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDADropFrameCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDADropFrameCommand(PDAThreadDMContext thread) {
+ super(thread, "drop " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEvalCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEvalCommand.java
new file mode 100644
index 00000000000..9a7fea67f33
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEvalCommand.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Sets what events cause the execution to stop.
+ *
+ * <pre>
+ * C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
+ * R: ok
+ * E: resumed {thread_id} client
+ * E: evalresult result
+ * E: suspended {thread_id} eval
+ *
+ * Errors:
+ * error: invalid thread
+ * error: cannot evaluate while vm is suspended
+ * error: thread running
+ * </pre>
+ *
+ * Where event_name could be <code>unimpinstr</code> or <code>nosuchlabel</code>.
+ */
+@Immutable
+public class PDAEvalCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAEvalCommand(PDAThreadDMContext thread, String operation) {
+ super(thread, "eval " + thread.getID() + " " + operation);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEventStopCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEventStopCommand.java
new file mode 100644
index 00000000000..3ca751f4fc2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAEventStopCommand.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Sets what events cause the execution to stop.
+ *
+ * <pre>
+ * C: eventstop {event_name} {0|1}
+ * R: ok
+ * ...
+ * E: suspended event {event_name}
+ * </pre>
+ *
+ * Where event_name could be <code>unimpinstr</code> or <code>nosuchlabel</code>.
+ */
+@Immutable
+public class PDAEventStopCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public enum Event { UNIMPINSTR, NOSUCHLABEL };
+
+ public PDAEventStopCommand(PDAVirtualMachineDMContext context, Event event, boolean enable) {
+ super(context,
+ "eventstop " +
+ (event == Event.UNIMPINSTR ? "unimpinstr " : "nosuchlabel ") +
+ (enable ? "1" : "0"));
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAExitCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAExitCommand.java
new file mode 100644
index 00000000000..7bc192f753e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAExitCommand.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Instructs the debugger to exit.
+ *
+ * <pre>
+ * C: exit
+ * R: ok
+ * </pre>
+ */
+@Immutable
+public class PDAExitCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAExitCommand(PDAVirtualMachineDMContext context) {
+ super(context, "exit");
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrame.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrame.java
new file mode 100644
index 00000000000..9b6b0e230d4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrame.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * Object representing a frame in the stack command results.
+ *
+ * @see PDAStackCommand
+ */
+@Immutable
+public class PDAFrame {
+
+ final public IPath fFilePath;
+ final public int fLine;
+ final public String fFunction;
+ final public String[] fVariables;
+
+ PDAFrame(String frameString) {
+ StringTokenizer st = new StringTokenizer(frameString, "|");
+
+ fFilePath = new Path(st.nextToken());
+ fLine = Integer.parseInt(st.nextToken());
+ fFunction = st.nextToken();
+
+ List<String> variablesList = new ArrayList<String>();
+ while (st.hasMoreTokens()) {
+ variablesList.add(st.nextToken());
+ }
+ fVariables = variablesList.toArray(new String[variablesList.size()]);
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommand.java
new file mode 100644
index 00000000000..ee62c5cfb2c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves command stack frame information
+ *
+ * <pre>
+ * C: stack {thread_id} {frame_number}
+ * R: {file}|{line}|{function}|{var_1}|{var_2}|...
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAFrameCommand extends AbstractPDACommand<PDAFrameCommandResult> {
+
+ public PDAFrameCommand(PDAThreadDMContext thread, int frameNum) {
+ super(thread, "frame " + thread.getID() + " " + frameNum);
+ }
+
+ @Override
+ public PDAFrameCommandResult createResult(String resultText) {
+ return new PDAFrameCommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommandResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommandResult.java
new file mode 100644
index 00000000000..e430d20ac77
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAFrameCommandResult.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+
+/**
+ * @see PDAFrameCommand
+ */
+@Immutable
+public class PDAFrameCommandResult extends PDACommandResult {
+
+ /**
+ * Frame data return by the frame command.
+ */
+ final public PDAFrame fFrame;
+
+ PDAFrameCommandResult(String response) {
+ super(response);
+ fFrame = new PDAFrame(response);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAGroupsCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAGroupsCommand.java
new file mode 100644
index 00000000000..1a70dd9e19c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAGroupsCommand.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Retrieves register groups information
+ *
+ * <pre>
+ * C: groups
+ * R: {group 1}|{group 2}|{group 3}|...|
+ * </pre>
+ */
+@Immutable
+public class PDAGroupsCommand extends AbstractPDACommand<PDAListResult> {
+
+ public PDAGroupsCommand(PDAVirtualMachineDMContext context) {
+ super(context, "groups");
+ }
+
+ @Override
+ public PDAListResult createResult(String resultText) {
+ return new PDAListResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAListResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAListResult.java
new file mode 100644
index 00000000000..64519d72727
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAListResult.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+
+/**
+ * @see PDADataCommand
+ */
+@Immutable
+public class PDAListResult extends PDACommandResult {
+
+ final public String[] fValues;
+
+ PDAListResult(String response) {
+ super(response);
+ StringTokenizer st = new StringTokenizer(response, "|");
+ List<String> valuesList = new ArrayList<String>();
+
+ while (st.hasMoreTokens()) {
+ String token = st.nextToken();
+ if (token.length() != 0) {
+ valuesList.add(token);
+ }
+ }
+
+ fValues = new String[valuesList.size()];
+ for (int i = 0; i < valuesList.size(); i++) {
+ fValues[i] = valuesList.get(i);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPopDataCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPopDataCommand.java
new file mode 100644
index 00000000000..d2a7cae6215
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPopDataCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Pops the top value from the data stack
+ *
+ * <pre>
+ * C: popdata {thread_id}
+ * R: ok
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAPopDataCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAPopDataCommand(PDAThreadDMContext thread) {
+ super(thread, "popdata " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPushDataCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPushDataCommand.java
new file mode 100644
index 00000000000..4237b5596e3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAPushDataCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Pushes the given value on top of the data stack.
+ *
+ * <pre>
+ * C: pushdata {thread_id} {value}
+ * R: ok
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAPushDataCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAPushDataCommand(PDAThreadDMContext thread, int value) {
+ super(thread, "pushdata " + thread.getID() + " " + value);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegister.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegister.java
new file mode 100644
index 00000000000..a76d9ec754f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegister.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Object representing a register in the registers command results.
+ *
+ * @see PDARCommand
+ */
+@Immutable
+public class PDARegister {
+
+ final public String fName;
+ final public boolean fWritable;
+ final public PDABitField[] fBitFields;
+
+ PDARegister(String regString) {
+ StringTokenizer st = new StringTokenizer(regString, "|");
+
+ String regInfo = st.nextToken();
+ StringTokenizer regSt = new StringTokenizer(regInfo, " ");
+ fName = regSt.nextToken();
+ fWritable = Boolean.parseBoolean(regSt.nextToken());
+
+ List<PDABitField> bitFieldsList = new ArrayList<PDABitField>();
+ while (st.hasMoreTokens()) {
+ bitFieldsList.add(new PDABitField(st.nextToken()));
+ }
+ fBitFields = bitFieldsList.toArray(new PDABitField[bitFieldsList.size()]);
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommand.java
new file mode 100644
index 00000000000..ed72790b7a7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommand.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves registers definition information
+ *
+ * <pre>
+ * C: registers {group name}
+ * R: {register name} {true|false}|{bit field name} {start bit} {bit count} {mnemonic 1} {mnemonic 2} ...#{register name} ...
+ * </pre>
+ */
+@Immutable
+public class PDARegistersCommand extends AbstractPDACommand<PDARegistersCommandResult> {
+
+ public PDARegistersCommand(PDAThreadDMContext context, String group) {
+ super(context, "registers " + group);
+ }
+
+ @Override
+ public PDARegistersCommandResult createResult(String resultText) {
+ return new PDARegistersCommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommandResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommandResult.java
new file mode 100644
index 00000000000..7a25ae85149
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDARegistersCommandResult.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+
+/**
+ * @see PDARegistersCommand
+ */
+@Immutable
+public class PDARegistersCommandResult extends PDACommandResult {
+
+ /**
+ * Array of registers returned by the registers commands.
+ */
+ final public PDARegister[] fRegisters;
+
+ PDARegistersCommandResult(String response) {
+ super(response);
+ StringTokenizer st = new StringTokenizer(response, "#");
+ List<PDARegister> regList = new ArrayList<PDARegister>();
+
+ while (st.hasMoreTokens()) {
+ regList.add(new PDARegister(st.nextToken()));
+ }
+ fRegisters = regList.toArray(new PDARegister[regList.size()]);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAResumeCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAResumeCommand.java
new file mode 100644
index 00000000000..4dfc585754f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAResumeCommand.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Resumes the execution of a single thread. Can be issued only if the virtual
+ * machine is running.
+ *
+ * <pre>
+ * C: resume {thread_id}
+ * R: ok
+ * E: resumed {thread_id} client
+ *
+ * Errors:
+ * error: invalid thread
+ * error: cannot resume thread when vm is suspended
+ * error: thread already running
+ * </pre>
+ */
+@Immutable
+public class PDAResumeCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAResumeCommand(PDAThreadDMContext thread) {
+ super(thread, "resume " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetBreakpointCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetBreakpointCommand.java
new file mode 100644
index 00000000000..53d62a2f4f6
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetBreakpointCommand.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Sets a breakpoint at given line
+ *
+ * <pre>
+ * Suspend a single thread:
+ * C: set {line_number} 0
+ * R: ok
+ * C: resume {thread_id}
+ * E: resumed {thread_id} client
+ * E: suspended {thread_id} breakpoint line_number
+ *
+ * Suspend the VM:
+ * C: set {line_number} 1
+ * R: ok
+ * C: vmresume
+ * E: vmresumed client
+ * E: vmsuspended {thread_id} breakpoint line_number
+ * </pre>
+ */
+@Immutable
+public class PDASetBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDASetBreakpointCommand(PDAVirtualMachineDMContext context, int line, boolean stopVM) {
+ super(context,
+ "set " +
+ (line - 1) + " " +
+ (stopVM ? "1" : "0"));
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetDataCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetDataCommand.java
new file mode 100644
index 00000000000..e6b54aacd52
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetDataCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Sets a data value in the data stack at the given location
+ *
+ * <pre>
+ * C: setdata {thread_id} {index} {value}
+ * R: ok
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDASetDataCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDASetDataCommand(PDAThreadDMContext thread, int index, String value) {
+ super(thread, "setdata " + thread.getID() + " " + index + " " + value);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetVarCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetVarCommand.java
new file mode 100644
index 00000000000..2cab2417249
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASetVarCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Sets a variable value
+ *
+ * <pre>
+ * C: setvar {thread_id} {frame_number} {variable} {value}
+ * R: ok
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDASetVarCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDASetVarCommand(PDAThreadDMContext thread, int frame, String variable, String value) {
+ super(thread, "setvar " + thread.getID() + " " + frame + " " + variable + " " + value);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommand.java
new file mode 100644
index 00000000000..57e90b8979e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves command stack information
+ *
+ * <pre>
+ * C: stack {thread_id}
+ * R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAStackCommand extends AbstractPDACommand<PDAStackCommandResult> {
+
+ public PDAStackCommand(PDAThreadDMContext thread) {
+ super(thread, "stack " + thread.getID());
+ }
+
+ @Override
+ public PDAStackCommandResult createResult(String resultText) {
+ return new PDAStackCommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommandResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommandResult.java
new file mode 100644
index 00000000000..d7e1a0c256c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackCommandResult.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+
+/**
+ * @see PDAStackCommand
+ */
+@Immutable
+public class PDAStackCommandResult extends PDACommandResult {
+
+ /**
+ * Array of frames return by the stack commands. The frames are ordered
+ * with the highest-level frame first.
+ */
+ final public PDAFrame[] fFrames;
+
+ PDAStackCommandResult(String response) {
+ super(response);
+ StringTokenizer st = new StringTokenizer(response, "#");
+ List<PDAFrame> framesList = new ArrayList<PDAFrame>();
+
+ while (st.hasMoreTokens()) {
+ framesList.add(new PDAFrame(st.nextToken()));
+ }
+ fFrames = framesList.toArray(new PDAFrame[framesList.size()]);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommand.java
new file mode 100644
index 00000000000..225f5c36a0f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommand.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves command stack depth
+ *
+ * <pre>
+ * C: stackdepth {thread_id}
+ * R: {depth}
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAStackDepthCommand extends AbstractPDACommand<PDAStackDepthCommandResult> {
+
+ public PDAStackDepthCommand(PDAThreadDMContext thread) {
+ super(thread, "stackdepth " + thread.getID());
+ }
+
+ @Override
+ public PDAStackDepthCommandResult createResult(String resultText) {
+ return new PDAStackDepthCommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommandResult.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommandResult.java
new file mode 100644
index 00000000000..d2e1b452990
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStackDepthCommandResult.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+
+/**
+ * @see PDADataCommand
+ */
+@Immutable
+public class PDAStackDepthCommandResult extends PDACommandResult {
+
+ final public int fDepth;
+
+ PDAStackDepthCommandResult(String response) {
+ super(response);
+ int depth = 1; // default to something that won't cause NPEs
+ try {
+ depth = Integer.parseInt(response);
+ } catch (NumberFormatException e) {}
+ fDepth = depth;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepCommand.java
new file mode 100644
index 00000000000..3fc8514bd82
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepCommand.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Executes next instruction
+ *
+ * <pre>
+ * If VM running:
+ * C: step {thread_id}
+ * R: ok
+ * E: resumed {thread_id} client
+ * E: suspended {thread_id} step
+ *
+ * If VM suspended:
+ * C: step {thread_id}
+ * R: ok
+ * E: vmresumed client
+ * E: vmsuspended {thread_id} step
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAStepCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAStepCommand(PDAThreadDMContext thread) {
+ super(thread, "step " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepReturnCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepReturnCommand.java
new file mode 100644
index 00000000000..9a45f8782c1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAStepReturnCommand.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Executes instructions until the current subroutine is finished
+ *
+ * <pre>
+ * If VM running:
+ * C: stepreturn {thread_id}
+ * R: ok
+ * E: resumed {thread_id} client
+ * E: suspended {thread_id} step
+ *
+ * If VM suspended:
+ * C: stepreturn {thread_id}
+ * R: ok
+ * E: vmresumed client
+ * E: vmsuspended {thread_id} step
+ *
+ * Errors:
+ * error: invalid thread
+ * </pre>
+ */
+@Immutable
+public class PDAStepReturnCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAStepReturnCommand(PDAThreadDMContext thread) {
+ super(thread, "stepreturn " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASuspendCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASuspendCommand.java
new file mode 100644
index 00000000000..cdc125985bf
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDASuspendCommand.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Suspends execution of a single thread. Can be issued only if the virtual
+ * machine is running.
+ *
+ * <pre>
+ * C: suspend {thread_id}
+ * R: ok
+ * E: suspended {thread_id} client
+ *
+ * Errors:
+ * error: invalid thread
+ error: vm already suspended
+ * error: thread already suspended
+ * </pre>
+ */
+@Immutable
+public class PDASuspendCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDASuspendCommand(PDAThreadDMContext thread) {
+ super(thread, "suspend " + thread.getID());
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMResumeCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMResumeCommand.java
new file mode 100644
index 00000000000..48ff4108455
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMResumeCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Resumes the execution of the whole virtual machine
+ *
+ * <pre>
+ * C: vmresume
+ * R: ok
+ * E: vmresumed client
+ *
+ * Errors:
+ * error: vm already running
+ * </pre>
+ */
+@Immutable
+public class PDAVMResumeCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAVMResumeCommand(PDAVirtualMachineDMContext context) {
+ super(context, "vmresume");
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMSuspendCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMSuspendCommand.java
new file mode 100644
index 00000000000..11259a8f9fc
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVMSuspendCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Suspends the execution of the whole virtual machine
+ *
+ * <pre>
+ * C: vmsuspend
+ * R: ok
+ * E: vmsuspended client
+ *
+ * Errors:
+ * error: thread already suspended
+ * </pre>
+ */
+@Immutable
+public class PDAVMSuspendCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAVMSuspendCommand(PDAVirtualMachineDMContext context) {
+ super(context, "vmsuspend");
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVarCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVarCommand.java
new file mode 100644
index 00000000000..a6c15e1a45b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAVarCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAThreadDMContext;
+
+/**
+ * Retrieves variable value
+ *
+ * <pre>
+ * C: var {thread_id} {frame_number} {variable_name}
+ * R: {variable_value}
+ *
+ * Errors:
+ * error: invalid thread
+ * error: variable undefined
+ * </pre>
+ */
+@Immutable
+public class PDAVarCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public PDAVarCommand(PDAThreadDMContext thread, int frameId, String name) {
+ super(thread, "var " + thread.getID() + " " + frameId + " " + name);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAWatchCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAWatchCommand.java
new file mode 100644
index 00000000000..5bc90bcbb02
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/service/commands/PDAWatchCommand.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.pda.service.commands;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Sets a watchpoint on a given variable
+ *
+ * <pre>
+ * C: watch {function}::{variable_name} {watch_operation}
+ * R: ok
+ * C: vmresume
+ * R: vmresumed client
+ * E: vmsuspended {thread_id} watch {watch_operation} {function}::{variable_name}
+ * </pre>
+ */
+@Immutable
+public class PDAWatchCommand extends AbstractPDACommand<PDACommandResult> {
+
+ public enum WatchOperation { READ, WRITE, BOTH, NONE };
+
+ private static int getWatchOperationCode(WatchOperation operation) {
+ switch (operation) {
+ case READ:
+ return 1;
+ case WRITE:
+ return 2;
+ case BOTH:
+ return 3;
+ default:
+ return 0;
+ }
+ }
+
+ public PDAWatchCommand(PDAVirtualMachineDMContext context, String function, String variable, WatchOperation operation) {
+ super(context, "watch " + function+ "::" + variable + " " + getWatchOperationCode(operation));
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourceLookupDirector.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourceLookupDirector.java
new file mode 100644
index 00000000000..750ce9701c2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourceLookupDirector.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.sourcelookup;
+
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
+
+/**
+ * PDA source lookup director.
+ */
+public class PDASourceLookupDirector extends AbstractSourceLookupDirector {
+ public void initializeParticipants() {
+ // No need to add participants here, the source display adapter will
+ // add the participant with the correct session ID.
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourcePathComputerDelegate.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourcePathComputerDelegate.java
new file mode 100644
index 00000000000..6977bc29c96
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/examples/dsf/pda/sourcelookup/PDASourcePathComputerDelegate.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ * Wind River Systems - adopted to use with DSF
+ *******************************************************************************/
+package org.eclipse.cdt.examples.dsf.pda.sourcelookup;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate;
+import org.eclipse.debug.core.sourcelookup.containers.FolderSourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.ProjectSourceContainer;
+import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer;
+
+
+/**
+ * Computes the default source lookup path for a PDA launch configuration.
+ * The default source lookup path is the folder or project containing
+ * the PDA program being launched. If the program is not specified, the workspace
+ * is searched by default.
+ * <p>
+ * This class is identical to the corresponding in PDA debugger implemented in
+ * org.eclipse.debug.examples.
+ * </p>
+ */
+public class PDASourcePathComputerDelegate implements ISourcePathComputerDelegate {
+
+ public ISourceContainer[] computeSourceContainers(ILaunchConfiguration configuration, IProgressMonitor monitor) throws CoreException {
+ String path = configuration.getAttribute(PDAPlugin.ATTR_PDA_PROGRAM, (String)null);
+ ISourceContainer sourceContainer = null;
+ if (path != null) {
+ IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(path));
+ if (resource != null) {
+ IContainer container = resource.getParent();
+ if (container.getType() == IResource.PROJECT) {
+ sourceContainer = new ProjectSourceContainer((IProject)container, false);
+ } else if (container.getType() == IResource.FOLDER) {
+ sourceContainer = new FolderSourceContainer(container, false);
+ }
+ }
+ }
+ if (sourceContainer == null) {
+ sourceContainer = new WorkspaceSourceContainer();
+ }
+ return new ISourceContainer[]{sourceContainer};
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/BasicTests.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/BasicTests.java
new file mode 100644
index 00000000000..51557bbe9e5
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/BasicTests.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import junit.framework.Assert;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.service.command.ICommand;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandListener;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandResult;
+import org.eclipse.cdt.dsf.debug.service.command.ICommandToken;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.core.runtime.CoreException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class BasicTests extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ fProgram = "samples/example.pda";
+ }
+
+ @Test
+ public void testCommandListener() throws CoreException, InterruptedException, ExecutionException {
+
+ class CommandInfo {
+ CommandInfo(ICommand<?> command, ICommandResult result) { fCommand = command; fResult = result; }
+ ICommand<?> fCommand;
+ ICommandResult fResult;
+ }
+
+ class CommandListener implements ICommandListener {
+
+ List<CommandInfo> fDoneCommands = new LinkedList<CommandInfo>();
+ List<CommandInfo> fQueuedCommands = new LinkedList<CommandInfo>();
+ List<CommandInfo> fRemovedCommands = new LinkedList<CommandInfo>();
+ List<CommandInfo> fSentCommands = new LinkedList<CommandInfo>();
+
+ public void commandDone(ICommandToken token, ICommandResult result) {
+ fDoneCommands.add(new CommandInfo(token.getCommand(), result));
+ }
+ public void commandQueued(ICommandToken token) {
+ fQueuedCommands.add(new CommandInfo(token.getCommand(), null));
+ }
+ public void commandRemoved(ICommandToken token) {
+ fRemovedCommands.add(new CommandInfo(token.getCommand(), null));
+ }
+ public void commandSent(ICommandToken token) {
+ fSentCommands.add(new CommandInfo(token.getCommand(), null));
+ }
+
+ void reset() {
+ fDoneCommands.clear();
+ fQueuedCommands.clear();
+ fRemovedCommands.clear();
+ fSentCommands.clear();
+ }
+ }
+
+ final CommandListener listener = new CommandListener();
+ fExecutor.execute(new DsfRunnable() {
+ public void run() {
+ fCommandControl.addCommandListener(listener);
+ }
+ });
+
+ final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getContext(), "data 1");
+
+ // Test sending the command and checking all listeners were called.
+ Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {
+ @Override
+ protected void execute(DataRequestMonitor<PDACommandResult> rm) {
+ fCommandControl.queueCommand(testCommand, rm);
+ }
+ };
+ fExecutor.execute(sendCommandQuery);
+ PDACommandResult result = sendCommandQuery.get();
+ Assert.assertEquals(1, listener.fQueuedCommands.size());
+ Assert.assertEquals(testCommand, listener.fQueuedCommands.get(0).fCommand);
+ Assert.assertEquals(0, listener.fRemovedCommands.size());
+ Assert.assertEquals(1, listener.fSentCommands.size());
+ Assert.assertEquals(testCommand, listener.fSentCommands.get(0).fCommand);
+ Assert.assertEquals(1, listener.fDoneCommands.size());
+ Assert.assertEquals(testCommand, listener.fDoneCommands.get(0).fCommand);
+ Assert.assertEquals(result, listener.fDoneCommands.get(0).fResult);
+
+ // Test queuing then removing command
+ listener.reset();
+ Query<Object> queueRemoveCommandQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ ICommandToken token = fCommandControl.queueCommand(
+ testCommand,
+ new DataRequestMonitor<PDACommandResult>(fExecutor, null) {
+ @Override
+ protected void handleCompleted() {
+ Assert.fail("This command should never have been executed.");
+ }
+ });
+ fCommandControl.removeCommand(token);
+
+ rm.setData(new Object());
+ rm.done();
+ }
+ };
+ fExecutor.execute(queueRemoveCommandQuery);
+ queueRemoveCommandQuery.get();
+ Assert.assertEquals(1, listener.fQueuedCommands.size());
+ Assert.assertEquals(testCommand, listener.fQueuedCommands.get(0).fCommand);
+ Assert.assertEquals(1, listener.fRemovedCommands.size());
+ Assert.assertEquals(testCommand, listener.fRemovedCommands.get(0).fCommand);
+ Assert.assertEquals(0, listener.fSentCommands.size());
+ Assert.assertEquals(0, listener.fDoneCommands.size());
+
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/CommandControlTestsBase.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/CommandControlTestsBase.java
new file mode 100644
index 00000000000..c4d2e7b4690
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/CommandControlTestsBase.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import junit.framework.Assert;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.debug.service.command.IEventListener;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABackend;
+import org.eclipse.cdt.examples.dsf.pda.service.PDACommandControl;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+import org.eclipse.cdt.tests.dsf.pda.util.Launching;
+import org.eclipse.core.runtime.CoreException;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ *
+ */
+public class CommandControlTestsBase {
+
+ protected static String fProgram;
+
+ protected DsfExecutor fExecutor;
+ protected DsfSession fSession;
+ protected PDABackend fPDABackend;
+ protected PDACommandControl fCommandControl;
+ private BlockingQueue<Object> fEventsQueue = new LinkedBlockingQueue<Object>();
+
+ private BufferedReader fOutputReader;
+
+ @Before
+ public void startup() throws CoreException, InterruptedException, ExecutionException, IOException {
+
+ class InitializeCommandServiceQuery extends Query<Object> {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ fCommandControl.initialize(rm);
+ }
+ };
+
+ fExecutor = new DefaultDsfExecutor();
+ fSession = DsfSession.startSession(fExecutor, "PDA Test");
+
+ Process proc = Launching.launchPDA(fSession, null, fProgram);
+ Assert.assertNotNull(proc);
+
+ // Remember the backend service of this session.
+ // Note this must be called after the above LaunchPDA().
+ fPDABackend = Launching.getBackendService();
+
+ fOutputReader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
+ Assert.assertTrue(fOutputReader.readLine().contains("-debug"));
+
+ fCommandControl = new PDACommandControl(fSession);
+
+ fCommandControl.addEventListener(new IEventListener() {
+ public void eventReceived(Object output) {
+ fEventsQueue.add(output);
+ }
+ });
+
+ InitializeCommandServiceQuery initQuery = new InitializeCommandServiceQuery();
+ fExecutor.execute(initQuery);
+ initQuery.get();
+ Assert.assertEquals("debug connection accepted", fOutputReader.readLine());
+ }
+
+ @After
+ public void shutdown() throws CoreException, InterruptedException, ExecutionException, IOException {
+ if (fOutputReader != null) {
+ fOutputReader.close();
+ }
+
+ class ShutdownCommandServiceQuery extends Query<Object> {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ fCommandControl.shutdown(rm);
+ }
+ };
+
+ if (fExecutor != null) {
+ ShutdownCommandServiceQuery shutdownQuery = new ShutdownCommandServiceQuery();
+ fExecutor.execute(shutdownQuery);
+ shutdownQuery.get();
+ }
+
+ class ShutdownBackendServiceQuery extends Query<Object> {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ fPDABackend.shutdown(rm);
+ }
+ };
+
+ if (fExecutor != null) {
+ ShutdownBackendServiceQuery shutdownQuery = new ShutdownBackendServiceQuery();
+ fExecutor.execute(shutdownQuery);
+ shutdownQuery.get();
+ }
+ }
+
+ protected void sendCommand(String command) throws Throwable {
+ sendCommand(command, "ok");
+ }
+
+ protected void sendCommand(String command, String expectedResult) throws Throwable {
+
+ final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getContext(), command);
+
+ // Test sending the command and checking all listeners were called.
+ Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {
+ @Override
+ protected void execute(DataRequestMonitor<PDACommandResult> rm) {
+ fCommandControl.queueCommand(testCommand, rm);
+ }
+ };
+
+ String responseText = null;
+ fExecutor.execute(sendCommandQuery);
+ try {
+ PDACommandResult result = sendCommandQuery.get();
+ responseText = result.fResponseText;
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof CoreException) {
+ responseText = ((CoreException)e.getCause()).getStatus().getMessage();
+ } else {
+ throw e.getCause();
+ }
+ }
+ Assert.assertEquals("Command returned an unexpected result", expectedResult, responseText);
+
+ }
+
+ protected void clearEvents() {
+ fEventsQueue.clear();
+ }
+
+ protected void expectEvent(String expectedEvent) throws InterruptedException {
+ Assert.assertEquals("Unexpected event received", expectedEvent, fEventsQueue.take());
+ }
+
+ protected void expectOutput(String expectedOutput) throws IOException {
+ Assert.assertEquals("Unexpected output received", expectedOutput, fOutputReader.readLine());
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestCommand.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestCommand.java
new file mode 100644
index 00000000000..236457a4858
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestCommand.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import org.eclipse.cdt.examples.dsf.pda.service.PDAVirtualMachineDMContext;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.AbstractPDACommand;
+import org.eclipse.cdt.examples.dsf.pda.service.commands.PDACommandResult;
+
+/**
+ *
+ */
+class PDATestCommand extends AbstractPDACommand<PDACommandResult> {
+ PDATestCommand(PDAVirtualMachineDMContext context, String command) {
+ super(context, command);
+ }
+
+ @Override
+ public PDACommandResult createResult(String resultText) {
+ return new PDACommandResult(resultText);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestEvent.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestEvent.java
new file mode 100644
index 00000000000..325972537d8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/PDATestEvent.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+/**
+ *
+ */
+public class PDATestEvent {
+ final public String fEventText;
+ PDATestEvent(String event) {
+ fEventText = event;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test1.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test1.java
new file mode 100644
index 00000000000..c82179c8d80
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test1.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test1 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("samples/example.pda"));
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testRun() throws Throwable {
+ sendCommand("vmresume");
+ expectOutput("\"hello\"");
+ expectOutput("\"barfoo\"");
+ expectOutput("\"first\"");
+ expectOutput("\"second\"");
+ expectOutput("12");
+ expectOutput("11");
+ expectOutput("10");
+ expectOutput("\"barfoo\"");
+ expectOutput("\"first\"");
+ expectOutput("\"second\"");
+ expectOutput("\"end\"");
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test10.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test10.java
new file mode 100644
index 00000000000..bce14a6b9a7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test10.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test10 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest10.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testRegisters() throws Throwable {
+ expectEvent("started 1");
+ // run to the end of register definitions
+ sendCommand("set 10 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("registers");
+ expectEvent("vmsuspended 1 breakpoint 10");
+
+ // Test the definitions commands
+ sendCommand("groups", "group1|group2|");
+ sendCommand("registers group1", "reg1 true|field1 0 2 |field2 2 2 zero 0 one 1 two 2 three 3 #reg2 false#");
+ sendCommand("registers group2", "reg3 true#");
+
+ // Run to the end of the program
+ sendCommand("set 37 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectOutput("1");
+ expectOutput("2");
+ expectOutput("0");
+ expectOutput("4");
+ expectOutput("0");
+ expectOutput("0");
+ expectOutput("2");
+ expectOutput("8");
+ expectEvent("vmsuspended 1 breakpoint 37");
+
+ // Test var get/set commands
+ sendCommand("var 1 1 $reg1", "8");
+ sendCommand("var 1 1 $reg1.field1", "0");
+ sendCommand("var 1 1 $reg1.field2", "2");
+ sendCommand("setvar 1 1 $reg1.field2 3");
+ sendCommand("var 1 1 $reg1.field2", "3");
+ sendCommand("setvar 1 1 $reg1 1");
+ sendCommand("var 1 1 $reg1", "1");
+
+ // exit
+ sendCommand("exit");
+ expectEvent("terminated");
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test2.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test2.java
new file mode 100644
index 00000000000..e145ef30128
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test2.java
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test2 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest2.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testCommonDebugCommands() throws Throwable {
+ expectEvent("started 1");
+ // test step
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ // test breakpoint
+ sendCommand("set 4 1");
+ sendCommand("data 1", "6|");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 4");
+ // test data stack
+ sendCommand("data 1", "6|7|8|9|");
+ sendCommand("popdata 1");
+ sendCommand("data 1", "6|7|8|");
+ sendCommand("pushdata 1 11");
+ sendCommand("data 1", "6|7|8|11|");
+ sendCommand("setdata 1 1 2");
+ sendCommand("data 1", "6|2|8|11|");
+ // test call stack
+ sendCommand("set 12 1");
+ sendCommand("set 19 1");
+ sendCommand("stepreturn 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 breakpoint 12");
+ sendCommand("clear 19");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
+ sendCommand("stackdepth 1", "3");
+ sendCommand("frame 1 0", fProgram + "|6|main");
+ sendCommand("frame 1 1", fProgram + "|18|sub1|m|n");
+ sendCommand("frame 1 2", fProgram + "|12|sub2" );
+ sendCommand("stepreturn 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
+ sendCommand("stepreturn 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
+ sendCommand("set 6 1");
+ sendCommand("stepreturn 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 breakpoint 6");
+ // test set and clear
+ sendCommand("set 27 1");
+ sendCommand("set 29 1");
+ sendCommand("set 33 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 33");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 27");
+ sendCommand("clear 33");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 29");
+ // test var and setvar
+ sendCommand("set 47 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 47");
+ sendCommand("var 1 1 b", "4");
+ sendCommand("var 1 2 b", "2");
+ sendCommand("var 1 1 a", "0");
+ sendCommand("setvar 1 1 a 99");
+ sendCommand("data 1", "6|2|8|11|27|1|4|");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("var 1 1 a", "99");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("data 1", "6|2|8|11|27|1|4|99|");
+ sendCommand("var 1 1 x", "error: variable undefined");
+ sendCommand("setvar 1 1 x 100");
+ sendCommand("var 1 1 x", "100");
+ // test exit
+ sendCommand("exit");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testCommonDebugCommandsWithThreadRC() throws Throwable {
+ expectEvent("started 1");
+ // test breakpoint
+ sendCommand("set 3 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("suspended 1 breakpoint 3");
+ sendCommand("data 1", "6|7|8|");
+ // test step
+ sendCommand("step 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ // test data stack
+ sendCommand("data 1", "6|7|8|9|");
+ sendCommand("popdata 1");
+ sendCommand("data 1", "6|7|8|");
+ sendCommand("pushdata 1 11");
+ sendCommand("data 1", "6|7|8|11|");
+ sendCommand("setdata 1 1 2");
+ sendCommand("data 1", "6|2|8|11|");
+ // test call stack
+ sendCommand("set 12 0");
+ sendCommand("set 19 0");
+ sendCommand("stepreturn 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 breakpoint 12");
+ sendCommand("clear 19");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
+ sendCommand("stackdepth 1", "3");
+ sendCommand("frame 1 0", fProgram + "|6|main");
+ sendCommand("frame 1 1", fProgram + "|18|sub1|m|n");
+ sendCommand("frame 1 2", fProgram + "|12|sub2" );
+ sendCommand("stepreturn 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
+ sendCommand("stepreturn 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
+ sendCommand("set 6 0");
+ sendCommand("stepreturn 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 breakpoint 6");
+ // test set and clear
+ sendCommand("set 27 0");
+ sendCommand("set 29 0");
+ sendCommand("set 33 0");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("suspended 1 breakpoint 33");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("suspended 1 breakpoint 27");
+ sendCommand("clear 33");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("suspended 1 breakpoint 29");
+ // test var and setvar
+ sendCommand("set 47 0");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("suspended 1 breakpoint 47");
+ sendCommand("var 1 1 b", "4");
+ sendCommand("var 1 2 b", "2");
+ sendCommand("var 1 1 a", "0");
+ sendCommand("setvar 1 1 a 99");
+ sendCommand("data 1", "6|2|8|11|27|1|4|");
+ sendCommand("step 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("var 1 1 a", "99");
+ sendCommand("step 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("data 1", "6|2|8|11|27|1|4|99|");
+ // test exit
+ sendCommand("exit");
+ expectEvent("terminated");
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test3.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test3.java
new file mode 100644
index 00000000000..0569b7b26a3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test3.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test3 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest3.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testUncaughtEvents() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("unimplemented instruction foobar");
+ expectEvent("no such label zippy");
+ expectEvent("no such label swishy");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testCaughtUnimpinstrEvents() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("eventstop unimpinstr 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("unimplemented instruction foobar");
+ expectEvent("vmsuspended 1 event unimpinstr");
+ sendCommand("eventstop unimpinstr 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("unimplemented instruction foobar");
+ expectEvent("no such label zippy");
+ expectEvent("no such label swishy");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testCaughtNosuchlabelEvents() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("eventstop nosuchlabel 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("unimplemented instruction foobar");
+ expectEvent("no such label zippy");
+ expectEvent("vmsuspended 1 event nosuchlabel");
+ sendCommand("eventstop nosuchlabel 0");
+ sendCommand("set 11 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("no such label zippy");
+ expectEvent("vmsuspended 1 breakpoint 11");
+ sendCommand("eventstop nosuchlabel 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("no such label swishy");
+ expectEvent("vmsuspended 1 event nosuchlabel");
+ sendCommand("eventstop nosuchlabel 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("no such label swishy");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test6.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test6.java
new file mode 100644
index 00000000000..d1241a98a1f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test6.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test6 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest6.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testWatchPoints() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("watch inner::a 1");
+ sendCommand("watch main::a 2");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 watch write main::a");
+ sendCommand("stack 1", fProgram + "|4|main|a|b");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 watch read inner::a");
+ sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c");
+ sendCommand("watch inner::a 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testEval() throws Throwable {
+ expectEvent("started 1");
+
+ sendCommand("eval 1 test_error", "error: cannot evaluate while vm is suspended");
+
+ sendCommand("set 25 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("suspended 1 breakpoint 25");
+
+ sendCommand("eval 1 push%204|push%205|add");
+ expectEvent("resumed 1 eval");
+ expectEvent("evalresult 9");
+ expectEvent("suspended 1 eval");
+
+ sendCommand("step 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
+ sendCommand("data 1", "4|4|");
+ sendCommand("eval 1 call%20other");
+ expectEvent("resumed 1 eval");
+ expectEvent("evalresult 15");
+ expectEvent("suspended 1 eval");
+ sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
+ sendCommand("data 1", "4|4|");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test8.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test8.java
new file mode 100644
index 00000000000..d09e8bf80ac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test8.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test8 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest8.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testDropFrame() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
+ sendCommand("drop 1");
+ expectEvent("vmresumed drop");
+ expectEvent("vmsuspended 1 drop");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testDropFrameWithThreadRC() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("set 12 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("suspended 1 breakpoint 12");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
+ sendCommand("drop 1");
+ expectEvent("resumed 1 drop");
+ expectEvent("suspended 1 drop");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
+ sendCommand("step 1");
+ expectEvent("resumed 1 step");
+ expectEvent("suspended 1 step");
+ sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
+ sendCommand("clear 12");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("exited 1");
+ expectEvent("terminated");
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test9.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test9.java
new file mode 100644
index 00000000000..b9b92631d38
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/service/command/Test9.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.tests.dsf.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.cdt.examples.dsf.pda.PDAPlugin;
+import org.eclipse.core.runtime.Path;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class Test9 extends CommandControlTestsBase {
+
+ @BeforeClass
+ public static void setProgram() {
+ File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest9.pda"));
+
+ fProgram = programFile.getPath();
+ }
+
+ @Test
+ public void testThreadsWithVMRC() throws Throwable {
+ expectEvent("started 1");
+ sendCommand("state", "client");
+ sendCommand("state 1", "vm");
+
+ // Check error responses
+ sendCommand("vmsuspend", "error: vm already suspended");
+ sendCommand("resume 1", "error: cannot resume thread when vm is suspended");
+
+ // Run to thread create routine
+ sendCommand("threads", "1");
+ sendCommand("set 2 1");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("vmsuspended 1 breakpoint 2");
+ sendCommand("state", "1 breakpoint 2");
+ sendCommand("state 1", "vm");
+
+ // Step over first thread create
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("started 2");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("state", "1 step");
+ sendCommand("state 1", "vm");
+ sendCommand("threads", "1 2");
+ sendCommand("stack 1", fProgram + "|3|main");
+ sendCommand("stack 2", fProgram + "|9|foo");
+ sendCommand("step 1");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 1 step");
+ sendCommand("stack 1", fProgram + "|4|main");
+ sendCommand("stack 2", fProgram + "|10|foo");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectOutput("thread_created");
+ expectEvent("vmsuspended 1 breakpoint 2");
+
+ // Step over second thread create
+ sendCommand("step 2");
+ expectEvent("vmresumed step");
+ expectEvent("started 3");
+ expectEvent("vmsuspended 2 step");
+ sendCommand("threads", "1 2 3");
+ sendCommand("stack 1", fProgram + "|3|main");
+ sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|15|inner");
+ sendCommand("stack 3", fProgram + "|9|foo");
+ sendCommand("step 3");
+ expectEvent("vmresumed step");
+ expectEvent("vmsuspended 3 step");
+ sendCommand("stack 1", fProgram + "|4|main");
+ sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|16|inner|b");
+ sendCommand("stack 3", fProgram + "|10|foo");
+
+ // Run to the end and watch threads starting/exiting.
+ sendCommand("clear 2");
+ sendCommand("vmresume");
+ expectOutput("thread_created");
+ expectEvent("vmresumed client");
+ expectEvent("started 4");
+ expectEvent("exited 2");
+ expectEvent("started 5");
+ expectEvent("exited 3");
+ expectEvent("started 6");
+ expectEvent("exited 4");
+ expectEvent("exited 1");
+ expectEvent("exited 5");
+ expectEvent("exited 6");
+ expectEvent("terminated");
+ }
+
+ @Test
+ public void testThreadsWithThreadRC() throws Throwable {
+ expectEvent("started 1");
+
+ // Check error responses for thread run control
+ sendCommand("set 1 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("suspended 1 breakpoint 1");
+ sendCommand("state", "running");
+ sendCommand("state 1", "breakpoint 1");
+
+ sendCommand("resume", "error: invalid thread");
+ sendCommand("vmresume", "error: vm already running");
+ sendCommand("clear 1");
+ sendCommand("suspend 1", "error: thread already suspended");
+ sendCommand("vmsuspend");
+ expectEvent("vmsuspended client");
+ sendCommand("state", "client");
+ sendCommand("state 1", "vm");
+ sendCommand("suspend 1", "error: vm already suspended");
+ sendCommand("resume 1", "error: cannot resume thread when vm is suspended");
+
+ // Create breakpoints at thread create and thread entry point.
+ sendCommand("set 2 0");
+ sendCommand("set 10 0");
+ sendCommand("vmresume");
+ expectEvent("vmresumed client");
+ expectEvent("suspended 1 breakpoint 2");
+
+ // Create first thread, and run it to completion
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("started 2");
+ expectEvent("suspended 2 breakpoint 10");
+ expectEvent("suspended 1 breakpoint 2");
+ sendCommand("state 1", "breakpoint 2");
+ sendCommand("state 2", "breakpoint 10");
+ sendCommand("threads", "1 2");
+ sendCommand("resume 2");
+ expectEvent("resumed 2 client");
+ expectEvent("exited 2");
+ sendCommand("threads", "1");
+
+ // Create second thread, step it
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("started 3");
+ expectEvent("suspended 3 breakpoint 10");
+ expectEvent("suspended 1 breakpoint 2");
+ sendCommand("threads", "1 3");
+ sendCommand("stack 1", fProgram + "|2|main");
+ sendCommand("stack 3", fProgram + "|10|foo");
+ sendCommand("step 3");
+ expectEvent("resumed 3 step");
+ expectEvent("suspended 3 step");
+ sendCommand("state 1", "breakpoint 2");
+ sendCommand("state 3", "step");
+ sendCommand("stack 1", fProgram + "|2|main");
+ sendCommand("stack 3", fProgram + "|11|foo");
+
+ // Create the rest of threads
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("started 4");
+ expectEvent("suspended 4 breakpoint 10");
+ expectEvent("suspended 1 breakpoint 2");
+ sendCommand("threads", "1 3 4");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+ expectEvent("started 5");
+ expectEvent("suspended 5 breakpoint 10");
+ expectEvent("suspended 1 breakpoint 2");
+ sendCommand("threads", "1 3 4 5");
+ sendCommand("resume 1");
+ expectEvent("resumed 1 client");
+
+ // Main thread exits
+ expectEvent("started 6");
+ expectEvent("suspended 6 breakpoint 10");
+ expectEvent("exited 1");
+ sendCommand("threads", "3 4 5 6");
+
+ // Exit
+ sendCommand("exit");
+ expectEvent("terminated");
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/util/Launching.java b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/util/Launching.java
new file mode 100644
index 00000000000..9917854a05b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf.pda/src/org/eclipse/cdt/tests/dsf/pda/util/Launching.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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
+ * Nokia - create and use backend service.
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.pda.util;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.pda.service.PDABackend;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.Launch;
+
+/**
+ *
+ */
+public class Launching {
+
+ private static PDABackend fBackendService;
+
+ public static Process launchPDA(DsfSession session, Launch launch, String pdaProgram) throws CoreException {
+
+ class InitializeBackendServiceQuery extends Query<Object> {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ fBackendService.initialize(rm);
+ }
+ };
+
+ fBackendService = new PDABackend(session, launch, pdaProgram);
+ InitializeBackendServiceQuery initQuery = new InitializeBackendServiceQuery();
+ session.getExecutor().execute(initQuery);
+ try {
+ initQuery.get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ return null;
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ return fBackendService.getProcess();
+ }
+
+ public static PDABackend getBackendService() {
+ return fBackendService;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/.classpath b/dsf/org.eclipse.cdt.examples.dsf/.classpath
new file mode 100644
index 00000000000..5f6c0064a2e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/.classpath
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src_ant"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/.externalToolBuilders/PreProcessor.launch b/dsf/org.eclipse.cdt.examples.dsf/.externalToolBuilders/PreProcessor.launch
new file mode 100644
index 00000000000..dbd1fe8affe
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/.externalToolBuilders/PreProcessor.launch
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
+<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
+<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"/>
+<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;launchConfigurationWorkingSet editPageId=&quot;org.eclipse.ui.resourceWorkingSetPage&quot; factoryID=&quot;org.eclipse.ui.internal.WorkingSetFactory&quot; label=&quot;workingSet&quot; name=&quot;workingSet&quot;&gt;&#10;&lt;item factoryID=&quot;org.eclipse.ui.internal.model.ResourceFactory&quot; path=&quot;/org.eclipse.dd.examples.dsf/src_preprocess&quot; type=&quot;2&quot;/&gt;&#10;&lt;/launchConfigurationWorkingSet&gt;}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/org.eclipse.cdt.examples.dsf/build_preprocess.xml}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
+<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
+</launchConfiguration>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/.project b/dsf/org.eclipse.cdt.examples.dsf/.project
new file mode 100644
index 00000000000..c3e61028def
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/.project
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.examples.dsf</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>
+ <buildCommand>
+ <name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>LaunchConfigHandle</key>
+ <value>&lt;project&gt;/.externalToolBuilders/PreProcessor.launch</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.examples.dsf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..2c5e26be9e4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,71 @@
+#Tue Jun 24 11:03:17 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=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=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeUncheckedExceptions=disabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.examples.dsf/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..94ceea3145d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Vendor: %providerName
+Bundle-SymbolicName: org.eclipse.cdt.examples.dsf;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.examples.dsf.DsfExamplesPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.debug.ui,
+ org.eclipse.cdt.dsf,
+ org.eclipse.ui,
+ org.eclipse.cdt.dsf.ui,
+ org.apache.ant;bundle-version="1.7.0";resolution:=optional
+Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.examples.dsf/about.html b/dsf/org.eclipse.cdt.examples.dsf/about.html
new file mode 100644
index 00000000000..cb740ae8bc8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/about.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>About</title></head><body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>June 5, 2007</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf/build.properties b/dsf/org.eclipse.cdt.examples.dsf/build.properties
new file mode 100644
index 00000000000..e061b4e53d0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/build.properties
@@ -0,0 +1,17 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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
+###############################################################################
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ plugin.properties,\
+ about.html
diff --git a/dsf/org.eclipse.cdt.examples.dsf/build_preprocess.xml b/dsf/org.eclipse.cdt.examples.dsf/build_preprocess.xml
new file mode 100644
index 00000000000..6183be5cf6c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/build_preprocess.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0"?>
+<!-- ======================================================================
+ 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
+ Wind River Systems - adopted to use with DSF
+
+ EclipseCon
+ DSF Tutorial Exercises
+ ====================================================================== -->
+<project name="EclipseCon" default="generateAll">
+ <description>
+ DSF Tutorial Exercises
+ </description>
+
+ <taskdef name="preprocess" classname="org.eclipse.cdt.examples.ant.tasks.PreProcessor" classpath="bin" />
+ <property name="$workspace" location="c:\eclipse-dev\dev-3.4" />
+ <property name="srcBase" location="${workspace}/org.eclipse.cdt.examples.dsf/src_preprocess" />
+ <property name="destBase" location="${workspace}/org.eclipse.cdt.examples.dsf/src" />
+
+ <!-- =================================
+ target: generateAll
+ ================================= -->
+ <target name="generateAll" description="--> DSF Tutorial Exercises">
+
+ <!-- = = = = = = = = = = = = = = = = =
+ macrodef: process
+ = = = = = = = = = = = = = = = = = -->
+ <macrodef name="process">
+ <attribute name="packagedir"/>
+ <sequential>
+ <delete dir="src/@{packagedir}"/>
+ <mkdir dir="src/@{packagedir}"/>
+ <mkdir dir="src/@{packagedir}/answers"/>
+ <preprocess destdir="src/@{packagedir}" symbols="exercises">
+ <fileset dir="src_preprocess/@{packagedir}"/>
+ </preprocess>
+ <preprocess destdir="src/@{packagedir}/answers" symbols="answers">
+ <fileset dir="src_preprocess/@{packagedir}"/>
+ </preprocess>
+ </sequential>
+ </macrodef>
+
+ <process packagedir="org/eclipse/cdt/examples/dsf/requestmonitor"/>
+ <process packagedir="org/eclipse/cdt/examples/dsf/dataviewer"/>
+ </target>
+
+</project>
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/alarm.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/alarm.gif
new file mode 100644
index 00000000000..33cc76e9dc5
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/alarm.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/alarm_triggered.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/alarm_triggered.gif
new file mode 100644
index 00000000000..609dbb7269c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/alarm_triggered.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/layout.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/layout.gif
new file mode 100644
index 00000000000..4a07fffc16a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/layout.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/remove.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/remove.gif
new file mode 100644
index 00000000000..2cd9c544436
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/remove.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/sample.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/sample.gif
new file mode 100644
index 00000000000..34fb3c9d8cb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/sample.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/icons/timer.gif b/dsf/org.eclipse.cdt.examples.dsf/icons/timer.gif
new file mode 100644
index 00000000000..6089d528ce0
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/icons/timer.gif
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/plugin.properties b/dsf/org.eclipse.cdt.examples.dsf/plugin.properties
new file mode 100644
index 00000000000..79a07a28bc3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2006, 2008 Wind River Systems 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=Debugger Services Framework Examples
+providerName=Eclipse.org
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf/plugin.xml b/dsf/org.eclipse.cdt.examples.dsf/plugin.xml
new file mode 100644
index 00000000000..afe5a8574a2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/plugin.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <category
+ name="DSF Examples"
+ id="org.eclipse.cdt.examples.dsf">
+ </category>
+ <view
+ name="Timers View"
+ icon="icons/timer.gif"
+ category="org.eclipse.cdt.examples.dsf"
+ class="org.eclipse.cdt.examples.dsf.timers.TimersView"
+ id="org.eclipse.cdt.examples.dsf.TimersView">
+ </view>
+ </extension>
+ <extension
+ point="org.eclipse.ui.actionSets">
+ <actionSet
+ id="org.eclipse.cdt.dsf.test.actionSet"
+ label="DSF Examples">
+ <menu
+ id="org.eclipse.cdt.examples.dsf"
+ label="DSF Examples"
+ path="additions">
+ <groupMarker name="concurrent"/>
+ </menu>
+ <action
+ class="org.eclipse.cdt.examples.dsf.filebrowser.FileBrowserAction"
+ id="org.eclipse.cdt.dsf.test.fileBrowser"
+ label="Open File Browser Dialog"
+ menubarPath="org.eclipse.cdt.examples.dsf/concurrent"
+ style="push"/>
+ </actionSet>
+ </extension>
+
+</plugin>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java
new file mode 100644
index 00000000000..8799f748c88
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/DsfExamplesPlugin.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfExamplesPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.examples.dsf"; //$NON-NLS-1$
+
+ public static final String IMG_LAYOUT_TOGGLE = "icons/layout.gif"; //$NON-NLS-1$
+ public static final String IMG_ALARM = "icons/alarm.gif"; //$NON-NLS-1$
+ public static final String IMG_ALARM_TRIGGERED = "icons/alarm_triggered.gif"; //$NON-NLS-1$
+ public static final String IMG_TIMER = "icons/timer.gif"; //$NON-NLS-1$
+ public static final String IMG_REMOVE = "icons/remove.gif"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfExamplesPlugin fgPlugin;
+
+ private static BundleContext fgBundleContext;
+
+ /**
+ * The constructor
+ */
+ public DsfExamplesPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ getImageRegistry().put(IMG_ALARM, imageDescriptorFromPlugin(PLUGIN_ID, IMG_ALARM));
+ getImageRegistry().put(IMG_ALARM_TRIGGERED, imageDescriptorFromPlugin(PLUGIN_ID, IMG_ALARM_TRIGGERED));
+ getImageRegistry().put(IMG_TIMER, imageDescriptorFromPlugin(PLUGIN_ID, IMG_TIMER));
+ getImageRegistry().put(IMG_REMOVE, imageDescriptorFromPlugin(PLUGIN_ID, IMG_REMOVE));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ fgPlugin = null;
+ fgBundleContext = null;
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfExamplesPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+ /**
+ * Returns an image descriptor for the image file at the given
+ * plug-in relative path
+ *
+ * @param path the path
+ * @return the image descriptor
+ */
+ public static ImageDescriptor getImageDescriptor(String path) {
+ return imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java
new file mode 100644
index 00000000000..2e686f5c8d1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserAction.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.actions.ActionDelegate;
+
+/**
+ * Action that opens the File Browser example dialog.
+ */
+public class FileBrowserAction extends ActionDelegate
+ implements IWorkbenchWindowActionDelegate
+{
+ private IWorkbenchWindow fWindow;
+
+ @Override
+ public void run(IAction action) {
+ if (fWindow != null) {
+ // Create the dialog and open it.
+ Dialog dialog = new FileBrowserDialog(fWindow.getShell());
+ dialog.open();
+ }
+ }
+
+ public void init(IWorkbenchWindow window) {
+ fWindow = window;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java
new file mode 100644
index 00000000000..807913c0216
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserDialog.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * File Browser example dialog. It hold a tree viewer that displays
+ * file system contents and a text box for entering a file path to be
+ * shown in the tree.
+ */
+@SuppressWarnings("restriction")
+public class FileBrowserDialog extends Dialog {
+
+ /**
+ * Tree viewer for showing the filesystem contents.
+ */
+ private TreeModelViewer fViewer;
+
+ /**
+ * The model adapter for the tree viewer.
+ */
+ private FileBrowserModelAdapter fModelAdapter;
+
+ /**
+ * Flag used to disable text-box changed events, when the text
+ * box is updated due to selection change in tree.
+ */
+ private boolean fDisableTextChangeNotifications = false;
+
+ public FileBrowserDialog(Shell parent) {
+ super(parent);
+ setShellStyle(getShellStyle() | SWT.RESIZE);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite area = (Composite) super.createDialogArea(parent);
+ IPresentationContext presentationContext = new PresentationContext("org.eclipse.cdt.examples.dsf.filebrowser"); //$NON-NLS-1$
+
+ fViewer = new TreeModelViewer(area, SWT.VIRTUAL, presentationContext);
+ fViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ fModelAdapter = new FileBrowserModelAdapter(presentationContext);
+ fViewer.setInput(fModelAdapter.getVMProvider().getViewerInputObject());
+
+ final Text text = new Text(area, SWT.SINGLE | SWT.BORDER);
+ text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ public void selectionChanged(SelectionChangedEvent event) {
+ /*
+ * Update the file name in the text control, to match the
+ * selection in the tree. Do this only if the user is not
+ * actively typing in the text field (test if text has focus).
+ */
+ if (!text.isFocusControl() &&
+ event.getSelection() instanceof IStructuredSelection &&
+ ((IStructuredSelection)event.getSelection()).getFirstElement() instanceof FileVMContext)
+ {
+ FileVMContext fileVmc = (FileVMContext)((IStructuredSelection)event.getSelection()).getFirstElement();
+
+ fDisableTextChangeNotifications = true;
+ text.setText(fileVmc.getFile().getAbsolutePath());
+ fDisableTextChangeNotifications = false;
+ }
+ }
+ });
+
+ text.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ if (!fDisableTextChangeNotifications) {
+ fModelAdapter.getVMProvider().selectionTextChanged(text.getText());
+ }
+ }
+ });
+
+ return area;
+ }
+
+ @Override
+ public boolean close() {
+ if (super.close()) {
+ fModelAdapter.dispose();
+ fModelAdapter = null;
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java
new file mode 100644
index 00000000000..497b31f45c1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserModelAdapter.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ * This is the adapter that implements the flexible hierarchy viewer interfaces
+ * for providing content, labels, and event proxy-ing for the viewer. This
+ * adapter is registered with the DSF Session object, and is returned by the
+ * IDMContext.getAdapter() and IVMContext.getAdapter() methods,
+ * which both call {@link DsfSession#getModelAdapter(Class)}.
+ * <p>
+ * The adapter implementation for this exercise is hard-coded to provide
+ * contents for only one view. In turn the view contents are determined using
+ * the configurable ViewModelProvider. For demonstration purposes, this model
+ * adapter has two different layout configurations that can be used. These
+ * layout configurations can be set by calling the {@link #setViewLayout} method.
+ * <p>
+ * This class is primarily accessed by the flexible hierarchy viewer from a
+ * non-executor thread. So the class is thread-safe, except for a view methods
+ * which must be called on the executor thread.
+ *
+ * @see AbstractDMVMProvider
+ */
+@SuppressWarnings("restriction")
+@ThreadSafe
+public class FileBrowserModelAdapter extends AbstractVMAdapter
+{
+ FileBrowserVMProvider fViewModelProvider;
+
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ /*
+ * In this example there is only one viewer, so there is only one
+ * VMProvider.
+ */
+ return fViewModelProvider;
+ }
+
+ public FileBrowserModelAdapter(IPresentationContext presentationContext) {
+ super();
+ fViewModelProvider = new FileBrowserVMProvider(this, presentationContext);
+ }
+
+ FileBrowserVMProvider getVMProvider() {
+ return fViewModelProvider;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java
new file mode 100644
index 00000000000..ef3d098bb9c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileBrowserVMProvider.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.RootVMNode;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class FileBrowserVMProvider extends AbstractVMProvider
+{
+ /**
+ * The object to be set to the viewer that shows contents supplied by this provider.
+ * @see org.eclipse.jface.viewers.TreeViewer#setInput(Object)
+ */
+ private final IAdaptable fViewerInputObject =
+ new IAdaptable() {
+ /**
+ * The input object provides the viewer access to the viewer model adapter.
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if ( adapter.isInstance(getVMAdapter()) ) {
+ return getVMAdapter();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "File Browser Viewer Input"; //$NON-NLS-1$
+ }
+ };
+
+ /**
+ * Constructor creates and configures the layout nodes to display file
+ * system contents.
+ * @param adapter The viewer model adapter that this provider is registered with.
+ * @param presentationContext The presentation context that this provider is
+ * generating contents for.
+ */
+ public FileBrowserVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext) {
+ super(adapter, presentationContext);
+
+ IRootVMNode root = new RootVMNode(this);
+ IVMNode fileSystemRoots = new FilesystemRootsVMNode(this);
+ addChildNodes(root, new IVMNode[] { fileSystemRoots });
+ IVMNode files = new FileVMNode(this);
+ addChildNodes(fileSystemRoots, new IVMNode[] { files });
+ addChildNodes(files, new IVMNode[] { files });
+ setRootNode(root);
+ }
+
+ /**
+ * Returns the input object to be set to the viewer that shows contents
+ * supplied by this provider.
+ */
+ public Object getViewerInputObject() {
+ return fViewerInputObject;
+ }
+
+ /**
+ * Event handler for file selection text changes in the dialog.
+ * @param text New text entered in file selection text box.
+ */
+ void selectionTextChanged(final String text) {
+ if (isDisposed()) return;
+
+ // We're in the UI thread. Re-dispach to VM Adapter executor thread
+ // and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ handleEvent(text);
+ }});
+ } catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java
new file mode 100644
index 00000000000..93b8da64e9e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMContext.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+
+class FileVMContext extends AbstractVMContext {
+ private File fFile;
+ FileVMContext(IVMNode layoutNode, File file) {
+ super(layoutNode);
+ fFile = file;
+ }
+
+ File getFile() { return fFile; }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof FileVMContext && ((FileVMContext)obj).getFile().equals(fFile);
+ }
+
+ @Override
+ public int hashCode() {
+ return fFile.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return fFile.toString();
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java
new file mode 100644
index 00000000000..e137dad245f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FileVMNode.java
@@ -0,0 +1,314 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.internal.ui.DsfUIPlugin;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+
+
+/**
+ * File view model node which returns file elements that are found in the directory
+ * specified by the parent element. The child nodes of this node are fixed to
+ * reference this element, and therefore this node will recursively populate
+ * the contents of the tree reflecting the underlying filesystem directories.
+ * <br>
+ * Note: this node does NOT sub-class the {@link org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode}
+ */
+@SuppressWarnings("restriction")
+class FileVMNode
+ implements IElementLabelProvider, IVMNode
+{
+ /**
+ * Reference to the viewer model provider. It's mainly used to access the
+ * viewer model adapter and its executor.
+ */
+ private final FileBrowserVMProvider fProvider;
+
+ public FileVMNode(FileBrowserVMProvider provider) {
+ fProvider = provider;
+ }
+
+ @Override
+ public String toString() {
+ return "FileVMNode";
+ }
+
+
+ public void dispose() {
+ // All resources garbage collected.
+ }
+
+ public void setChildNodes(IVMNode[] childNodes) {
+ throw new UnsupportedOperationException("This node does not support children."); //$NON-NLS-1$
+ }
+
+ /**
+ * List of child nodes containing only a reference to this.
+ */
+ private final IVMNode[] fChildNodes = { this };
+
+ public IVMNode[] getChildNodes() {
+ return fChildNodes;
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IHasChildrenUpdate update : updates) {
+ /*
+ * Do not retrieve directory contents just to mark the plus
+ * sign in the tree. If it's a directory, just assume that
+ * it has children.
+ */
+ FileVMContext vmc = (FileVMContext)update.getElement();
+ update.setHasChilren(vmc.getFile().isDirectory());
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenCountUpdate update : updates) {
+ update.setChildCount(getFiles(update).length);
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenUpdate update : updates) {
+ File[] files = getFiles(update);
+ int offset = update.getOffset() != -1 ? update.getOffset() : 0;
+ int length = update.getLength() != -1 ? update.getLength() : files.length;
+ for (int i = offset; (i < files.length) && (i < (offset + length)); i++) {
+ update.setChild(new FileVMContext(FileVMNode.this, files[i]), i);
+ }
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel(getLabel((FileVMContext)update.getElement()), 0);
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ private static final File[] EMPTY_FILE_LIST = new File[0];
+
+ /**
+ * Retrieves the list of files for this node. The list of files is based
+ * on the parent element in the tree, which must be of type FileVMC.
+ *
+ * @param update Update object containing the path (and the parent element)
+ * in the tree viewer.
+ * @return List of files contained in the directory specified in the
+ * update object. An empty list if the parent element is not a directory.
+ * @throws ClassCastException If the parent element contained in the update
+ * is NOT of type FileVMC.
+ */
+ private File[] getFiles(IViewerUpdate update) {
+ FileVMContext vmc = (FileVMContext)update.getElement();
+ File[] files = vmc.getFile().listFiles();
+ return files != null ? files : EMPTY_FILE_LIST;
+ }
+
+ /**
+ * Returs the text label to show in the tree for given element.
+ */
+ private String getLabel(FileVMContext vmc) {
+ return vmc.getFile().getName();
+ }
+
+ public void getContextsForEvent(VMDelta parentDelta, Object event, DataRequestMonitor<IVMContext[]> rm) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfUIPlugin.PLUGIN_ID, IDsfStatusConstants.NOT_SUPPORTED, "", null)); //$NON-NLS-1$
+ rm.done();
+ }
+
+ public int getDeltaFlags(Object e) {
+ /*
+ * @see buildDelta()
+ */
+ int retVal = IModelDelta.NO_CHANGE;
+ if (e instanceof String) {
+ retVal |= IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+
+ return retVal;
+ }
+
+ public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ /*
+ * The FileLayoutNode is recursive, with itself as the only child. In this
+ * method the delta is calculated for a full path VMContext elements, and the
+ * implementation of this method is not recursive.
+ */
+ if (event instanceof String) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ /*
+ * Requirements for a selection event to be issued is that the file exist, and
+ * that the parentDelta contain a FileVMC of a parent directory as its element.
+ *
+ * The test for first the former requirement could be performed inside getDeltaFlags()
+ * but getDeltaFlags() is synchronous, so it is better to perform this test here using
+ * a background thread (job).
+ *
+ * The latter is requirement is needed because this node does not have the algorithm
+ * calculate the complete list of root nodes. That algorithm is implemented inside the
+ * {@link FileSystemRootsLayoutNode#updateElements} method.
+ */
+
+ final File eventFile = new File((String)event);
+ File parentFile = null;
+ if (parentDelta.getElement() instanceof FileVMContext) {
+ parentFile = ((FileVMContext)parentDelta.getElement()).getFile();
+ }
+
+ // The file has to exist in order for us to be able to select
+ // it in the tree.
+ if (eventFile.exists() && parentFile != null) {
+ // Create a list containing all files in path
+ List<File> filePath = new LinkedList<File>();
+ for (File file = eventFile; file != null && !file.equals(parentFile); file = file.getParentFile()) {
+ filePath.add(0, file);
+ }
+
+ if (filePath.size() != 0) {
+ // Build the delta for all files in path.
+ ModelDelta delta = parentDelta;
+ File[] allFilesInDirectory = parentFile.listFiles();
+ for (File pathSegment : filePath) {
+ // All files in path should be directories, and should therefore
+ // have a valid list of elements.
+ assert allFilesInDirectory != null;
+
+ File[] pathSegmentDirectoryFiles = pathSegment.listFiles();
+ delta = delta.addNode(
+ new FileVMContext(FileVMNode.this, pathSegment),
+ nodeOffset + Arrays.asList(allFilesInDirectory).indexOf(pathSegment),
+ IModelDelta.NO_CHANGE,
+ pathSegmentDirectoryFiles != null ? pathSegmentDirectoryFiles.length : 0);
+ allFilesInDirectory = pathSegmentDirectoryFiles;
+ }
+
+ // The last file in path gets the EXPAND | SELECT flags.
+ delta.setFlags(delta.getFlags() | IModelDelta.SELECT | IModelDelta.EXPAND);
+ }
+ }
+
+ // Invoke the request monitor.
+
+ requestMonitor.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ } else {
+ requestMonitor.done();
+ }
+ }
+
+ /**
+ * Override the behavior which checks for delta flags of all the child nodes,
+ * because we would get stuck in a recursive loop. Instead call only the child
+ * nodes which are not us.
+ */
+ protected Map<IVMNode, Integer> getChildNodesWithDeltas(Object e) {
+ Map<IVMNode, Integer> nodes = new HashMap<IVMNode, Integer>();
+ for (final IVMNode childNode : getChildNodes()) {
+ int delta = childNode.getDeltaFlags(e);
+ if (delta != IModelDelta.NO_CHANGE) {
+ nodes.put(childNode, delta);
+ }
+ }
+ return nodes;
+ }
+
+ public IVMProvider getVMProvider() {
+ return fProvider;
+ }
+
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java
new file mode 100644
index 00000000000..a2eb938da95
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/FilesystemRootsVMNode.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.filebrowser;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+
+
+/**
+ * Viewer model node that populates the filesystem root elements.
+ */
+@SuppressWarnings("restriction")
+class FilesystemRootsVMNode extends AbstractVMNode
+ implements IElementLabelProvider
+{
+ public FilesystemRootsVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public String toString() {
+ return "FilesystemRootsVMNode";
+ }
+
+ public void update(final IChildrenUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ File[] files = File.listRoots();
+ for (IChildrenUpdate update : updates) {
+ int offset = update.getOffset() != -1 ? update.getOffset() : 0;
+ int length = update.getLength() != -1 ? update.getLength() : files.length;
+ for (int i = offset; (i < files.length) && (i < (offset + length)); i++) {
+ update.setChild(new FileVMContext(FilesystemRootsVMNode.this, files[i]), i);
+ }
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final IHasChildrenUpdate[] updates) {
+ for (IHasChildrenUpdate update : updates) {
+ /*
+ * Assume that all filesystem roots have children. If user attempts
+ * to expand an empty directory, the plus sign will be removed
+ * from the element.
+ */
+ update.setHasChilren(true);
+ update.done();
+ }
+ }
+
+ public void update(final IChildrenCountUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (IChildrenCountUpdate update : updates) {
+ if (!checkUpdate(update)) continue;
+ update.setChildCount(File.listRoots().length);
+ update.done();
+ }
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel(getLabel((FileVMContext)update.getElement()), 0);
+ update.done();
+ }
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+
+ /**
+ * Returs the text label to show in the tree for given element. Filesystem
+ * roots return an empty string for call to File.getName(), use the abolute path
+ * string instead.
+ */
+ private String getLabel(FileVMContext vmc) {
+ return vmc.getFile().getAbsolutePath();
+ }
+
+ public int getDeltaFlags(Object e) {
+ /*
+ * @see buildDelta()
+ */
+ int retVal = IModelDelta.NO_CHANGE;
+ if (e instanceof String) {
+ retVal |= IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+
+ return retVal;
+ }
+
+ public void buildDelta(final Object event, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ if (event instanceof String) {
+ new Job("") { //$NON-NLS-1$
+ {
+ setSystem(true);
+ setPriority(INTERACTIVE);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ final File eventFile = new File((String)event);
+
+ if (eventFile.exists()) {
+ // Create a list containing all files in path of the file from the event
+ List<File> filePath = new LinkedList<File>();
+ for (File file = eventFile; file != null; file = file.getParentFile()) {
+ filePath.add(0, file);
+ }
+ File eventRoot = filePath.get(0);
+
+ // Get the index of the file in list of filesystem roots.
+ File[] roots = File.listRoots();
+
+ int index = 0;
+ for (; index < roots.length; index++) {
+ if (eventRoot.equals(roots[index])) break;
+ }
+
+ // Check if the specified file is not one of the roots.
+ if (index < roots.length) {
+ ModelDelta delta = parentDelta.addNode(
+ new FileVMContext(FilesystemRootsVMNode.this, eventRoot),
+ index, IModelDelta.NO_CHANGE);
+
+ if (eventFile.equals(eventRoot)) {
+ // The event is for the root node. Select it and extend parent node.
+ delta.setFlags(delta.getFlags() | IModelDelta.SELECT | IModelDelta.EXPAND);
+ }
+ }
+ }
+
+ // Invoke the request monitor.
+ requestMonitor.done();
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ } else {
+ requestMonitor.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html
new file mode 100644
index 00000000000..865be837a58
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/filebrowser/package.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>DSF Filesystem Browser Example</title>
+</head>
+<body>
+<h2>DSF Filesystem Browser Example</h2>
+<h3>Goals</h3>
+This example demonstrates an implementation of a viewer model with a
+layout node that has itself as a child.&nbsp; Such layout nodes are
+needed to represents elements which themselves have a natural tree
+structures.&nbsp; This example uses filesystem folders as the
+tree-structured data, which is retrieved directly from the java.io.File
+class.&nbsp; This example also demonstrates a viewer model
+implementation which does not retrieve data using DSF services and
+associated data model interfaces.&nbsp; <br>
+<h3><span style="font-weight: bold;">Design</span></h3>
+<span style="text-decoration: underline;">Model Adapter Hookup</span><br>
+A flexible-hierarchy tree viewer {@link
+org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer}
+is created within a model dialog.&nbsp; Corresponding {@link
+FileBrowserModelAdapter} and {@link FileBrowserVMProvider} classes are
+instanciated, and the root element object created by
+FileBrowserVMProvider is set as input to the tree viewer.&nbsp; From
+there FileBrowserModelAdapter is returned as the {@link
+IElementContentProvier} and {@link IModelProxyFactory} for all elements
+in the tree.<br>
+<br>
+<p><span style="text-decoration: underline;">Layout Nodes</span><br>
+There are three layout nodes:<br>
+</p>
+<ul>
+ <li>{@link FileBrowserVMProvider.VMRootLayoutNode} is just a root
+node, which generates the input element for the viewer.</li>
+ <li>{@link FilesystemRootsLayoutNode} retrieves the roots of the
+filesystem hierarchy ("C:\", "D:\", etc on Windows).&nbsp; <br>
+ </li>
+ <li>{@link FileLayoutNode} is a child of <span
+ style="font-family: monospace;">FilesystemRootsLayoutNode</span> and
+it recursively retrieves all folders and files under the given parent
+file element.&nbsp; This layout node does not allow any children nodes
+to be added to it, and it returns only itself as a child node (through
+a call to <span style="font-family: monospace;">IVMLayoutNode.getChildLayoutNodes</span>).<br>
+ </li>
+</ul>
+Both <span style="font-family: monospace;">FilesystemRootsLayoutNode</span>
+and <span style="font-family: monospace;">FileLayoutNode</span> create
+elements of the same type: {@link FileVMContext}.&nbsp; Additionally,
+when populating elements in the tree, the <span
+ style="font-family: monospace;">FileLayoutNode</span> requires that a <span
+ style="font-family: monospace;">FileVMContext</span> element be the
+parent element in order to be able to retrieve its children.&nbsp; <br>
+<span style="font-family: monospace;"></span>
+<p><span style="font-family: monospace;"></span></p>
+<span style="text-decoration: underline;">Event Handling/Generating
+Model Deltas</span><br>
+The view model responds to events generated by a text box in the
+dialog, where the user can type in a filesystem path.&nbsp; If the
+entered path resolves to a file on the filesystem, the view model
+generates a delta to select and reveal the given file in the
+tree.&nbsp; The two file layout nodes handle generating the delta in
+different ways:<br>
+<ul>
+ <li><span style="font-family: monospace;">FilesystemRootsLayoutNode</span>
+is a standard layout node.&nbsp; <br>
+ </li>
+ <ol>
+ <li>In the event handler implementation {@link
+org.eclipse.cdt.dsf.ui.viewermodel.IVMLayoutNode#buildDelta}, the user
+specified file-path is compared to the list of file-system roots.&nbsp;
+ <br>
+ </li>
+ <li>If the user file-path contains one of the filesystem roots, a
+new delta node is added for that root and the child layout node is
+called to continue the delta processing.&nbsp; <br>
+ </li>
+ <li>If the user file-path points to one of the filesystem roots,
+the <span style="font-family: monospace;">IModelDelta.SELECT</span>
+and <span style="font-family: monospace;">IModelDelta.EXPAND</span>
+flags are also added to the delta so that the root will be selected in
+the viewer.<br>
+ </li>
+ </ol>
+ <li><span style="font-family: monospace;">FileLayoutNode</span> is
+the special case, because it is a recusrive node.&nbsp; This node does
+not call any child nodes to process the delta, instead it calculates
+the delta for all file elements in user file-path, starting at the
+parent element. <br>
+ </li>
+ <ol>
+ <li>First the parent <span style="font-family: monospace;">FileVMContext</span>
+element is retrieved from the delta.&nbsp; <br>
+ </li>
+ <li>Then the user file-path is broken down into {@link
+java.io.File} objects representing each segment in the path, starting
+at the parent file element retrieved in step 1.</li>
+ <li>Then a delta node is added for each segment of the calculated
+path.&nbsp; <br>
+ </li>
+ <li><span style="font-family: monospace;">IModelDelta.SELECT</span>
+and <span style="font-family: monospace;">IModelDelta.EXPAND</span>
+flags are added to the last delta.<br>
+ </li>
+ </ol>
+</ul>
+<h3>How to use</h3>
+<ol>
+ <li>Make sure that the DSF examples menu is visible in the perspective</li>
+ <ul>
+ <li>Go to Windows -&gt; Customize Perspective...</li>
+ <li>Select Commands tab</li>
+ <li>Check the "DSF Examples" in the "Available command groups"
+table.</li>
+ </ul>
+ <li>Open the dialog by selecting DSF Examples-&gt;Open File Browser
+Dialog menu item.</li>
+ <li>Expand the items in the tree to see filesystem contents.</li>
+ <li>Select elements in the tree, to fill in text box with selected
+file's path.</li>
+ <li>Type in a file path in text box and have the tree expand to the
+specified element.<br>
+ </li>
+</ol>
+</body>
+</html>
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java
new file mode 100644
index 00000000000..3823930faf7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmService.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerTickDMEvent;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The alarm service tracks triggers and alarms. Triggers have a specified
+ * value and can be created and removed independently. Alarms are created
+ * for a specific timer and a trigger, and can indicate whether an alarm is
+ * triggered.
+ * <p>
+ * This service depends on the TimerService, so the TimerService has to be
+ * initialized before this service is initialized.
+ * </p>
+ */
+public class AlarmService extends AbstractDsfService
+{
+ /** Event indicating that the list of triggers is changed. */
+ @Immutable
+ public static class TriggersChangedEvent {}
+
+ /** Context representing an alarm tracked by this service. */
+ @Immutable
+ public static class TriggerDMContext extends AbstractDMContext {
+ /** Alarm number, also index into alarm map */
+ final int fNumber;
+
+ private TriggerDMContext(String sessionId, int number) {
+ super(sessionId, new IDMContext[0]);
+ fNumber = number;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return baseEquals(other) &&
+ ((TriggerDMContext)other).fNumber == fNumber;
+ }
+
+ public int getTriggerNumber() {
+ return fNumber;
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + fNumber;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".trigger[" + fNumber + "]";
+ }
+ }
+
+ /**
+ * Context representing the "triggered" status of an alarm with respect to
+ * a specific timer.
+ */
+ @Immutable
+ public static class AlarmDMContext extends AbstractDMContext {
+ // An alarm requires both a timer and alarm context, both of which
+ // become parents of the alarm context.
+ // Note: beyond the parent contexts this context does not contain
+ // any other data, because no other data is needed.
+ private AlarmDMContext(String sessionId,
+ TimerDMContext timerCtx, TriggerDMContext alarmCtx)
+ {
+ super(sessionId, new IDMContext[] { timerCtx, alarmCtx });
+ }
+
+ @Override
+ public boolean equals(Object other) { return baseEquals(other); }
+
+ @Override
+ public int hashCode() { return baseHashCode(); }
+
+ @Override
+ public String toString() {
+ return baseToString() + ":alarm"; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Event indicating that an alarm has been triggered by a timer.
+ */
+ public class AlarmTriggeredDMEvent extends AbstractDMEvent<AlarmDMContext> {
+ public AlarmTriggeredDMEvent(AlarmDMContext context) {
+ super(context);
+ }
+ }
+
+ private int fTriggerNumberCounter = 1;
+ private Map<TriggerDMContext, Integer> fTriggers =
+ new LinkedHashMap<TriggerDMContext, Integer>();
+
+ AlarmService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfExamplesPlugin.getDefault().getBundle().getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ // After super-class is finished initializing
+ // perform TimerService initialization.
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ // Add this class as a listener for service events, in order to receive
+ // TimerTickEvent events.
+ getSession().addServiceEventListener(this, null);
+
+ // Register service
+ register(new String[]{AlarmService.class.getName()}, new Hashtable<String,String>());
+
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor) {
+ getSession().removeServiceEventListener(this);
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+
+ public boolean isValid() { return true; }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(TimerTickDMEvent event) {
+ final TimerDMContext timerContext = event.getDMContext();
+
+ int timerValue = getServicesTracker().getService(TimerService.class).
+ getTimerValue(event.getDMContext());
+
+ // If a timer triggers an alarm, this service needs to issue an alarm
+ // triggered event.
+ checkAlarmsForTimer(timerContext, timerValue);
+ }
+
+ private void checkAlarmsForTimer(TimerDMContext timerContext, int timerValue) {
+ // Check the existing alarms for whether they are triggered by given
+ // timer.
+ for (Map.Entry<TriggerDMContext, Integer> entry : fTriggers.entrySet()) {
+ if (timerValue == entry.getValue()) {
+ // Generate the AlarmTriggeredEvent
+ AlarmDMContext alarmCtx = new AlarmDMContext(
+ getSession().getId(), timerContext, entry.getKey());
+ getSession().dispatchEvent(
+ new AlarmTriggeredDMEvent(alarmCtx), getProperties());
+ }
+ }
+ }
+
+
+ /** Returns the list of triggers. */
+ public TriggerDMContext[] getTriggers() {
+ return fTriggers.keySet().toArray(new TriggerDMContext[fTriggers.size()]);
+ }
+
+ /** Returns the trigger value. */
+ public int getTriggerValue(TriggerDMContext alarmCtx) {
+ Integer value = fTriggers.get(alarmCtx);
+ if (value != null) {
+ return value;
+ } else {
+ return -1;
+ }
+ }
+
+ /** Returns the alarm context for given timer and trigger contexts. */
+ public AlarmDMContext getAlarm(TriggerDMContext alarmCtx, TimerDMContext timerCtx) {
+ return new AlarmDMContext(getSession().getId(), timerCtx, alarmCtx);
+ }
+
+ /** Returns true if the given alarm is triggered */
+ public boolean isAlarmTriggered(AlarmDMContext alarmCtx) {
+ // Extract the timer and trigger contexts. They should always be part
+ // of the alarm.
+ TimerService.TimerDMContext timerCtx = DMContexts.getAncestorOfType(
+ alarmCtx, TimerService.TimerDMContext.class);
+ TriggerDMContext triggerCtx = DMContexts.getAncestorOfType(
+ alarmCtx, TriggerDMContext.class);
+
+ assert triggerCtx != null && timerCtx != null;
+
+ // Find the trigger and check whether the timers value has surpassed it.
+ if (fTriggers.containsKey(triggerCtx)) {
+ int timerValue = getServicesTracker().getService(TimerService.class).
+ getTimerValue(timerCtx);
+
+ return timerValue >= fTriggers.get(triggerCtx);
+ }
+
+ return false;
+ }
+
+ /** Creates a new alarm object with given value. */
+ public TriggerDMContext createTrigger(int value) {
+ TriggerDMContext triggerCtx =
+ new TriggerDMContext(getSession().getId(), fTriggerNumberCounter++);
+ fTriggers.put(triggerCtx, value);
+ getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
+ return triggerCtx;
+ }
+
+ /** Removes given alarm from service. */
+ public void deleteTrigger(TriggerDMContext alarmCtx) {
+ fTriggers.remove(alarmCtx);
+ getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
+ }
+
+ /** Changes the value of the given trigger. */
+ public void setTriggerValue(TriggerDMContext ctx, int newValue) {
+ if (fTriggers.containsKey(ctx)) {
+ fTriggers.put(ctx, newValue);
+ }
+ getSession().dispatchEvent(new TriggersChangedEvent(), getProperties());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java
new file mode 100644
index 00000000000..be7b22f3b07
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/AlarmsVMNode.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.AlarmDMContext;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ * View model node that determines whether an "alarm triggered" indicator is
+ * shown in the tree. This indicator is only shown if a given alarm is
+ * triggered for a given timer.
+ *
+ * @see AlarmDMContext
+ */
+@SuppressWarnings("restriction")
+class AlarmsVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider
+{
+ public AlarmsVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, AlarmDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "AlarmsVMNode(" + getSession().getId() + ")";
+ }
+
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ // Check that the service is available and find the trigger and timer contexts.
+ // If not found, fail.
+ AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
+ TriggerDMContext alarmDmc = findDmcInPath(
+ update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
+ TimerDMContext timerDmc = findDmcInPath(
+ update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
+ if (alarmService == null || alarmDmc == null || timerDmc == null) {
+ update.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Required elements not found in path"));
+ update.done();
+ return;
+ }
+
+ // Get the alarm context then check the triggered value.
+ final AlarmDMContext alarmStatusDmc = alarmService.getAlarm(alarmDmc, timerDmc);
+ boolean triggered = alarmService.isAlarmTriggered(alarmStatusDmc);
+
+ // Only return the alarm in list of elements if it is triggered.
+ if (triggered) {
+ update.setChild(createVMContext(alarmStatusDmc), 0);
+ }
+ update.done();
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ for (ILabelUpdate update : updates) {
+ update.setLabel("ALARM TRIGGERED", 0);
+ update.setImageDescriptor(
+ DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
+ DsfExamplesPlugin.IMG_ALARM_TRIGGERED),
+ 0);
+ update.done();
+ }
+ }
+
+
+ public int getDeltaFlags(Object e) {
+ if (e instanceof AlarmService.AlarmTriggeredDMEvent) {
+ return IModelDelta.ADDED | IModelDelta.SELECT | IModelDelta.EXPAND;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
+ // The alarm element is added when and selected upon a triggered event.
+ // Parent element is also expanded allow the alarm to be selected.
+ if (e instanceof AlarmService.AlarmTriggeredDMEvent) {
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.EXPAND);
+ parentDelta.addNode(
+ createVMContext( ((AlarmService.AlarmTriggeredDMEvent)e).getDMContext() ),
+ 0,
+ IModelDelta.ADDED | IModelDelta.SELECT);
+ }
+ requestMonitor.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java
new file mode 100644
index 00000000000..cb8276c9a13
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesShutdownSequence.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Sequence that stops the services in the timers session.
+ */
+public class ServicesShutdownSequence extends Sequence {
+
+ // Session to that the services are running in.
+ final private DsfSession fSession;
+
+ // DSF Services is created as the first step of the sequence. It
+ // cannot be created by the constructor because it can only be called
+ // in the session thread.
+ DsfServicesTracker fTracker;
+
+ public ServicesShutdownSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fTracker = new DsfServicesTracker(DsfExamplesPlugin.getBundleContext(), fSession.getId());
+ requestMonitor.done();
+ }
+
+ @Override
+ public void rollBack(RequestMonitor requestMonitor) {
+ // Dispose the tracker in case shutdown sequence is aborted
+ // and is rolled back.
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(AlarmService.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ shutdownService(TimerService.class, requestMonitor);
+ }
+ },
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Dispose the tracker after the services are shut down.
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ // A convenience method that shuts down given service. Only service class
+ // is used to identify the service.
+ private <V extends IDsfService> void shutdownService(Class<V> clazz, RequestMonitor requestMonitor) {
+ IDsfService service = fTracker.getService(clazz);
+ if (service != null) {
+ service.shutdown(requestMonitor);
+ }
+ else {
+ requestMonitor.setStatus(new Status(
+ IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID,
+ IDsfStatusConstants.INTERNAL_ERROR,
+ "Service '" + clazz.getName() + "' not found.", null));
+ requestMonitor.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java
new file mode 100644
index 00000000000..c137bc36369
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/ServicesStartupSequence.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * Startup sequence for the timers session. With only two services, this is
+ * a very simple sequence.
+ */
+public class ServicesStartupSequence extends Sequence {
+
+ final private DsfSession fSession;
+
+ // The reference to the services are saved to use in the last step.
+ private TimerService fTimerService = null;
+ private AlarmService fAlarmService = null;
+
+
+ public ServicesStartupSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ Step[] fSteps = new Step[] {
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fTimerService = new TimerService(fSession);
+ fTimerService.initialize(requestMonitor);
+ }},
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fAlarmService = new AlarmService(fSession);
+ fAlarmService.initialize(requestMonitor);
+ }},
+ new Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ // Create the first timer and trigger.
+ fTimerService.startTimer();
+ fAlarmService.createTrigger(5);
+ requestMonitor.done();
+ }}
+ };
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java
new file mode 100644
index 00000000000..6b05f0a1c5e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimerService.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Timer service tracks a set of timers, which are created per user request.
+ * The timers are represented using a Data Model context object, which
+ * implements {@link IDMContext}. Each timers value, which can be retrieved
+ * by calling {@link #getTimerValue(TimerDMContext)}, is incremented every
+ * second. When a timer value is incremented the TimerService issues a
+ * {@link TimerTickDMEvent}.
+ */
+public class TimerService extends AbstractDsfService
+{
+ /** Event indicating that the list of timers is changed. */
+ @Immutable
+ public static class TimersChangedEvent {}
+
+ /** Data Model context representing a timer. */
+ @Immutable
+ public static class TimerDMContext extends AbstractDMContext {
+ final int fNumber;
+
+ public TimerDMContext(String sessionId, int timer) {
+ super(sessionId, new IDMContext[0]);
+ fNumber = timer;
+ }
+
+ /** Returns the sequential creation number of this timer. */
+ public int getTimerNumber() {
+ return fNumber;
+ }
+
+ // Timer context objects are created as needed and not cached, so the
+ // equals method implementation is critical.
+ @Override
+ public boolean equals(Object other) {
+ return baseEquals(other) &&
+ ((TimerDMContext)other).fNumber == fNumber;
+ }
+
+ @Override
+ public int hashCode() { return baseHashCode() + fNumber; }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".timer[" + fNumber + "]";
+ }
+ }
+
+ /**
+ * Event indicating that a timer's value has incremented. The context in
+ * the event points to the timer that has changed.
+ */
+ public class TimerTickDMEvent extends AbstractDMEvent<TimerDMContext> {
+ public TimerTickDMEvent(TimerDMContext context) {
+ super(context);
+ }
+ }
+
+ /** Counter for generating timer numbers */
+ private int fTimerNumberCounter = 1;
+
+ // Use a linked hash in order to be able to return an ordered list of timers.
+ private Map<TimerDMContext, Integer> fTimers =
+ new LinkedHashMap<TimerDMContext, Integer>();
+
+ private Map<TimerDMContext, Future<?>> fTimerFutures =
+ new HashMap<TimerDMContext, Future<?>>();
+
+
+ TimerService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfExamplesPlugin.getDefault().getBundle().getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ // After super-class is finished initializing
+ // perform TimerService initialization.
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ // Register service
+ register( new String[]{ TimerService.class.getName() },
+ new Hashtable<String,String>() );
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor) {
+ // Cancel timer futures to avoid firing more events.
+ for (Future<?> future : fTimerFutures.values()) {
+ future.cancel(false);
+ }
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+
+ /** Retrieves the list of timer contexts. */
+ public TimerDMContext[] getTimers() {
+ return fTimers.keySet().toArray(new TimerDMContext[fTimers.size()]);
+ }
+
+ /** Retrieves the timer value for the given context. */
+ public int getTimerValue(TimerDMContext context) {
+ Integer value = fTimers.get(context);
+ if (value != null) {
+ return value;
+ }
+ return -1;
+ }
+
+ /** Creates a new timer and returns its context. */
+ public TimerDMContext startTimer() {
+ // Create a new timer context and add it to the internal list.
+ final TimerDMContext newTimer =
+ new TimerDMContext(getSession().getId(), fTimerNumberCounter++);
+ fTimers.put(newTimer, 0);
+
+ // Create a new runnable that will execute every second and increment
+ // the timer value. The returned future is the handle that allows
+ // for canceling the scheduling of the runnable.
+ Future<?> timerFuture = getExecutor().scheduleAtFixedRate(
+ new Runnable() {
+ public void run() {
+ fTimers.put(newTimer, fTimers.get(newTimer) + 1);
+ getSession().dispatchEvent(new TimerTickDMEvent(newTimer), getProperties());
+ }
+ @Override
+ public String toString() { return "Scheduled timer runnable for timer " + newTimer; } //$NON-NLS-1$
+ },
+ 1, 1, TimeUnit.SECONDS);
+ fTimerFutures.put(newTimer, timerFuture);
+
+ // Issue an event to allow clients to update the list of timers.
+ getSession().dispatchEvent(new TimersChangedEvent(), getProperties());
+ return newTimer;
+ }
+
+ /** Removes given timer from list of timers. */
+ public void killTimer(TimerDMContext timerContext) {
+ if (fTimers.containsKey(timerContext)) {
+ fTimers.remove(timerContext);
+ fTimerFutures.remove(timerContext).cancel(false);
+ }
+ getSession().dispatchEvent(new TimersChangedEvent(), getProperties());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java
new file mode 100644
index 00000000000..c804f6d2476
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersRootVMNode.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.RootDMVMNode;
+import org.eclipse.cdt.examples.dsf.timers.TimersVMProvider.TimersViewLayoutChanged;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class TimersRootVMNode extends RootDMVMNode {
+
+ public TimersRootVMNode(AbstractVMProvider provider) {
+ super(provider);
+ }
+
+ @Override
+ public boolean isDeltaEvent(Object rootObject, Object e) {
+ if (e instanceof TimersViewLayoutChanged) {
+ return true;
+ }
+ return super.isDeltaEvent(rootObject, e);
+ }
+
+ @Override
+ public int getDeltaFlags(Object e) {
+ if (e instanceof TimersViewLayoutChanged) {
+ return IModelDelta.CONTENT;
+ }
+
+ return IModelDelta.NO_CHANGE;
+ }
+
+ @Override
+ public void createRootDelta(Object rootObject, Object event, final DataRequestMonitor<VMDelta> rm) {
+ rm.setData(new VMDelta(rootObject, 0, IModelDelta.NO_CHANGE));
+ int flags = IModelDelta.NO_CHANGE;
+ if (event instanceof TimersViewLayoutChanged) {
+ flags |= IModelDelta.CONTENT;
+ }
+ rm.setData( new VMDelta(rootObject, 0, flags) );
+ rm.done();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java
new file mode 100644
index 00000000000..5fae6c32c75
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMAdapter.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMAdapter;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ * This is the adapter that implements the flexible hierarchy viewer interfaces
+ * for providing content, labels, and event processing for the viewer. This
+ * adapter is registered with the DSF Session object, and is returned by the
+ * IDMContext.getAdapter() and IVMContext.getAdapter() methods,
+ * which both call {@link DsfSession#getModelAdapter(Class)}.
+ */
+@SuppressWarnings("restriction")
+@ThreadSafe
+public class TimersVMAdapter extends AbstractDMVMAdapter
+{
+ @Override
+ protected IVMProvider createViewModelProvider(IPresentationContext context) {
+ if ( TimersView.ID_VIEW_TIMERS.equals(context.getId()) ) {
+ return new TimersVMProvider(this, context, getSession());
+ }
+ return null;
+ }
+
+ public TimersVMAdapter(DsfSession session, IPresentationContext presentationContext) {
+ super(session);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java
new file mode 100644
index 00000000000..bba6d1f1ed3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMNode.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.text.MessageFormat;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelAttribute;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelColumnInfo;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+
+
+/**
+ * View model node that defines how timer DMContexts are displayed in the view. Timers
+ * change with every tick of the timer, so the label has to be repained
+ * upon timer tick events.
+ * @see TimerDMContext
+ */
+@SuppressWarnings("restriction")
+class TimersVMNode extends AbstractDMVMNode
+ implements IElementLabelProvider, IElementPropertiesProvider
+{
+ private static final String PROP_TIMER_NUMBER = "alarmNumber";
+ private static final String PROP_TIMER_VALUE = "alarmTriggerValue";
+
+ // Create and configure the label provider.
+ private static final PropertyBasedLabelProvider fgLabelProvider;
+ static {
+ fgLabelProvider = new PropertyBasedLabelProvider();
+
+ LabelColumnInfo idCol = new LabelColumnInfo(
+ new LabelAttribute[] {
+ new LabelText(new MessageFormat("Timer #{0}"),
+ new String[] { PROP_TIMER_NUMBER }),
+ new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().
+ getDescriptor(DsfExamplesPlugin.IMG_ALARM))
+ });
+ fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
+
+ LabelColumnInfo valueCol = new LabelColumnInfo(
+ new LabelAttribute[] {
+ new LabelText(new MessageFormat("{0}"),
+ new String[] { PROP_TIMER_VALUE })
+ });
+ fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE,
+ valueCol);
+
+ }
+
+
+ public TimersVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, TimerDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "TimersVMNode(" + getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ fgLabelProvider.update(updates);
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ TimerService timerService = getServicesTracker().getService(TimerService.class, null);
+ if ( timerService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // Retrieve the timer DMContexts, create the corresponding VMCs array, and
+ // set them as result.
+ TimerDMContext[] timers = timerService.getTimers();
+ fillUpdateWithVMCs(update, timers);
+ update.done();
+ }
+
+
+ public void update(final IPropertiesUpdate[] updates) {
+ // Switch to the session thread before processing the updates.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ for (IPropertiesUpdate update : updates) {
+ updatePropertiesInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession#getExecutor")
+ private void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
+ // Find the timer context in the element being updated
+ TimerDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), TimerDMContext.class);
+ TimerService timerService = getServicesTracker().getService(TimerService.class, null);
+
+ // If either update or service are not valid, fail the update and exit.
+ if ( dmc == null || timerService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ int value = timerService.getTimerValue(dmc);
+
+ if (value == -1) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ update.setProperty(PROP_TIMER_NUMBER, dmc.getTimerNumber());
+ update.setProperty(PROP_TIMER_VALUE, value);
+ update.done();
+ }
+
+ public int getDeltaFlags(Object e) {
+ // This node generates delta if the timers have changed, or if the
+ // label has changed.
+ if (e instanceof TimerService.TimerTickDMEvent) {
+ return IModelDelta.STATE;
+ } else if (e instanceof TimerService.TimersChangedEvent) {
+ return IModelDelta.CONTENT;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor requestMonitor) {
+ if (e instanceof TimerService.TimerTickDMEvent) {
+ // Add delta indicating that the given timer has changed.
+ parentDelta.addNode( createVMContext(((TimerService.TimerTickDMEvent)e).getDMContext()), IModelDelta.STATE );
+ } else if (e instanceof TimerService.TimersChangedEvent) {
+ // The list of timers has changed, which means that the parent
+ // node needs to refresh its contents, which in turn will re-fetch the
+ // elements from this node.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+ requestMonitor.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java
new file mode 100644
index 00000000000..e44c122d7db
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersVMProvider.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.cdt.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggersChangedEvent;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimersChangedEvent;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+/**
+ * The View Model provider for the Timers view. This provider allows for
+ * switching between two different view layouts:
+ * <ol>
+ * <li>Timers -> Triggers -> Alarms</li>
+ * <li>Triggers -> Timers -> Alarms</li>
+ * </ol>
+ * A special event is sent when the layout is changed in order to generate
+ * a proper delta to refresh the view.
+ */
+@SuppressWarnings("restriction")
+public class TimersVMProvider extends AbstractDMVMProvider {
+
+ /** Event indicating that the timers view layout has changed */
+ public static class TimersViewLayoutChanged {}
+
+ /** Enumeration of possible layouts for the timers view model */
+ public enum ViewLayout { TRIGGERS_AT_TOP, TIMERS_AT_TOP }
+
+ public TimersVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session) {
+ super(adapter, presentationContext, session);
+ // Set the initial view layout.
+ setViewLayout(ViewLayout.TIMERS_AT_TOP);
+ }
+
+ /**
+ * Configures a new layout for the timers view model.
+ * @param layout New layout to use.
+ */
+ public void setViewLayout(ViewLayout layout) {
+ clearNodes();
+ if (layout == ViewLayout.TRIGGERS_AT_TOP) {
+ IRootVMNode root = new TimersRootVMNode(this);
+ IVMNode triggersNode = new TriggersVMNode(this, getSession());
+ addChildNodes(root, new IVMNode[] { triggersNode });
+ IVMNode timersNode = new TimersVMNode(this, getSession());
+ addChildNodes(triggersNode, new IVMNode[] { timersNode });
+ IVMNode alarmNode = new AlarmsVMNode(this, getSession());
+ addChildNodes(timersNode, new IVMNode[] { alarmNode });
+ setRootNode(root);
+ } else if (layout == ViewLayout.TIMERS_AT_TOP) {
+ IRootVMNode root = new TimersRootVMNode(this);
+ IVMNode timersNode = new TimersVMNode(this, getSession());
+ addChildNodes(root, new IVMNode[] { timersNode });
+ IVMNode triggersNode = new TriggersVMNode(this, getSession());
+ addChildNodes(timersNode, new IVMNode[] { triggersNode });
+ IVMNode alarmNode = new AlarmsVMNode(this, getSession());
+ addChildNodes(triggersNode, new IVMNode[] { alarmNode });
+ setRootNode(root);
+ }
+
+ handleEvent(new TimersViewLayoutChanged());
+ }
+
+ @Override
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ return new TimersViewColumnPresentation();
+ }
+
+ @Override
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ return TimersViewColumnPresentation.ID;
+ }
+
+ // Add a handler for the triggers and timers changed events. The
+ // AbstractDMVMProvider superclass automatically registers this provider
+ // for all IDMEvent events, however these two events do not implement
+ // IDMEvent
+ @DsfServiceEventHandler
+ public void eventDispatched(final TriggersChangedEvent event) {
+ if (isDisposed()) return;
+
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ handleEvent(event);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final TimersChangedEvent event) {
+ if (isDisposed()) return;
+
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+ handleEvent(event);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java
new file mode 100644
index 00000000000..d9c4a59dac8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersView.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.TimerService.TimerDMContext;
+import org.eclipse.cdt.examples.dsf.timers.TimersVMProvider.ViewLayout;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.PresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.IInputValidator;
+import org.eclipse.jface.dialogs.InputDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.part.ViewPart;
+
+
+/**
+ * Example view which displays data from timers and alarms services. It starts
+ * a new DSF session and configures the services for it. Then it configures
+ * a data model provider to process the service data and display it in a
+ * flexible-hierarchy asynchronous viewer.
+ */
+@SuppressWarnings("restriction")
+public class TimersView extends ViewPart {
+
+ /** Timers view ID */
+ public static final String ID_VIEW_TIMERS = "org.eclipse.cdt.examples.dsf.TimersView";
+
+ /** Asynchronous tree viewer from the platform debug.ui plugin. */
+ private TreeModelViewer fViewer;
+
+ /** Presentation context of the timers viewer */
+ private PresentationContext fPresentationContext;
+
+ /** DSF executor to use for a new session with timers and alarms services */
+ private DsfExecutor fExecutor;
+
+ /** DSF session */
+ private DsfSession fSession;
+
+ /** DSF services tracker used by actions in the viewer. */
+ private DsfServicesTracker fServices;
+
+ /** Adapter used to provide view model for flexible-hierarchy viewer */
+ private TimersVMAdapter fTimersVMAdapter;
+
+ /** Action which toggles the layout in the viewer */
+ private Action fToggleLayoutAction;
+
+ /** Action that adds a new timer */
+ private Action fAddTimerAction;
+
+ /** Action that adds a new trigger */
+ private Action fAddTriggerAction;
+
+ /** Action that removes the selected trigger or timer */
+ private Action fRemoveAction;
+
+ public TimersView() {}
+
+ /**
+ * This is a call-back that will allow us to create the viewer and
+ * initialize it. For this view, it creates the DSF session, along
+ * with its services. Then it creates the viewer model adapter and
+ * registers it with the session.
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ // Create the Flexible Hierarchy viewer. Also create a presentation
+ // context which will be given to the content/label provider adapters
+ // to distinguish this view from other flexible-hierarchy views.
+ fPresentationContext = new PresentationContext(ID_VIEW_TIMERS);
+ fViewer = new TreeModelViewer(
+ parent, SWT.VIRTUAL | SWT.FULL_SELECTION, fPresentationContext);
+
+ // Create the executor, which will be used exclusively with this view,
+ // as well as a session and a services tracker for managing references
+ // to services.
+ fExecutor = new DefaultDsfExecutor();
+ fSession = DsfSession.startSession(fExecutor, "Timers(DSF Example)");
+ fServices = new DsfServicesTracker(
+ DsfExamplesPlugin.getBundleContext(), fSession.getId());
+
+ // Start the services using a sequence. The sequence runs in the
+ // session executor thread, therefore the thread calling this method
+ // has to block using Future.get() until the sequence it completes.
+ // The Future.get() will throw an exception if the sequence fails.
+ ServicesStartupSequence startupSeq = new ServicesStartupSequence(fSession);
+ fSession.getExecutor().execute(startupSeq);
+ try {
+ startupSeq.get();
+ } catch (InterruptedException e) { assert false;
+ } catch (ExecutionException e) { assert false;
+ }
+
+ // Create the flexible hierarchy content/label adapter. Then register
+ // it with the session.
+ fTimersVMAdapter = new TimersVMAdapter(fSession, fPresentationContext);
+ fSession.registerModelAdapter(IElementContentProvider.class, fTimersVMAdapter);
+ fSession.registerModelAdapter(IModelProxyFactory.class, fTimersVMAdapter);
+ fSession.registerModelAdapter(IColumnPresentationFactory.class, fTimersVMAdapter);
+
+ // Create the input object for the view. This object needs to return
+ // the VM adapter through the IAdaptable interface when queried for the
+ // flexible hierarchy adapters.
+ final IAdaptable viewerInputObject =
+ new IAdaptable() {
+ /**
+ * The input object provides the viewer access to the viewer model adapter.
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if ( adapter.isInstance(fTimersVMAdapter) ) {
+ return fTimersVMAdapter;
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "Timers View Root"; //$NON-NLS-1$
+ }
+ };
+ fViewer.setInput(viewerInputObject);
+
+ makeActions();
+ contributeToActionBars();
+ }
+
+ @Override
+ public void dispose() {
+ try {
+ // First dispose the view model, which is the client of services.
+ // This operation needs to be performed in the session executor
+ // thread. Block using Future.get() until this call completes.
+ fSession.getExecutor().submit(new Runnable() {
+ public void run() {
+ fSession.unregisterModelAdapter(IElementContentProvider.class);
+ fSession.unregisterModelAdapter(IModelProxyFactory.class);
+ fSession.unregisterModelAdapter(IColumnPresentationFactory.class);
+ }}).get();
+
+ // Dispose the VM adapter.
+ fTimersVMAdapter.dispose();
+ fTimersVMAdapter = null;
+
+ // Next invoke the shutdown sequence for the services. Sequence
+ // class also implements Future.get()...
+ ServicesShutdownSequence shutdownSeq =
+ new ServicesShutdownSequence(fSession);
+ fSession.getExecutor().execute(shutdownSeq);
+ try {
+ shutdownSeq.get();
+ } catch (InterruptedException e) { assert false;
+ } catch (ExecutionException e) { assert false;
+ }
+
+ // Finally end the session and the executor.
+ fSession.getExecutor().submit(new Runnable() {
+ public void run() {
+ DsfSession.endSession(fSession);
+ fSession = null;
+ fExecutor.shutdown();
+ fExecutor = null;
+ }}).get();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ super.dispose();
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ fillLocalToolBar(bars.getToolBarManager());
+ }
+
+ private void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(fToggleLayoutAction);
+ manager.add(fAddTimerAction);
+ manager.add(fAddTriggerAction);
+ manager.add(fRemoveAction);
+ manager.add(new Separator());
+ }
+
+ private void makeActions() {
+ fToggleLayoutAction = new Action("Toggle Layout", IAction.AS_CHECK_BOX) { //$NON-NLS-1$
+ @Override
+ public void run() {
+ // Get the toggle state of the action while on UI thread.
+ final ViewLayout layout = isChecked() ? ViewLayout.TRIGGERS_AT_TOP : ViewLayout.TIMERS_AT_TOP;
+
+ IVMProvider provider = fTimersVMAdapter.getVMProvider(fPresentationContext);
+ ((TimersVMProvider)provider).setViewLayout(layout);
+ }
+ };
+ fToggleLayoutAction.setToolTipText("Toggle Layout"); //$NON-NLS-1$
+ fToggleLayoutAction.setImageDescriptor(DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(
+ DsfExamplesPlugin.IMG_LAYOUT_TOGGLE));
+
+ fAddTimerAction = new Action("Add New Timer") {
+ @Override
+ public void run() {
+ fExecutor.execute(new Runnable() {
+ public void run() {
+ // Only need to create the new timer, the events will
+ // cause the view to refresh.
+ fServices.getService(TimerService.class).startTimer();
+ }
+ });
+ }
+ };
+ fAddTimerAction.setToolTipText("Add a new timer");
+ fAddTimerAction.setImageDescriptor(
+ getImage(DsfExamplesPlugin.IMG_TIMER));
+
+ fAddTriggerAction = new Action("Add New Trigger") {
+ @Override
+ public void run() {
+ // Ask user for the new trigger value.
+ InputDialog inputDialog = new InputDialog(
+ getSite().getShell(),
+ "New Trigger",
+ "Please enter trigger value",
+ "",
+ new IInputValidator() {
+ public String isValid(String input) {
+ try {
+ int i= Integer.parseInt(input);
+ if (i <= 0)
+ return "Please enter a positive integer";
+
+ } catch (NumberFormatException x) {
+ return "Please enter a positive integer";
+ }
+ return null;
+ }
+ }
+ );
+ if (inputDialog.open() != Window.OK) return;
+ int tmpTriggerValue = -1;
+ try {
+ tmpTriggerValue = Integer.parseInt(inputDialog.getValue());
+ } catch (NumberFormatException x) { assert false; }
+ final int triggerValue = tmpTriggerValue;
+ fExecutor.execute(new Runnable() {
+ public void run() {
+ // Create the new trigger
+ fServices.getService(AlarmService.class).
+ createTrigger(triggerValue);
+ }
+ });
+ }
+ };
+ fAddTriggerAction.setToolTipText("Add a new trigger");
+ fAddTriggerAction.setImageDescriptor(
+ getImage(DsfExamplesPlugin.IMG_ALARM));
+
+ fRemoveAction = new Action("Remove") {
+ @Override
+ public void run() {
+ final Object selectedElement =
+ ((IStructuredSelection)fViewer.getSelection()).getFirstElement();
+ if (!(selectedElement instanceof IDMVMContext)) return;
+ final IDMContext selectedCtx =
+ ((IDMVMContext)selectedElement).getDMContext();
+ // Based on the context from the selection, call the
+ // appropriate service to remove the item.
+ if (selectedCtx instanceof TimerDMContext) {
+ fExecutor.execute(new Runnable() { public void run() {
+ fServices.getService(TimerService.class).killTimer(
+ ((TimerDMContext)selectedCtx));
+ }});
+ } else if (selectedCtx instanceof AlarmService.TriggerDMContext) {
+ fExecutor.execute(new Runnable() { public void run() {
+ fServices.getService(AlarmService.class).deleteTrigger(
+ (AlarmService.TriggerDMContext)selectedCtx);
+ }});
+ }
+ }
+ };
+ fRemoveAction.setToolTipText("Remove selected item");
+ fRemoveAction.setImageDescriptor( getImage(DsfExamplesPlugin.IMG_REMOVE) );
+ }
+
+ private ImageDescriptor getImage(String key) {
+ return DsfExamplesPlugin.getDefault().getImageRegistry().getDescriptor(key);
+ }
+
+ /**
+ * Passing the focus request to the viewer's control.
+ */
+ @Override
+ public void setFocus() {
+ fViewer.getControl().setFocus();
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java
new file mode 100644
index 00000000000..a43778a525a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TimersViewColumnPresentation.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+/**
+ *
+ */
+@SuppressWarnings("restriction")
+public class TimersViewColumnPresentation implements IColumnPresentation {
+
+ public static final String ID = DsfExamplesPlugin.PLUGIN_ID + ".TIMER_COLUMN_PRESENTATION_ID"; //$NON-NLS-1$
+ public static final String COL_ID = ID + ".COL_ID"; //$NON-NLS-1$
+ public static final String COL_VALUE = ID + ".COL_VALUE"; //$NON-NLS-1$
+
+ public void init(IPresentationContext context) {}
+
+ public void dispose() {}
+
+ public String[] getAvailableColumns() {
+ return new String[] { COL_ID, COL_VALUE };
+ }
+
+ public String getHeader(String id) {
+ if (COL_ID.equals(id)) {
+ return "ID"; //$NON-NLS-1$
+ } else if (COL_VALUE.equals(id)) {
+ return "Value"; //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ public String getId() {
+ return ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ public String[] getInitialColumns() {
+ return getAvailableColumns();
+ }
+
+ public boolean isOptional() {
+ return true;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java
new file mode 100644
index 00000000000..b7de00a0ca4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggerCellModifier.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.swt.widgets.Shell;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * Cell modifier used to edit the trigger value.
+ */
+@ThreadSafeAndProhibitedFromDsfExecutor("fSession.getExecutor()")
+public class TriggerCellModifier implements ICellModifier {
+
+ private final DsfSession fSession;
+
+ // Need to use the OSGi service tracker (instead of DsfServiceTracker),
+ // because it's being accessed on multiple threads.
+ @ThreadSafe
+ private ServiceTracker fServiceTracker;
+
+ /**
+ * Constructor for the modifier requires a valid session in order to
+ * initialize the service tracker.
+ * @param session DSF session this modifier will use.
+ */
+ public TriggerCellModifier(DsfSession session) {
+ fSession = session;
+ }
+
+ public boolean canModify(Object element, String property) {
+ return TimersViewColumnPresentation.COL_VALUE.equals(property) &&
+ getAlarmDMC(element) != null;
+ }
+
+ public Object getValue(Object element, String property) {
+ if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return "";
+
+ // Get the context and the session. If element is not an trigger
+ // context or if the session is stale then bail out.
+ TriggerDMContext triggerCtx = getAlarmDMC(element);
+ if (triggerCtx == null) return "";
+ DsfSession session = DsfSession.getSession(triggerCtx.getSessionId());
+ if (session == null) return "";
+
+ // Create the query to request the value from service.
+ GetValueQuery query = new GetValueQuery(triggerCtx);
+ try {
+ session.getExecutor().execute(query);
+ } catch (RejectedExecutionException e) {
+ return "";
+ }
+ try {
+ return query.get().toString();
+ } catch (InterruptedException e) {
+ assert false;
+ return "";
+ } catch (ExecutionException e) {
+ return "";
+ }
+ }
+
+
+ public void modify(Object element, String property, Object value) {
+ if (!TimersViewColumnPresentation.COL_VALUE.equals(property)) return;
+
+ TriggerDMContext dmc = getAlarmDMC(element);
+ if (dmc == null) return;
+ DsfSession session = DsfSession.getSession(dmc.getSessionId());
+ if (session == null) return;
+
+ // Shell is used in displaying error dialogs.
+ Shell shell = getShell();
+ if (shell == null) return;
+
+ Integer intValue = null;
+ if (value instanceof String) {
+ try {
+ intValue = new Integer(((String)value).trim());
+ } catch (NumberFormatException e) {
+ MessageDialog.openError(shell, "Invalid Value",
+ "Please enter a positive integer");
+ return;
+ }
+ if (intValue.intValue() <= 0) {
+ MessageDialog.openError(shell, "Invalid Value",
+ "Please enter a positive integer");
+ return;
+ }
+ }
+
+ // Create the query to write the value to the service.
+ SetValueQuery query = new SetValueQuery(dmc, intValue);
+
+ try {
+ session.getExecutor().execute(query);
+ } catch (RejectedExecutionException e) {
+ // View must be shutting down, no need to show error dialog.
+ }
+ try {
+ // Return value is irrelevant, any error would come through with an exception.
+ query.get().toString();
+ } catch (InterruptedException e) {
+ assert false;
+ } catch (ExecutionException e) {
+ // View must be shutting down, no need to show error dialog.
+ }
+ }
+
+ /**
+ * Need to dispose the cell modifier property because of the service
+ * tracker.
+ */
+ @ThreadSafe
+ public synchronized void dispose() {
+ if (fServiceTracker != null) {
+ fServiceTracker.close();
+ }
+ }
+
+ private Shell getShell() {
+ if (DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow() != null) {
+ return DsfExamplesPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell();
+ }
+ return null;
+ }
+
+ private TriggerDMContext getAlarmDMC(Object element) {
+ if (element instanceof IAdaptable) {
+ return (TriggerDMContext)((IAdaptable)element).getAdapter(TriggerDMContext.class);
+ }
+ return null;
+ }
+
+ @ThreadSafe
+ private synchronized AlarmService getService(TriggerDMContext dmc) {
+ // Create and initialize the service tracker if needed.
+ String serviceId = DsfServices.createServiceFilter( AlarmService.class, fSession.getId() );
+ if (fServiceTracker == null) {
+ try {
+ fServiceTracker = new ServiceTracker(
+ DsfExamplesPlugin.getBundleContext(),
+ DsfExamplesPlugin.getBundleContext().createFilter(serviceId),
+ null);
+ fServiceTracker.open();
+ } catch (InvalidSyntaxException e) {
+ return null;
+ }
+ }
+ // Get the service.
+ return (AlarmService)fServiceTracker.getService();
+ }
+
+
+ private class GetValueQuery extends Query<Integer> {
+ final TriggerDMContext fDmc;
+
+ private GetValueQuery(TriggerDMContext dmc) {
+ super();
+ fDmc = dmc;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Integer> rm) {
+ // Guard against the session being disposed. If session is disposed
+ // it could mean that the executor is shut-down, which in turn
+ // could mean that we can't execute the "done" argument.
+ // In that case, cancel to notify waiting thread.
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ return;
+ }
+
+ AlarmService service = getService(fDmc);
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service not available", null));
+ rm.done();
+ return;
+ }
+
+ int value = service.getTriggerValue(fDmc);
+ if (value == -1) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE,
+ "Invalid context", null));
+ rm.done();
+ return;
+ }
+
+ rm.setData(value);
+ rm.done();
+ }
+ }
+
+ private class SetValueQuery extends Query<Object> {
+
+ TriggerDMContext fDmc;
+ int fValue;
+
+ SetValueQuery(TriggerDMContext dmc, int value) {
+ super();
+ fDmc = dmc;
+ fValue = value;
+ }
+
+ @Override
+ protected void execute(final DataRequestMonitor<Object> rm) {
+ // Guard against terminated session
+ final DsfSession session = DsfSession.getSession(fDmc.getSessionId());
+ if (session == null) {
+ cancel(false);
+ return;
+ }
+
+ // Guard against a disposed service
+ AlarmService service = getService(fDmc);
+ if (service == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE,
+ "Service not available", null));
+ rm.done();
+ return;
+ }
+
+ // Finally set the value and return.
+ service.setTriggerValue(fDmc, fValue);
+
+ // Return value is irrelevant.
+ rm.setData(new Object());
+ rm.done();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java
new file mode 100644
index 00000000000..4b6cef7d88a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/TriggersVMNode.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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.cdt.examples.dsf.timers;
+
+import java.text.MessageFormat;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
+import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IElementPropertiesProvider;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelAttribute;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelColumnInfo;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelImage;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.LabelText;
+import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertyBasedLabelProvider;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+import org.eclipse.cdt.examples.dsf.timers.AlarmService.TriggerDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementEditor;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ICellModifier;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.swt.widgets.Composite;
+
+
+/**
+ * View model node that defines how alarm DMContexts are displayed in the view. Alarm
+ * nodes are fairly static, once they are created their label doesn't change.
+ * @see TriggerDMContext
+ */
+@SuppressWarnings("restriction")
+class TriggersVMNode extends AbstractDMVMNode
+ implements IElementEditor, IElementPropertiesProvider, IElementLabelProvider
+{
+ private static final String PROP_TRIGGER_NUMBER = "alarmNumber";
+ private static final String PROP_TRIGGER_VALUE = "alarmTriggerValue";
+
+ // Create and configure the label provider.
+ private static final PropertyBasedLabelProvider fgLabelProvider;
+ static {
+ fgLabelProvider = new PropertyBasedLabelProvider();
+
+ LabelColumnInfo idCol = new LabelColumnInfo(
+ new LabelAttribute[] {
+ new LabelText(new MessageFormat("Trigger #{0}"),
+ new String[] { PROP_TRIGGER_NUMBER }),
+ new LabelImage(DsfExamplesPlugin.getDefault().getImageRegistry().
+ getDescriptor(DsfExamplesPlugin.IMG_ALARM))
+ });
+ fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_ID, idCol);
+
+ LabelColumnInfo valueCol = new LabelColumnInfo(
+ new LabelAttribute[] {
+ new LabelText(new MessageFormat("{0}"),
+ new String[] { PROP_TRIGGER_VALUE })
+ });
+ fgLabelProvider.setColumnInfo(TimersViewColumnPresentation.COL_VALUE,
+ valueCol);
+ }
+
+ private TriggerCellModifier fAlarmCellModifier;
+
+ public TriggersVMNode(AbstractDMVMProvider provider, DsfSession session) {
+ super(provider, session, TriggerDMContext.class);
+ }
+
+ @Override
+ public String toString() {
+ return "TriggersVMNode(" + getSession().getId() + ")";
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
+ if ( alarmService == null ) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ TriggerDMContext[] triggers = alarmService.getTriggers();
+ fillUpdateWithVMCs(update, triggers);
+ update.done();
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ fgLabelProvider.update(updates);
+ }
+
+ public void update(final IPropertiesUpdate[] updates) {
+ // Switch to the session thread before processing the updates.
+ try {
+ getSession().getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ for (IPropertiesUpdate update : updates) {
+ updatePropertiesInSessionThread(update);
+ }
+ }});
+ } catch (RejectedExecutionException e) {
+ for (IViewerUpdate update : updates) {
+ handleFailedUpdate(update);
+ }
+ }
+ }
+
+ @ConfinedToDsfExecutor("getSession#getExecutor")
+ private void updatePropertiesInSessionThread(final IPropertiesUpdate update) {
+ // Find the trigger context in the element being updated
+ TriggerDMContext triggerCtx = findDmcInPath(
+ update.getViewerInput(), update.getElementPath(), TriggerDMContext.class);
+ AlarmService alarmService = getServicesTracker().getService(AlarmService.class, null);
+
+ // If either update or service are not valid, fail the update and return.
+ if ( triggerCtx == null || alarmService == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ // Calculate and set the update properties.
+ int value = alarmService.getTriggerValue(triggerCtx);
+
+ if (value == -1) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ update.setProperty(PROP_TRIGGER_NUMBER, triggerCtx.getTriggerNumber());
+ update.setProperty(PROP_TRIGGER_VALUE, value);
+ update.done();
+ }
+
+ public CellEditor getCellEditor(IPresentationContext context, String columnId,
+ Object element, Composite parent)
+ {
+ // Create a cell editor to modify the trigger value.
+ if (TimersViewColumnPresentation.COL_VALUE.equals(columnId)) {
+ return new TextCellEditor(parent);
+ }
+ return null;
+ }
+
+ // Note: this method is synchronized because IElementEditor.getCellModifier can be called
+ // on any thread, even though in practice it should be only called on the UI thread.
+ public ICellModifier getCellModifier(IPresentationContext context,
+ Object element)
+ {
+ // Create the cell modifier if needed.
+ if (fAlarmCellModifier == null) {
+ fAlarmCellModifier = new TriggerCellModifier(getSession());
+ }
+ return fAlarmCellModifier;
+ }
+
+ public int getDeltaFlags(Object e) {
+ // Since the label for triggers doesn't change, this node will generate
+ // delta info only if the list of alarms is changed.
+ if (e instanceof AlarmService.TriggersChangedEvent) {
+ return IModelDelta.CONTENT;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+
+ public void buildDelta(Object event, VMDelta parentDelta, int nodeOffset,
+ RequestMonitor requestMonitor)
+ {
+ if (event instanceof AlarmService.TriggersChangedEvent) {
+ // The list of alarms has changed, which means that the parent
+ // node needs to refresh its contents, which in turn will re-fetch the
+ // elements from this node.
+ parentDelta.setFlags(parentDelta.getFlags() | IModelDelta.CONTENT);
+ }
+ requestMonitor.done();
+ }
+
+ @Override
+ public void dispose() {
+ if (fAlarmCellModifier != null) {
+ fAlarmCellModifier.dispose();
+ }
+ super.dispose();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png
new file mode 100644
index 00000000000..0e7c8683d61
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src/org/eclipse/cdt/examples/dsf/timers/doc-files/package-1.png
Binary files differ
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_ant/org/eclipse/cdt/examples/ant/tasks/PreProcessor.java b/dsf/org.eclipse.cdt.examples.dsf/src_ant/org/eclipse/cdt/examples/ant/tasks/PreProcessor.java
new file mode 100644
index 00000000000..b90cfcefc12
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_ant/org/eclipse/cdt/examples/ant/tasks/PreProcessor.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * 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
+ * Bjorn Freeman-Benson - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.examples.ant.tasks;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Java preprocessor for code examples. Used to export source code for
+ * example plug-ins with parts of code missing/inserted etc., for
+ * various exercises.
+ * <p>
+ * The preprocessor looks for #ifdef statements in java comments, and is
+ * run with a set of symbols. For example:
+ * <pre>
+ * //#ifdef ex1
+ * ... code to insert when 'ex1' symbol is on
+ * //#else
+ * ... code to insert when not 'ex1'
+ * //#endif
+ * </pre>
+ * </p>
+ */
+public class PreProcessor extends Task {
+
+ private Vector fFileSets = new Vector();
+ private File fDestDir = null;
+ private Set fSymbols = new HashSet();
+ private FileUtils fUtils = FileUtils.getFileUtils();
+
+ // possible states
+ private static final int STATE_OUTSIDE_CONDITION = 0;
+ private static final int STATE_TRUE_CONDITION = 1;
+ private static final int STATE_FALSE_CONDITION = 2;
+ private static final int STATE_POST_TRUE_CONDITION = 3;
+
+ // matchers
+ private Matcher IF_DEF_MATCHER = Pattern.compile("#ifdef\\s+\\w+").matcher("");
+ private Matcher ELSE_IF_MATCHER = Pattern.compile("#elseif\\s+\\w+").matcher("");
+ private Matcher ELSE_MATCHER = Pattern.compile("#else$|#else\\W+").matcher("");
+ private Matcher END_MATCHER = Pattern.compile("#endif").matcher("");
+
+
+ /**
+ * Constructs a new preprocessor task
+ */
+ public PreProcessor() {
+ }
+
+ /**
+ * Adds a set of files to process.
+ *
+ * @param set a set of files to process
+ */
+ public void addFileset(FileSet set) {
+ fFileSets.addElement(set);
+ }
+
+ /**
+ * Sets the destination directory for processed files.
+ *
+ * @param destDir destination directory for processed files
+ */
+ public void setDestdir(File destDir) {
+ fDestDir = destDir;
+ }
+
+ /**
+ * Sets the symbols that are "on" for the preprocessing.
+ *
+ * @param symbols symbols that are "on" for the preprocessing
+ */
+ public void setSymbols(String symbols) {
+ String[] strings = symbols.split(",");
+ for (int i = 0; i < strings.length; i++) {
+ String string = strings[i].trim();
+ if (string.length() > 0) {
+ fSymbols.add(string);
+ }
+ }
+ }
+
+ public void execute() throws BuildException {
+ if (fSymbols.size() == 0) {
+ throw new BuildException("No symbols specified for preprocessor");
+ }
+ if (fFileSets.isEmpty()) {
+ throw new BuildException("No filesets specified for processing");
+ }
+ if (!fDestDir.exists()) {
+ throw new BuildException("destdir does not exist: " + fDestDir.getAbsolutePath());
+ }
+ StringBuffer buf = new StringBuffer("Symbols: ");
+ String[] symbols = (String[]) fSymbols.toArray(new String[fSymbols.size()]);
+ for (int i = 0; i < symbols.length; i++) {
+ String symbol = symbols[i];
+ buf.append(symbol);
+ if(i < (symbols.length -1)) {
+ buf.append(", ");
+ }
+ }
+ log(buf.toString());
+
+ Iterator fileSets = fFileSets.iterator();
+ while (fileSets.hasNext()) {
+ FileSet fileSet = (FileSet) fileSets.next();
+ DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject());
+ String[] includedFiles = scanner.getIncludedFiles();
+ File baseDir = fileSet.getDir(getProject());
+ for (int i = 0; i < includedFiles.length; i++) {
+ String fileName = includedFiles[i];
+ processFile(baseDir, fileName, fDestDir);
+ }
+ }
+
+ }
+
+ /**
+ * Process the file
+ * @param baseDir base directory source file is relative to
+ * @param fileName source file name
+ * @param destDir root destination directory
+ */
+ private void processFile(File baseDir, String fileName, File destDir) throws BuildException {
+ File destFile = new File(destDir, fileName);
+ File srcFile = new File(baseDir, fileName);
+ File dir = destFile.getParentFile();
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ String contents = null;
+ if (fileName.endsWith(".java")) {
+ contents = preProcessFile(srcFile, "//#");
+ } else if (fileName.equals("plugin.xml")) {
+ contents = preProcessFile(srcFile, null);
+ }
+ if (contents == null) {
+ // no change, just copy file
+ try {
+ fUtils.copyFile(srcFile, destFile);
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ } else {
+ // write new file
+ FileWriter writer;
+ try {
+ writer = new FileWriter(destFile);
+ writer.write(contents);
+ writer.close();
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+
+ }
+ }
+
+ /**
+ * Preprocesses a file
+ *
+ * @param srcFile the file to process
+ * @param strip chars to stip off lines in a true condition, or <code>null</code>
+ * @return
+ */
+ public String preProcessFile(File srcFile, String strip) {
+ try {
+ FileReader fileReader = new FileReader(srcFile);
+ BufferedReader reader = new BufferedReader(fileReader);
+ StringBuffer buffer = new StringBuffer();
+ String line = reader.readLine();
+ String activeSymbol = null;
+ int state = STATE_OUTSIDE_CONDITION;
+ boolean changed = false;
+ while (line != null) {
+ boolean ifdef = IF_DEF_MATCHER.reset(line).find();
+ boolean elseif = ELSE_IF_MATCHER.reset(line).find();
+ boolean elze = ELSE_MATCHER.reset(line).find();
+ boolean endif = END_MATCHER.reset(line).find();
+ boolean commandLine = ifdef || elseif || elze || endif;
+ boolean written = false;
+ switch (state) {
+ case STATE_OUTSIDE_CONDITION:
+ if (ifdef) {
+ String condition = line.substring(IF_DEF_MATCHER.start(), IF_DEF_MATCHER.end());
+ String[] strings = condition.split("\\s+");
+ activeSymbol = strings[1].trim();
+ if (fSymbols.contains(activeSymbol)) {
+ state = STATE_TRUE_CONDITION;
+ } else {
+ state = STATE_FALSE_CONDITION;
+ }
+ } else if (elseif) {
+ throw new BuildException("#elseif encountered without corresponding #ifdef");
+ } else if (elze) {
+ throw new BuildException("#else encountered without corresponding #ifdef (" + srcFile.getPath() + ")");
+ } else if (endif) {
+ throw new BuildException("#endif encountered without corresponding #ifdef");
+ }
+ break;
+ case STATE_TRUE_CONDITION:
+ if (elze || elseif) {
+ state = STATE_POST_TRUE_CONDITION;
+ break;
+ } else if (endif) {
+ state = STATE_OUTSIDE_CONDITION;
+ break;
+ } else if (ifdef) {
+ throw new BuildException("illegal nested #ifdef");
+ }
+ case STATE_FALSE_CONDITION:
+ if (elseif) {
+ String condition = line.substring(ELSE_IF_MATCHER.start(), ELSE_IF_MATCHER.end());
+ String[] strings = condition.split("\\s+");
+ activeSymbol = strings[1].trim();
+ if (fSymbols.contains(activeSymbol)) {
+ state = STATE_TRUE_CONDITION;
+ } else {
+ state = STATE_FALSE_CONDITION;
+ }
+ } else if (elze) {
+ state = STATE_TRUE_CONDITION;
+ break;
+ } else if (endif) {
+ state = STATE_OUTSIDE_CONDITION;
+ break;
+ } else if (ifdef) {
+ throw new BuildException("illegal nested #ifdef");
+ }
+ case STATE_POST_TRUE_CONDITION:
+ if (endif) {
+ state = STATE_OUTSIDE_CONDITION;
+ break;
+ } else if (ifdef) {
+ throw new BuildException("illegal nested #ifdef");
+ }
+ }
+ if (!commandLine) {
+ if (state == STATE_OUTSIDE_CONDITION || state == STATE_TRUE_CONDITION) {
+ if (state == STATE_TRUE_CONDITION && strip != null) {
+ if (line.startsWith(strip)) {
+ line = line.substring(strip.length());
+ }
+ }
+ buffer.append(line);
+ buffer.append("\n");
+ written = true;
+ }
+ }
+ changed = changed || !written;
+ line = reader.readLine();
+ }
+ if (!changed) {
+ return null;
+ }
+ return buffer.toString();
+ } catch (IOException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ public static void main(String[] args) {
+ PreProcessor processor = new PreProcessor();
+ processor.setSymbols("ex2");
+ String string = processor.preProcessFile(new File("c:\\eclipse3.1\\dev\\example.debug.core\\src\\example\\debug\\core\\launcher\\PDALaunchDelegate.java"), "//#");
+ //String string = processor.preProcessFile(new File("c:\\eclipse3.1\\dev\\example.debug.core\\plugin.xml"), null);
+ System.out.println(string);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java
new file mode 100644
index 00000000000..bbf9bb8b921
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/AsyncDataViewer.java
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.ui.concurrent.DisplayDsfExecutor;
+import org.eclipse.jface.viewers.ILazyContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+
+/**
+ * Data viewer based on a table, which reads data using asynchronous methods.
+ * <p>
+ * This viewer implements the {@link ILazyContentProvider} interface
+ * which is used by the JFace TableViewer class to populate a Table. This
+ * interface contains separate asynchronous methods for requesting the count
+ * and values for individual indexes, which neatly correspond to the methods
+ * in {@link IDataGenerator}. As an added optimization, this viewer
+ * implementation checks for the range of visible items in the view upon each
+ * request, and it cancels old requests which scroll out of view but have not
+ * been completed yet. However, it is up to the data generator implementation
+ * to check the canceled state of the requests and ignore them.
+ * </p>
+ */
+@ConfinedToDsfExecutor("fDisplayExecutor")
+public class AsyncDataViewer
+ implements ILazyContentProvider, IDataGenerator.Listener
+{
+ // Executor to use instead of Display.asyncExec().
+ @ThreadSafe
+ final private DsfExecutor fDisplayExecutor;
+
+ // The viewer and generator that this content provider using.
+ final private TableViewer fViewer;
+ final private IDataGenerator fDataGenerator;
+
+ // Fields used in request cancellation logic.
+ private List<ValueDataRequestMonitor> fItemDataRequestMonitors = new LinkedList<ValueDataRequestMonitor>();
+ private Set<Integer> fIndexesToCancel = new HashSet<Integer>();
+ private int fCancelCallsPending = 0;
+
+ public AsyncDataViewer(TableViewer viewer, IDataGenerator generator) {
+ fViewer = viewer;
+ fDisplayExecutor = DisplayDsfExecutor.getDisplayDsfExecutor(fViewer.getTable().getDisplay());
+ fDataGenerator = generator;
+ fDataGenerator.addListener(this);
+ }
+
+ public void dispose() {
+ fDataGenerator.removeListener(this);
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Set the initial count to the viewer after the input is set.
+ queryItemCount();
+ }
+
+ public void updateElement(final int index) {
+ // Calculate the visible index range.
+ final int topIdx = fViewer.getTable().getTopIndex();
+ final int botIdx = topIdx + getVisibleItemCount(topIdx);
+
+ // Request the item for the given index.
+ queryValue(index);
+
+ // Invoke a cancel task with a delay. The delay allows multiple cancel
+ // calls to be combined together improving performance of the viewer.
+ fCancelCallsPending++;
+ fDisplayExecutor.schedule(
+ new Runnable() { public void run() {
+ cancelStaleRequests(topIdx, botIdx);
+ }},
+ 1, TimeUnit.MILLISECONDS);
+ }
+
+ private int getVisibleItemCount(int top) {
+ Table table = fViewer.getTable();
+ int itemCount = table.getItemCount();
+ return Math.min((table.getBounds().height / table.getItemHeight()) + 2, itemCount - top);
+ }
+
+ @ThreadSafe
+ public void countChanged() {
+ queryItemCount();
+ }
+
+ @ThreadSafe
+ public void valuesChanged(final Set<Integer> indexes) {
+ // Mark the changed items in table viewer as dirty, this will
+ // trigger update requests for these indexes if they are
+ // visible in the viewer.
+ final TableViewer tableViewer = fViewer;
+ fDisplayExecutor.execute( new Runnable() {
+ public void run() {
+ if (!fViewer.getTable().isDisposed()) {
+ for (Integer index : indexes) {
+ tableViewer.clear(index);
+ }
+ }
+ }});
+ }
+
+
+ private void queryItemCount() {
+ // Request count from data provider. When the count is returned, we
+ // have to re-dispatch into the display thread to avoid calling
+ // the table widget on the DSF dispatch thread.
+ fIndexesToCancel.clear();
+ fDataGenerator.getCount(
+ // Use the display executor to construct the request monitor, this
+ // will cause the handleCompleted() method to be automatically
+ // called on the display thread.
+ new DataRequestMonitor<Integer>(fDisplayExecutor, null) {
+ @Override
+ protected void handleCompleted() {
+ if (!fViewer.getTable().isDisposed()) {
+ fViewer.setItemCount(getData());
+ fViewer.getTable().clearAll();
+ }
+ }
+ });
+
+ }
+
+
+ // Dedicated class for data item requests. This class holds the index
+ // argument so it can be examined when canceling stale requests.
+ private class ValueDataRequestMonitor extends DataRequestMonitor<String> {
+
+ /** Index is used when canceling stale requests. */
+ int fIndex;
+
+ ValueDataRequestMonitor(int index) {
+ super(fDisplayExecutor, null);
+ fIndex = index;
+ }
+
+ @Override
+ protected void handleCompleted() {
+ fItemDataRequestMonitors.remove(this);
+
+ // Check if the request completed successfully, otherwise ignore it.
+ if (isSuccess()) {
+ if (!fViewer.getTable().isDisposed()) {
+ fViewer.replace(getData(), fIndex);
+ }
+ }
+ }
+ }
+
+ private void queryValue(final int index) {
+ ValueDataRequestMonitor rm = new ValueDataRequestMonitor(index);
+ fItemDataRequestMonitors.add(rm);
+ fDataGenerator.getValue(index, rm);
+ }
+
+ private void cancelStaleRequests(int topIdx, int botIdx) {
+ // Decrement the count of outstanding cancel calls.
+ fCancelCallsPending--;
+
+ // Must check again, in case disposed while re-dispatching.
+ if (fDataGenerator == null || fViewer.getTable().isDisposed()) return;
+
+ // Go through the outstanding requests and cancel any that
+ // are not visible anymore.
+ for (Iterator<ValueDataRequestMonitor> itr = fItemDataRequestMonitors.iterator(); itr.hasNext();) {
+ ValueDataRequestMonitor item = itr.next();
+ if (item.fIndex < topIdx || item.fIndex > botIdx) {
+ // Set the item to canceled status, so that the data provider
+ // will ignore it.
+ item.cancel();
+
+ // Add the item index to list of indexes that were canceled,
+ // which will be sent to the table widget.
+ fIndexesToCancel.add(item.fIndex);
+
+ // Remove the item from the outstanding cancel requests.
+ itr.remove();
+ }
+ }
+ if (!fIndexesToCancel.isEmpty() && fCancelCallsPending == 0) {
+ Set<Integer> canceledIdxs = fIndexesToCancel;
+ fIndexesToCancel = new HashSet<Integer>();
+
+ // Clear the indexes of the canceled request, so that the
+ // viewer knows to request them again when needed.
+ // Note: clearing using TableViewer.clear(int) seems very
+ // inefficient, it's better to use Table.clear(int[]).
+ int[] canceledIdxsArray = new int[canceledIdxs.size()];
+ int i = 0;
+ for (Integer index : canceledIdxs) {
+ canceledIdxsArray[i++] = index;
+ }
+ fViewer.getTable().clear(canceledIdxsArray);
+ }
+ }
+
+
+ public static void main(String[] args) {
+ // Create the shell to hold the viewer.
+ Display display = new Display();
+ Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setLayout(new GridLayout());
+ GridData data = new GridData(GridData.FILL_BOTH);
+ shell.setLayoutData(data);
+ Font font = new Font(display, "Courier", 10, SWT.NORMAL);
+
+ // Create the table viewer.
+ TableViewer tableViewer = new TableViewer(shell, SWT.BORDER | SWT.VIRTUAL);
+ tableViewer.getControl().setLayoutData(data);
+
+ // Create the data generator.
+ final IDataGenerator generator = new DataGeneratorWithExecutor();
+
+ // Create the content provider which will populate the viewer.
+ AsyncDataViewer contentProvider = new AsyncDataViewer(tableViewer, generator);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setInput(new Object());
+
+ // Open the shell and service the display dispatch loop until user
+ // closes the shell.
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+
+ // The IDataGenerator.shutdown() method is asynchronous, this requires
+ // using a query again in order to wait for its completion.
+ Query<Object> shutdownQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ generator.shutdown(rm);
+ }
+ };
+ ImmediateExecutor.getInstance().execute(shutdownQuery);
+ try {
+ shutdownQuery.get();
+ } catch (Exception e) {}
+
+ // Shut down the display.
+ font.dispose();
+ display.dispose();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java
new file mode 100644
index 00000000000..1643017df75
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithExecutor.java
@@ -0,0 +1,438 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.HashSet;
+//#ifdef answers
+//#import java.util.Iterator;
+//#endif
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+//#ifdef answers
+//#import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+//#import org.eclipse.cdt.dsf.concurrent.Immutable;
+//#import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+//#endif
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+
+/**
+ * DSF Executor-based implementation of the data generator.
+ * <p>
+ * This generator uses a queue of client requests and processes these
+ * requests periodically using a DSF executor. The main feature of this
+ * generator is that it uses the executor as its only synchronization object.
+ * This means that all the fields with the exception of the executor can only
+ * be accessed while running in the executor thread.
+ * </p>
+ */
+//#ifdef exercises
+//TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+//indicating allowed thread access to this class/method/member
+//#else
+//#@ThreadSafe
+//#endif
+public class DataGeneratorWithExecutor implements IDataGenerator {
+
+ // Request objects are used to serialize the interface calls into objects
+ // which can then be pushed into a queue.
+ //#ifdef exercises
+ // TODO Ecercise 4 - Add an annotationindicating allowed concurrency access
+ // Hint: Request and its subclasses have all their fields declared as final.
+ //#else
+//# @Immutable
+ //#endif
+ abstract class Request {
+ final RequestMonitor fRequestMonitor;
+
+ Request(RequestMonitor rm) {
+ fRequestMonitor = rm;
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @Immutable
+ //#endif
+ class CountRequest extends Request {
+ CountRequest(DataRequestMonitor<Integer> rm) {
+ super(rm);
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @Immutable
+ //#endif
+ class ItemRequest extends Request {
+ final int fIndex;
+ ItemRequest(int index, DataRequestMonitor<String> rm) {
+ super(rm);
+ fIndex = index;
+ }
+ }
+
+ // The executor used to access all internal data of the generator.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ // Hint: If a member does not have an annotation, the programmer can assume
+ // that the concurrency rule that applies to the class also applies to this
+ // member.
+ //#endif
+ private DsfExecutor fExecutor;
+
+ // Main request queue of the data generator. The getValue(), getCount(),
+ // and shutdown() methods write into the queue, while the serviceQueue()
+ // method reads from it.
+ // The executor used to access all internal data of the generator.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private List<Request> fQueue = new LinkedList<Request>();
+
+ // List of listeners is not synchronized, it also has to be accessed
+ // using the executor.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private List<Listener> fListeners = new LinkedList<Listener>();
+
+ // Current number of elements in this generator.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private int fCount = MIN_COUNT;
+
+ // Counter used to determine when to reset the element count.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private int fCountResetTrigger = 0;
+
+ // Elements which were modified since the last reset.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private Set<Integer> fChangedIndexes = new HashSet<Integer>();
+
+ // Flag used to ensure that requests are processed sequentially.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private boolean fServiceQueueInProgress = false;
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public DataGeneratorWithExecutor() {
+ // Create the executor
+ fExecutor = new DefaultDsfExecutor("Supplier Executor");
+
+ // Schedule a runnable to make the random changes.
+ fExecutor.scheduleAtFixedRate(
+ new DsfRunnable() {
+ public void run() {
+ randomChanges();
+ }
+ },
+ RANDOM_CHANGE_INTERVAL,
+ RANDOM_CHANGE_INTERVAL,
+ TimeUnit.MILLISECONDS);
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public void shutdown(final RequestMonitor rm) {
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ // Empty the queue of requests and fail them.
+ for (Request request : fQueue) {
+ request.fRequestMonitor.setStatus(
+ new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ request.fRequestMonitor.done();
+ }
+ fQueue.clear();
+
+ // Kill executor.
+ fExecutor.shutdown();
+ rm.done();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public void getCount(final DataRequestMonitor<Integer> rm) {
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fQueue.add(new CountRequest(rm));
+ serviceQueue();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public void getValue(final int index, final DataRequestMonitor<String> rm) {
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fQueue.add(new ItemRequest(index, rm));
+ serviceQueue();
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public void addListener(final Listener listener) {
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fListeners.add(listener);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#endif
+ public void removeListener(final Listener listener) {
+ try {
+ fExecutor.execute( new DsfRunnable() {
+ public void run() {
+ fListeners.remove(listener);
+ }
+ });
+ } catch (RejectedExecutionException e) {}
+ }
+
+ // Main processing function of this generator.
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void serviceQueue() {
+
+ //#ifdef exercises
+ // TODO Exercise 3 - Add logic to discard cancelled requests from queue.
+ // Hint: Since serviceQueue() is called using the executor, and the
+ // fQueue list can only be modified when running in the executor
+ // thread. This method can safely iterate and modify fQueue without
+ // risk of race conditions or concurrent modification exceptions.
+ //#else
+//# for (Iterator<Request> requestItr = fQueue.iterator(); requestItr.hasNext();) {
+//# Request request = requestItr.next();
+//# if (request.fRequestMonitor.isCanceled()) {
+//# request.fRequestMonitor.setStatus(
+//# new Status(IStatus.CANCEL, DsfExamplesPlugin.PLUGIN_ID, "Request canceled"));
+//# request.fRequestMonitor.done();
+//# requestItr.remove();
+//# }
+//# }
+ //#endif
+
+ // If a queue servicing is already scheduled, do nothing.
+ if (fServiceQueueInProgress) {
+ return;
+ }
+
+ if (fQueue.size() != 0) {
+ // If there are requests to service, remove one from the queue and
+ // schedule a runnable to process the request after a processing
+ // delay.
+ fServiceQueueInProgress = true;
+ final Request request = fQueue.remove(0);
+ fExecutor.schedule(
+ new DsfRunnable() {
+ public void run() {
+ if (request instanceof CountRequest) {
+ processCountRequest((CountRequest)request);
+ } else if (request instanceof ItemRequest) {
+ processItemRequest((ItemRequest)request);
+ }
+
+ // Reset the processing flag and process next
+ // request.
+ fServiceQueueInProgress = false;
+ serviceQueue();
+ }
+ },
+ PROCESSING_DELAY, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void processCountRequest(CountRequest request) {
+ @SuppressWarnings("unchecked") // Suppress warning about lost type info.
+ DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
+
+ rm.setData(fCount);
+ rm.done();
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void processItemRequest(ItemRequest request) {
+ @SuppressWarnings("unchecked") // Suppress warning about lost type info.
+ DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
+
+ if (fChangedIndexes.contains(request.fIndex)) {
+ rm.setData("Changed: " + request.fIndex);
+ } else {
+ rm.setData(Integer.toString(request.fIndex));
+ }
+ rm.done();
+ }
+
+ /**
+ * This method simulates changes in the supplier's data set.
+ */
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void randomChanges() {
+ // Once every number of changes, reset the count, the rest of the
+ // times just change certain values.
+ if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
+ randomCountReset();
+ } else {
+ randomDataChange();
+ }
+ }
+
+ /**
+ * Calculates new size for provider's data set.
+ */
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void randomCountReset() {
+ // Calculate the new count.
+ Random random = new java.util.Random();
+ fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
+
+ // Reset the changed values.
+ fChangedIndexes.clear();
+
+ // Notify listeners
+ for (Listener listener : fListeners) {
+ listener.countChanged();
+ }
+ }
+
+ /**
+ * Invalidates a random range of indexes.
+ */
+ //#ifdef exercises
+ // TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+ // indicating allowed thread access to this class/method/member
+ //#else
+//# @ConfinedToDsfExecutor("fExecutor")
+ //#endif
+ private void randomDataChange() {
+ // Calculate the indexes to change.
+ Random random = new java.util.Random();
+ Set<Integer> set = new HashSet<Integer>();
+ for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
+ set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
+ }
+
+ // Add the indexes to an overall set of changed indexes.
+ fChangedIndexes.addAll(set);
+
+ // Notify listeners
+ for (Listener listener : fListeners) {
+ listener.valuesChanged(set);
+ }
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java
new file mode 100644
index 00000000000..f3647f59f5a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/DataGeneratorWithThread.java
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.examples.dsf.DsfExamplesPlugin;
+
+/**
+ * Thread-based implementation of the data generator.
+ * <p>
+ * This generator is based around a queue of client requests and a thread which
+ * reads the requests from the queue and processes them. The distinguishing
+ * feature of this generator is that it uses a a blocking queue as the main
+ * synchronization object. However, fListeners, fShutdown, and fChangedIndexes
+ * fields also need to be thread-safe and so they implement their own
+ * synchronization.
+ * </p>
+ */
+public class DataGeneratorWithThread extends Thread implements IDataGenerator {
+
+ // Request objects are used to serialize the interface calls into objects
+ // which can then be pushed into a queue.
+ abstract class Request {
+ final RequestMonitor fRequestMonitor;
+
+ Request(RequestMonitor rm) {
+ fRequestMonitor = rm;
+ }
+ }
+
+ class CountRequest extends Request {
+ CountRequest(DataRequestMonitor<Integer> rm) {
+ super(rm);
+ }
+ }
+
+ class ItemRequest extends Request {
+ final int fIndex;
+ ItemRequest(int index, DataRequestMonitor<String> rm) {
+ super(rm);
+ fIndex = index;
+ }
+ }
+
+ class ShutdownRequest extends Request {
+ ShutdownRequest(RequestMonitor rm) {
+ super(rm);
+ }
+ }
+
+ // Main request queue of the data generator. The getValue(), getCount(),
+ // and shutdown() methods write into the queue, while the run() method
+ // reads from it.
+ private final BlockingQueue<Request> fQueue = new LinkedBlockingQueue<Request>();
+
+ // ListenerList class provides thread safety.
+ private ListenerList fListeners = new ListenerList();
+
+ // Current number of elements in this generator.
+ private int fCount = MIN_COUNT;
+
+ // Counter used to determine when to reset the element count.
+ private int fCountResetTrigger = 0;
+
+ // Elements which were modified since the last reset.
+ private Set<Integer> fChangedIndexes = Collections.synchronizedSet(new HashSet<Integer>());
+
+ // Used to determine when to make changes in data.
+ private long fLastChangeTime = System.currentTimeMillis();
+
+ // Flag indicating when the generator has been shut down.
+ private AtomicBoolean fShutdown = new AtomicBoolean(false);
+
+ public DataGeneratorWithThread() {
+ // Immediately kick off the request processing thread.
+ start();
+ }
+
+ public void shutdown(RequestMonitor rm) {
+ // Mark the generator as shut down. After the fShutdown flag is set,
+ // all new requests should be shut down.
+ if (!fShutdown.getAndSet(true)) {
+ fQueue.add(new ShutdownRequest(rm));
+ } else {
+ //
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ public void getCount(DataRequestMonitor<Integer> rm) {
+ if (!fShutdown.get()) {
+ fQueue.add(new CountRequest(rm));
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ public void getValue(int index, DataRequestMonitor<String> rm) {
+ if (!fShutdown.get()) {
+ fQueue.add(new ItemRequest(index, rm));
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, DsfExamplesPlugin.PLUGIN_ID, "Supplier shut down"));
+ rm.done();
+ }
+ }
+
+ public void addListener(Listener listener) {
+ fListeners.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ fListeners.remove(listener);
+ }
+
+ @Override
+ public void run() {
+ try {
+ while(true) {
+ // Get the next request from the queue. The time-out
+ // ensures that that the random changes get processed.
+ final Request request = fQueue.poll(100, TimeUnit.MILLISECONDS);
+
+ // If a request was dequeued, process it.
+ if (request != null) {
+ // Simulate a processing delay.
+ Thread.sleep(PROCESSING_DELAY);
+
+ if (request instanceof CountRequest) {
+ processCountRequest((CountRequest)request);
+ } else if (request instanceof ItemRequest) {
+ processItemRequest((ItemRequest)request);
+ } else if (request instanceof ShutdownRequest) {
+ // If shutting down, just break out of the while(true)
+ // loop and thread will exit.
+ request.fRequestMonitor.done();
+ break;
+ }
+ }
+
+ // Simulate data changes.
+ randomChanges();
+ }
+ }
+ catch (InterruptedException x) {}
+ }
+
+ private void processCountRequest(CountRequest request) {
+ @SuppressWarnings("unchecked") // Suppress warning about lost type info.
+ DataRequestMonitor<Integer> rm = (DataRequestMonitor<Integer>)request.fRequestMonitor;
+
+ rm.setData(fCount);
+ rm.done();
+ }
+
+ private void processItemRequest(ItemRequest request) {
+ @SuppressWarnings("unchecked") // Suppress warning about lost type info.
+ DataRequestMonitor<String> rm = (DataRequestMonitor<String>)request.fRequestMonitor;
+
+ if (fChangedIndexes.contains(request.fIndex)) {
+ rm.setData("Changed: " + request.fIndex);
+ } else {
+ rm.setData(Integer.toString(request.fIndex));
+ }
+ rm.done();
+ }
+
+
+ private void randomChanges() {
+ // Check if enough time is elapsed.
+ if (System.currentTimeMillis() > fLastChangeTime + RANDOM_CHANGE_INTERVAL) {
+ fLastChangeTime = System.currentTimeMillis();
+
+ // Once every number of changes, reset the count, the rest of the
+ // times just change certain values.
+ if (++fCountResetTrigger % RANDOM_COUNT_CHANGE_INTERVALS == 0){
+ randomCountReset();
+ } else {
+ randomDataChange();
+ }
+ }
+ }
+
+ private void randomCountReset() {
+ // Calculate the new count.
+ Random random = new java.util.Random();
+ fCount = MIN_COUNT + Math.abs(random.nextInt()) % (MAX_COUNT - MIN_COUNT);
+
+ // Reset the changed values.
+ fChangedIndexes.clear();
+
+ // Notify listeners
+ for (Object listener : fListeners.getListeners()) {
+ ((Listener)listener).countChanged();
+ }
+ }
+
+ private void randomDataChange() {
+ // Calculate the indexes to change.
+ Random random = new java.util.Random();
+ Set<Integer> set = new HashSet<Integer>();
+ for (int i = 0; i < fCount * RANDOM_CHANGE_SET_PERCENTAGE / 100; i++) {
+ set.add( new Integer(Math.abs(random.nextInt()) % fCount) );
+ }
+
+ // Add the indexes to an overall set of changed indexes.
+ fChangedIndexes.addAll(set);
+
+ // Notify listeners
+ for (Object listener : fListeners.getListeners()) {
+ ((Listener)listener).valuesChanged(set);
+ }
+ }
+}
+
+
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java
new file mode 100644
index 00000000000..882b0547211
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/IDataGenerator.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+//#ifdef answers
+//#import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+//#endif
+
+/**
+ * Data generator is simple source of data used to populate the example table
+ * view. It contains two asynchronous methods for retrieving the data
+ * parameters: the count and the value for a given index. It also allows the
+ * view to receive events indicating when the data supplied by the generator
+ * is changed.
+ */
+//#ifdef exercises
+// TODO Exercise 4 - Add an annotation (ThreadSafe/ConfinedToDsfExecutor)
+// indicating allowed thread access to this class/method/member
+//#else
+//#@ThreadSafe
+//#endif
+public interface IDataGenerator {
+
+ // Constants which control the data generator behavior.
+ // Changing the count range can stress the scalability of the system, while
+ // changing of the process delay and random change interval can stress
+ // its performance.
+ final static int MIN_COUNT = 100;
+ final static int MAX_COUNT = 200;
+ final static int PROCESSING_DELAY = 10;
+ final static int RANDOM_CHANGE_INTERVAL = 10000;
+ final static int RANDOM_COUNT_CHANGE_INTERVALS = 3;
+ final static int RANDOM_CHANGE_SET_PERCENTAGE = 10;
+
+
+ // Listener interface that the view needs to implement to react
+ // to the changes in data.
+ public interface Listener {
+ void countChanged();
+ void valuesChanged(Set<Integer> indexes);
+ }
+
+ // Data access methods.
+ void getCount(DataRequestMonitor<Integer> rm);
+ void getValue(int index, DataRequestMonitor<String> rm);
+
+ // Method used to shutdown the data generator including any threads that
+ // it may use.
+ void shutdown(RequestMonitor rm);
+
+ // Methods for registering change listeners.
+ void addListener(Listener listener);
+ void removeListener(Listener listener);
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java
new file mode 100644
index 00000000000..6f4dec363e8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/dataviewer/SyncDataViewer.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.dataviewer;
+//#else
+//#package org.eclipse.cdt.examples.dsf.dataviewer.answers;
+//#endif
+
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Data viewer based on a table, which reads data using synchronous methods.
+ * <p>
+ * This viewer implements the {@link IStructuredContentProvider} interface
+ * which is used by the JFace TableViewer class to populate a Table. This
+ * interface contains one principal methods for reading data {@link #getElements(Object)},
+ * which synchronously returns an array of elements. In order to implement this
+ * method using the asynchronous data generator, this provider uses the
+ * {@link Query} object.
+ * </p>
+ */
+public class SyncDataViewer
+ implements IStructuredContentProvider, IDataGenerator.Listener
+{
+ // The viewer and generator that this content provider using.
+ final private TableViewer fViewer;
+ final private IDataGenerator fDataGenerator;
+
+ public SyncDataViewer(TableViewer viewer, IDataGenerator generator) {
+ fViewer = viewer;
+ fDataGenerator = generator;
+ fDataGenerator.addListener(this);
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // Not used
+ }
+
+
+ public Object[] getElements(Object inputElement) {
+
+ // Create the query object for reading data count.
+ Query<Integer> countQuery = new Query<Integer>() {
+ @Override
+ protected void execute(DataRequestMonitor<Integer> rm) {
+ fDataGenerator.getCount(rm);
+ }
+ };
+
+ // Submit the query to be executed. A query implements a runnable
+ // interface and it has to be executed in order to do its work.
+ ImmediateExecutor.getInstance().execute(countQuery);
+ int count = 0;
+
+ // Block until the query completes, which will happen when the request
+ // monitor of the execute() method is marked done.
+ try {
+ count = countQuery.get();
+ } catch (Exception e) {
+ // InterruptedException and ExecutionException can be thrown here.
+ // ExecutionException containing a CoreException will be thrown
+ // if an error status is set to the Query's request monitor.
+ return new Object[0];
+ }
+
+ // Create the array that will be filled with elements.
+ // For each index in the array execute a query to get the element at
+ // that index.
+ final Object[] elements = new Object[count];
+
+ for (int i = 0; i < count; i++) {
+ final int index = i;
+ Query<String> valueQuery = new Query<String>() {
+ @Override
+ protected void execute(DataRequestMonitor<String> rm) {
+ fDataGenerator.getValue(index, rm);
+ }
+ };
+ ImmediateExecutor.getInstance().execute(valueQuery);
+ try {
+ elements[i] = valueQuery.get();
+ } catch (Exception e) {
+ elements[i] = "error";
+ }
+ }
+ return elements;
+ }
+
+ public void dispose() {
+ fDataGenerator.removeListener(this);
+ }
+
+ public void countChanged() {
+ // For any event from the generator, refresh the whole viewer.
+ refreshViewer();
+ }
+
+ public void valuesChanged(Set<Integer> indexes) {
+ // For any event from the generator, refresh the whole viewer.
+ refreshViewer();
+ }
+
+ private void refreshViewer() {
+ //#ifdef exercises
+ // TODO Exercise 5 - Add a call to getElements() to force a deadlock.
+ //#else
+//# getElements(null);
+ //#endif
+
+ // This method may be called on any thread, switch to the display
+ // thread before calling the viewer.
+ Display display = fViewer.getControl().getDisplay();
+ display.asyncExec( new Runnable() {
+ public void run() {
+ if (!fViewer.getControl().isDisposed()) {
+ fViewer.refresh();
+ }
+ }
+ });
+ }
+
+ public static void main(String[] args) {
+ // Create the shell to hold the viewer.
+ Display display = new Display();
+ Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setLayout(new GridLayout());
+ GridData data = new GridData(GridData.FILL_BOTH);
+ shell.setLayoutData(data);
+ Font font = new Font(display, "Courier", 10, SWT.NORMAL);
+
+ // Create the table viewer.
+ TableViewer tableViewer = new TableViewer(shell, SWT.BORDER);
+ tableViewer.getControl().setLayoutData(data);
+
+ // Create the data generator.
+ //#ifdef exercises
+ // TODO Exercise 5 - Use the DataGeneratorWithExecutor() instead.
+ final IDataGenerator generator = new DataGeneratorWithThread();
+ //#else
+//# final IDataGenerator generator = new DataGeneratorWithExecutor();
+ //#endif
+
+ // Create the content provider which will populate the viewer.
+ SyncDataViewer contentProvider = new SyncDataViewer(tableViewer, generator);
+ tableViewer.setContentProvider(contentProvider);
+ tableViewer.setInput(new Object());
+
+ // Open the shell and service the display dispatch loop until user
+ // closes the shell.
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch())
+ display.sleep();
+ }
+
+ // The IDataGenerator.shutdown() method is asynchronous, this requires
+ // using a query again in order to wait for its completion.
+ Query<Object> shutdownQuery = new Query<Object>() {
+ @Override
+ protected void execute(DataRequestMonitor<Object> rm) {
+ generator.shutdown(rm);
+ }
+ };
+ ImmediateExecutor.getInstance().execute(shutdownQuery);
+ try {
+ shutdownQuery.get();
+ } catch (Exception e) {}
+
+ // Shut down the display.
+ font.dispose();
+ display.dispose();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/Async2Plus2.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/Async2Plus2.java
new file mode 100644
index 00000000000..f2587380c4d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/Async2Plus2.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.requestmonitor;
+//#else
+//#package org.eclipse.cdt.examples.dsf.requestmonitor.answers;
+//#endif
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+
+/**
+ * Example of using a DataRequestMonitor to retrieve a result from an
+ * asynchronous method.
+ */
+public class Async2Plus2 {
+
+ public static void main(String[] args) {
+ Executor executor = ImmediateExecutor.getInstance();
+ DataRequestMonitor<Integer> rm =
+ new DataRequestMonitor<Integer>(executor, null) {
+ @Override
+ protected void handleCompleted() {
+ System.out.println("2 + 2 = " + getData());
+ }
+ };
+ asyncAdd(2, 2, rm);
+ }
+
+ static void asyncAdd(int value1, int value2, DataRequestMonitor<Integer> rm) {
+ rm.setData(value1 + value2);
+ rm.done();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncHelloWorld.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncHelloWorld.java
new file mode 100644
index 00000000000..81f23f61a2d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncHelloWorld.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.requestmonitor;
+//#else
+//#package org.eclipse.cdt.examples.dsf.requestmonitor.answers;
+//#endif
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * "Hello world" example which uses an asynchronous method to print out
+ * the result.
+ * <p>
+ * The main method uses an immediate executor, which executes runnables
+ * as soon as they are submitted, in creating its request monitor.
+ *
+ */
+public class AsyncHelloWorld {
+
+ public static void main(String[] args) {
+ Executor executor = ImmediateExecutor.getInstance();
+ RequestMonitor rm = new RequestMonitor(executor, null);
+ asyncHelloWorld(rm);
+ }
+
+ static void asyncHelloWorld(RequestMonitor rm) {
+ System.out.println("Hello world");
+ //#ifdef exercises
+ // TODO Exercise 1: - Call the second async. "Hello world 2" method.
+ // Hint: Calling an asynchronous method requires passing to it a
+ // request monitor. A new request monitor can be constructed with
+ // a parent RequestMonitor as an argument argument. The parent gets
+ // completed automatically when the lower level request monitor is
+ // completed.
+ rm.done();
+ //#else
+//# RequestMonitor rm2 = new RequestMonitor(ImmediateExecutor.getInstance(), rm);
+//# asyncHelloWorld2(rm2);
+ //#endif
+ }
+
+ //#ifdef exercises
+ // TODO: Exercise 1 - Add a second async. "Hello world 2" method.
+ //#else
+//# static void asyncHelloWorld2(RequestMonitor rm) {
+//# System.out.println("Hello world 2");
+//# rm.done();
+//# }
+ //#endif
+}
diff --git a/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncQuicksort.java b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncQuicksort.java
new file mode 100644
index 00000000000..2adb1a02c28
--- /dev/null
+++ b/dsf/org.eclipse.cdt.examples.dsf/src_preprocess/org/eclipse/cdt/examples/dsf/requestmonitor/AsyncQuicksort.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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
+ *******************************************************************************/
+//#ifdef exercises
+package org.eclipse.cdt.examples.dsf.requestmonitor;
+//#else
+//#package org.eclipse.cdt.examples.dsf.requestmonitor.answers;
+//#endif
+
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+//#ifdef answers
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+//#endif
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * Example of using a CountingRequestMonitor to wait for multiple
+ * asynchronous calls to complete.
+ */
+public class AsyncQuicksort {
+
+ static Executor fgExecutor = ImmediateExecutor.getInstance();
+
+ public static void main(String[] args) {
+ final int[] array = {5, 7, 8, 3, 2, 1, 9, 5, 4};
+
+ System.out.println("To sort: " + Arrays.toString(array));
+ asyncQuicksort(
+ array, 0, array.length - 1,
+ new RequestMonitor(fgExecutor, null) {
+ @Override
+ protected void handleCompleted() {
+ System.out.println("Sorted: " + Arrays.toString(array));
+ }
+ });
+ }
+
+ static void asyncQuicksort(final int[] array, final int left,
+ final int right, final RequestMonitor rm)
+ {
+ if (right > left) {
+ int pivot = left;
+ //#ifdef exercises
+ // TODO: Exercise 2 - Convert the call to partition into an
+ // asynchronous call to asyncPartition().
+ // Hint: The rest of the code below should be executed inside
+ // the DataRequestMonitor.handleCompleted() overriding method.
+ int newPivot = partition(array, left, right, pivot);
+ printArray(array, left, right, newPivot);
+
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
+ asyncQuicksort(array, left, newPivot - 1, countingRm);
+ asyncQuicksort(array, newPivot + 1, right, countingRm);
+ countingRm.setDoneCount(2);
+ //#else
+//# asyncPartition(
+//# array, left, right, pivot,
+//# new DataRequestMonitor<Integer>(fgExecutor, rm) {
+//# @Override
+//# protected void handleCompleted() {
+//# int newPivot = getData();
+//# printArray(array, left, right, newPivot);
+//#
+//# CountingRequestMonitor countingRm = new CountingRequestMonitor(fgExecutor, rm);
+//# asyncQuicksort(array, left, newPivot - 1, countingRm);
+//# asyncQuicksort(array, newPivot + 1, right, countingRm);
+//# countingRm.setDoneCount(2);
+//# }
+//# });
+ //#endif
+ } else {
+ rm.done();
+ }
+ }
+
+ //#ifdef exercises
+ // TODO Exercise 2 - Convert partition to an asynchronous method.
+ // Hint: a DataRequestMonitor<Integer> should be used to carry the
+ // return value to the caller.
+ static int partition(int[] array, int left, int right, int pivot)
+ //#else
+//# static void asyncPartition(int[] array, int left, int right, int pivot, DataRequestMonitor<Integer> rm)
+ //#endif
+ {
+ int pivotValue = array[pivot];
+ array[pivot] = array[right];
+ array[right] = pivotValue;
+ int store = left;
+ for (int i = left; i < right; i++) {
+ if (array[i] <= pivotValue) {
+ int tmp = array[store];
+ array[store] = array[i];
+ array[i] = tmp;
+ store++;
+ }
+ }
+ array[right] = array[store];
+ array[store] = pivotValue;
+
+ //#ifdef exercises
+ // TODO: Request Monitors Exercise 2 - Return the data to caller using
+ // a request monitor.
+ return store;
+ //#else
+//# // Java 5 automatically converts the int type of the store variable
+//# // to an Integer object.
+//# rm.setData(store);
+//# rm.done();
+ //#endif
+ }
+
+ static void printArray(int[] array, int left, int right, int pivot) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < array.length; i++ ) {
+ if (i == left) {
+ buffer.append('>');
+ } else if (i == pivot) {
+ buffer.append('-');
+ } else {
+ buffer.append(' ');
+ }
+ buffer.append(array[i]);
+
+ if (i == right) {
+ buffer.append('<');
+ } else if (i == pivot) {
+ buffer.append('-');
+ } else {
+ buffer.append(' ');
+ }
+ }
+
+ System.out.println(buffer);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/.classpath b/dsf/org.eclipse.cdt.tests.dsf/.classpath
new file mode 100644
index 00000000000..304e86186aa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/dsf/org.eclipse.cdt.tests.dsf/.cvsignore b/dsf/org.eclipse.cdt.tests.dsf/.cvsignore
new file mode 100644
index 00000000000..ba077a4031a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/dsf/org.eclipse.cdt.tests.dsf/.project b/dsf/org.eclipse.cdt.tests.dsf/.project
new file mode 100644
index 00000000000..1764ef4ec6f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.cdt.tests.dsf</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/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.core.prefs b/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..8f1321e3841
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,70 @@
+#Thu Sep 25 17:12:53 PDT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+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=ignore
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=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=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=error
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.ui.prefs b/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000000..28984618f01
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,3 @@
+#Thu Oct 12 11:27:35 PDT 2006
+eclipse.preferences.version=1
+internal.default.compliance=default
diff --git a/dsf/org.eclipse.cdt.tests.dsf/META-INF/MANIFEST.MF b/dsf/org.eclipse.cdt.tests.dsf/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..bbf5a59a186
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-Vendor: %pluginProvider
+Bundle-SymbolicName: org.eclipse.cdt.tests.dsf;singleton:=true
+Bundle-Version: 2.0.0.qualifier
+Bundle-Activator: org.eclipse.cdt.tests.dsf.DsfTestPlugin
+Bundle-Localization: plugin
+Bundle-ActivationPolicy: lazy
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.debug.ui,
+ org.eclipse.cdt.dsf,
+ org.junit4,
+ org.eclipse.ui,
+ org.eclipse.cdt.dsf.ui
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/dsf/org.eclipse.cdt.tests.dsf/about.html b/dsf/org.eclipse.cdt.tests.dsf/about.html
new file mode 100644
index 00000000000..04492dd7e1b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/about.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+
+
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>About</title></head><body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>May 14, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, "Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party ("Redistributor") and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body></html> \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.tests.dsf/build.properties b/dsf/org.eclipse.cdt.tests.dsf/build.properties
new file mode 100644
index 00000000000..e398e4efb7b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ about.html,\
+ plugin.properties
diff --git a/dsf/org.eclipse.cdt.tests.dsf/plugin.properties b/dsf/org.eclipse.cdt.tests.dsf/plugin.properties
new file mode 100644
index 00000000000..309e6e2f7d7
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2006 Wind River Systems 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=Debugger Services Framework Test Plugin
+providerName=Eclipse.org
+
diff --git a/dsf/org.eclipse.cdt.tests.dsf/plugin.xml b/dsf/org.eclipse.cdt.tests.dsf/plugin.xml
new file mode 100644
index 00000000000..ba839803701
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/plugin.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <category
+ name="DSF Tests"
+ id="org.eclipse.cdt.tests.dsf.model">
+ </category>
+ <view
+ name="Model Test View"
+ category="org.eclipse.cdt.tests.dsf.model"
+ class="org.eclipse.cdt.tests.dsf.model.ModelTestsView"
+ id="org.eclipse.cdt.tests.dsf.model.ModelTestView">
+ </view>
+ </extension>
+</plugin>
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/DsfTestPlugin.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/DsfTestPlugin.java
new file mode 100644
index 00000000000..742f1dda5cf
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/DsfTestPlugin.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfTestPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.tests.dsf"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfTestPlugin fgPlugin;
+ private static BundleContext fgBundleContext;
+
+ /**
+ * The constructor
+ */
+ public DsfTestPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ fgBundleContext = null;
+ fgPlugin = null;
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfTestPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/TestDsfExecutor.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/TestDsfExecutor.java
new file mode 100644
index 00000000000..3abea7202ae
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/TestDsfExecutor.java
@@ -0,0 +1,50 @@
+package org.eclipse.cdt.tests.dsf;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
+
+/**
+ * DsfExecutor for use with unit tests. It records the exceptions that were
+ * thrown in the executor thread so that they can be re-thrown by the test.
+ *
+ */
+public class TestDsfExecutor extends DefaultDsfExecutor {
+ private List<Throwable> fExceptions = Collections.synchronizedList(new ArrayList<Throwable>());
+
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ super.afterExecute(r, t);
+ if (r instanceof Future<?>) {
+ Future<?> future = (Future<?>)r;
+ try {
+ if (future.isDone()) {
+ future.get();
+ }
+ future.get();
+ } catch (InterruptedException e) { // Ignore
+ } catch (CancellationException e) { // Ignore also
+ } catch (ExecutionException e) {
+ if (e.getCause() != null) {
+ fExceptions.add(e.getCause());
+ }
+ }
+ }
+ }
+
+ public boolean exceptionsCaught() {
+ return fExceptions.size() != 0;
+ }
+
+ public Throwable[] getExceptions() {
+ synchronized (fExceptions) {
+ return fExceptions.toArray(new Throwable[fExceptions.size()]);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ValueHolder.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ValueHolder.java
new file mode 100644
index 00000000000..fb3945e25fd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/ValueHolder.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf;
+
+/**
+ * Utility class to hold a value retrieved in a runnable.
+ * Usage in a test is as follows:
+ * <pre>
+ * final ValueHolder<Integer> value = new ValueHolder<Integer>();
+ * fExecutor.execute(new Runnable() {
+ * public void run() {
+ * value.fValue = 1;
+ * }
+ * });
+ * Assert.assertTrue(value.fValue == 1);
+ * </pre>
+ */
+public class ValueHolder<V> {
+ public V fValue;
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfQueryTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfQueryTests.java
new file mode 100644
index 00000000000..6c78e535019
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfQueryTests.java
@@ -0,0 +1,216 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import junit.framework.Assert;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests that exercise the Query object.
+ */
+public class DsfQueryTests {
+ TestDsfExecutor fExecutor;
+
+ @Before
+ public void startServices() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+ }
+
+ @After
+ public void shutdownServices() throws ExecutionException, InterruptedException {
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fExecutor.shutdown();
+ }}).get();
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+ @Test
+ public void simpleGetTest() throws InterruptedException, ExecutionException {
+ Query<Integer> q = new Query<Integer>() {
+ @Override
+ protected void execute(DataRequestMonitor<Integer> rm) {
+ rm.setData(1);
+ rm.done();
+ }
+ };
+ // Check initial state
+ Assert.assertTrue(!q.isDone());
+ Assert.assertTrue(!q.isCancelled());
+
+ fExecutor.execute(q);
+ Assert.assertEquals(1, (int)q.get());
+
+ // Check final state
+ Assert.assertTrue(q.isDone());
+ Assert.assertTrue(!q.isCancelled());
+
+ }
+
+ @Test
+ public void getWithMultipleDispatchesTest() throws InterruptedException, ExecutionException {
+ Query<Integer> q = new Query<Integer>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Integer> rm) {
+ fExecutor.execute(new DsfRunnable() {
+ public void run() {
+ rm.setData(1);
+ rm.done();
+ }
+ @Override
+ public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() second runnable"; } //$NON-NLS-1$
+ });
+ }
+ @Override
+ public String toString() { return super.toString() + "\n getWithMultipleDispatchesTest() first runnable (query)"; } //$NON-NLS-1$
+ };
+ fExecutor.execute(q);
+ Assert.assertEquals(1, (int)q.get());
+ }
+
+ @Test (expected = ExecutionException.class)
+ public void exceptionOnGetTest() throws InterruptedException, ExecutionException {
+ Query<Integer> q = new Query<Integer>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Integer> rm) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ };
+
+ fExecutor.execute(q);
+
+ try {
+ q.get();
+ } finally {
+ Assert.assertTrue(q.isDone());
+ Assert.assertTrue(!q.isCancelled());
+ }
+ }
+
+ @Test
+ public void cancelWhileWaitingTest() throws InterruptedException, ExecutionException {
+ final Query<Integer> q = new Query<Integer>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Integer> rm) {
+ // Call done with a delay of 1 second, to avoid stalling the tests.
+ fExecutor.schedule(
+ new DsfRunnable() {
+ public void run() { rm.done(); }
+ },
+ 1, TimeUnit.SECONDS);
+ }
+ };
+
+ fExecutor.execute(q);
+
+ // Note: no point in checking isDone() and isCancelled() here, because
+ // the value could change on timing.
+
+ // This does not really guarantee that the cancel will be called after
+ // the call to Fugure.get(), but the 1ms delay in call to schedule should
+ // help.
+ new Job("DsfQueryTests cancel job") { @Override public IStatus run(IProgressMonitor monitor) { //$NON-NLS-1$
+ q.cancel(false);
+ return Status.OK_STATUS;
+ }}.schedule(1);
+
+ try {
+ q.get();
+ } catch (CancellationException e) {
+ return; // Success
+ } finally {
+ Assert.assertTrue(q.isDone());
+ Assert.assertTrue(q.isCancelled());
+ }
+ Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$
+ }
+
+ @Test
+ public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException {
+ final Query<Integer> q = new Query<Integer>() {
+ @Override protected void execute(final DataRequestMonitor<Integer> rm) {
+ Assert.fail("Query was cancelled, it should not be called."); //$NON-NLS-1$
+ rm.done();
+ }
+ };
+
+ // Cancel before invoking the query.
+ q.cancel(false);
+
+ Assert.assertTrue(q.isDone());
+ Assert.assertTrue(q.isCancelled());
+
+ // Start the query.
+ fExecutor.execute(q);
+
+ // Block to retrieve data
+ try {
+ q.get();
+ } catch (CancellationException e) {
+ return; // Success
+ } finally {
+ Assert.assertTrue(q.isDone());
+ Assert.assertTrue(q.isCancelled());
+ }
+ Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$
+ }
+
+ @Test
+ public void getTimeoutTest() throws InterruptedException, ExecutionException {
+ final Query<Integer> q = new Query<Integer>() {
+ @Override
+ protected void execute(final DataRequestMonitor<Integer> rm) {
+ // Call done with a delay of 1 second, to avoid stalling the tests.
+ fExecutor.schedule(
+ new DsfRunnable() {
+ public void run() { rm.done(); }
+ },
+ 1, TimeUnit.SECONDS);
+ }
+ };
+
+ fExecutor.execute(q);
+
+ // Note: no point in checking isDone() and isCancelled() here, because
+ // the value could change on timing.
+
+ try {
+ q.get(1, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ return; // Success
+ } finally {
+ Assert.assertFalse("Query should not be done yet, it should have timed out first.", q.isDone()); //$NON-NLS-1$
+ }
+ Assert.assertTrue("TimeoutException should have been thrown", false); //$NON-NLS-1$
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceProgressTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceProgressTests.java
new file mode 100644
index 00000000000..fb55ecf1985
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceProgressTests.java
@@ -0,0 +1,271 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia 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:
+ * Nokia - initial implementation. Oct. 2008
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.concurrent;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.swt.widgets.Display;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test whether a step in a sequence can control the progress monitor.
+ */
+public class DsfSequenceProgressTests {
+ private List<Throwable> fExceptions = Collections.synchronizedList(new ArrayList<Throwable>());
+ TestDsfExecutor fExecutor;
+
+ @Before
+ public void startExecutor() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+ }
+
+ @After
+ public void shutdownExecutor() throws ExecutionException, InterruptedException {
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fExecutor.shutdown();
+ }}).get();
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+ // Create a counter for tracking number of steps performed and steps
+ // rolled back.
+ class IntegerHolder { int fInteger; }
+ final IntegerHolder stepCounter = new IntegerHolder();
+ final IntegerHolder rollBackCounter = new IntegerHolder();
+
+ class SleepStep extends Sequence.Step {
+
+ @Override
+ public int getTicks() {
+ return 6;
+ }
+
+ @Override public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+
+ sleep(getTicks(), requestMonitor, null);
+
+ requestMonitor.done();
+ }
+
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ rollBackCounter.fInteger++;
+
+ sleep(1, null, null);
+
+ requestMonitor.done();
+ }
+
+ }
+
+ class SleepStepWithProgress extends Sequence.StepWithProgress {
+
+ @Override
+ public int getTicks() {
+ return 6;
+ }
+
+ private final static int SUB_TICKS = 3;
+
+ @Override
+ public void execute(RequestMonitor rm, IProgressMonitor pm) {
+ stepCounter.fInteger++;
+
+
+ // step has its own sub-progress ticks which take the total ticks
+ // of this step and divides them into subticks
+ pm.beginTask(getTaskName() + ": ", SUB_TICKS);
+ sleep(SUB_TICKS, rm, pm);
+
+ rm.done();
+ pm.done();
+ }
+
+ @Override
+ public void rollBack(RequestMonitor rm) {
+ rollBackCounter.fInteger++;
+
+ sleep(2, null, null);
+ rm.done();
+ }
+
+ }
+
+ @Test
+ /**
+ * It's better to run this as a manual interactive test. Run this as a JUnit
+ * plugin test.<br>
+ * <br>
+ * In the test workbench, watch the progress bar in the Progress View.<br>
+ * <br>
+ * During execution of a StepWithProgress, you should see the progress bar
+ * is growing and you can have more responsive cancel.<br>
+ * <br>
+ * Meanwhile, during execution of a step without progress, you should see
+ * that progress bar does not grow and cancel does not work until end of the
+ * step.<br>
+ * <br>
+ * Also watch that when you cancel the progress bar during the execution of
+ * the sequence, you should see that "Rollback.." appears in the progress bar
+ * label.<br>
+ */
+ public void sequenceProgressTest() throws InterruptedException, ExecutionException {
+
+ final Sequence.Step[] steps = new Sequence.Step[] {
+
+ new SleepStepWithProgress() {
+ @Override
+ public String getTaskName() {
+ return "StepWithProgress #1";
+ }},
+
+ new SleepStepWithProgress() {
+ @Override
+ public String getTaskName() {
+ return "StepWithProgress #2";
+ }},
+
+ new SleepStep() {
+ @Override
+ public String getTaskName() {
+ return "Step #3";
+ }},
+
+ new SleepStep() {
+ @Override
+ public String getTaskName() {
+ return "Step #4";
+ }},
+ };
+
+
+ fExceptions.clear();
+
+ Job myJob = new Job("Run test sequence") {
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ // Create and start.
+ Sequence sequence = new Sequence(fExecutor, monitor, "Run my sequence", "Rollback my sequence") {
+ @Override public Step[] getSteps() { return steps; }
+ };
+ fExecutor.execute(sequence);
+
+ // Block and wait for sequence to complete.
+ try {
+ sequence.get();
+ } catch (InterruptedException e) {
+ // ignore here.
+ } catch (ExecutionException e) {
+ // Expected exception, ignore here.
+ } finally {
+ try {
+ System.out.println("StepCounter: " + stepCounter.fInteger);
+ System.out.println("RollBackCounter: " + rollBackCounter.fInteger);
+
+ if (sequence.isCancelled())
+ Assert.assertTrue(
+ "Wrong number of steps were rolled back after cancellation.",
+ stepCounter.fInteger == rollBackCounter.fInteger);
+ else {
+ Assert.assertTrue(
+ "Wrong number of steps executed.",
+ stepCounter.fInteger == steps.length);
+ Assert.assertTrue(
+ "Some steps are mistakenly rolled back",
+ rollBackCounter.fInteger == 0);
+ }
+
+ // Check state from Future interface
+ Assert.assertTrue(sequence.isDone());
+ } catch (AssertionFailedError e) {
+ fExceptions.add(e);
+ }
+ }
+ return null;
+ }};
+
+ myJob.schedule();
+
+ // Wait for the job to finish
+ waitForJob(myJob);
+
+ // now throw any assertion errors.
+ if (fExceptions.size() > 0)
+ throw (AssertionFailedError)fExceptions.get(0);
+
+ }
+
+ private static void sleep(int seconds, RequestMonitor rm, IProgressMonitor pm) {
+ try {
+ for (int i = 0; i < seconds; i++) {
+ if (pm != null)
+ pm.subTask("subStep - " + (i+1));
+
+ Thread.sleep(1000);
+
+ if (pm != null) {
+ pm.worked(1);
+
+ if (pm.isCanceled()) {
+ return;
+ }
+ }
+
+ if (rm != null && rm.isCanceled()) {
+ return;
+ }
+ }
+
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ // Wait for a job to finish without possible blocking of UI thread.
+ //
+ private static void waitForJob(Job job) {
+ Display display = Display.getCurrent();
+ while (true) {
+ IStatus status = job.getResult();
+ if (status != null)
+ break;
+ if (display != null) {
+ while (display.readAndDispatch()) ;
+ }
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException e) {
+ job.cancel();
+ break;
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceTests.java
new file mode 100644
index 00000000000..51e8569376a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/concurrent/DsfSequenceTests.java
@@ -0,0 +1,315 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests that exercise the Sequence object.
+ */
+public class DsfSequenceTests {
+ TestDsfExecutor fExecutor;
+
+ @Before
+ public void startExecutor() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+ }
+
+ @After
+ public void shutdownExecutor() throws ExecutionException, InterruptedException {
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fExecutor.shutdown();
+ }}).get();
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+ @Test
+ public void simpleTest() throws InterruptedException, ExecutionException {
+ // Create a counter for tracking number of steps performed.
+ class IntegerHolder { int fInteger; }
+ final IntegerHolder stepCounter = new IntegerHolder();
+
+ // Create the steps of the sequence
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+ requestMonitor.done();
+ }
+ },
+ new Sequence.Step() {
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ // Create, start, and wait for the sequence.
+ Sequence sequence = new Sequence(fExecutor) {
+ @Override public Step[] getSteps() { return steps; }
+ };
+ Assert.assertTrue(!sequence.isDone());
+ Assert.assertTrue(!sequence.isCancelled());
+
+ fExecutor.execute(sequence);
+ sequence.get();
+
+ // Check the count
+ Assert.assertTrue(stepCounter.fInteger == 2);
+
+ // Check post conditions
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(!sequence.isCancelled());
+ }
+
+ @Test (expected = ExecutionException.class)
+ public void rollbackTest() throws InterruptedException, ExecutionException {
+ // Create a counter for tracking number of steps performed and steps
+ // rolled back.
+ class IntegerHolder { int fInteger; }
+ final IntegerHolder stepCounter = new IntegerHolder();
+ final IntegerHolder rollBackCounter = new IntegerHolder();
+
+ // Create the steps of the sequence
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+ requestMonitor.done();
+ }
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ rollBackCounter.fInteger++;
+ requestMonitor.done();
+ }
+ },
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+ requestMonitor.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "", null)); //$NON-NLS-1$
+ requestMonitor.done();
+ }
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ rollBackCounter.fInteger++;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ // Create and start.
+ Sequence sequence = new Sequence(fExecutor) {
+ @Override public Step[] getSteps() { return steps; }
+ };
+ fExecutor.execute(sequence);
+
+ // Block and wait for sequence to bomplete.
+ try {
+ sequence.get();
+ } finally {
+ // Both steps should be performed
+ Assert.assertTrue(stepCounter.fInteger == 2);
+ // Only one step is rolled back, the first one.
+ Assert.assertTrue(rollBackCounter.fInteger == 1);
+
+ // Check state from Future interface
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(!sequence.isCancelled());
+ }
+ Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
+ }
+
+ /**
+ * The goal of this test it to check that if an exception is thrown within
+ * the Step.execute(), the step will return from the Future.get() method.
+ */
+ @Test (expected = ExecutionException.class)
+ public void exceptionTest() throws InterruptedException, ExecutionException {
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ throw new Error("Exception part of unit test."); //$NON-NLS-1$
+ }
+ }
+ };
+
+ // Create and start.
+ Sequence sequence = new Sequence(fExecutor) {
+ @Override public Step[] getSteps() { return steps; }
+ };
+ fExecutor.execute(sequence);
+
+ // Block and wait for sequence to bomplete.
+ try {
+ sequence.get();
+ } finally {
+ // Check state from Future interface
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(!sequence.isCancelled());
+ }
+ Assert.assertTrue("Exception should have been thrown", false); //$NON-NLS-1$
+ }
+
+
+ @Test (expected = CancellationException.class)
+ public void cancelBeforeWaitingTest() throws InterruptedException, ExecutionException {
+ // Create the sequence
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$
+ }
+ }
+ };
+ Sequence sequence = new Sequence(fExecutor) {
+ @Override public Step[] getSteps() { return steps; }
+ };
+
+ // Cancel before invoking the sequence.
+ sequence.cancel(false);
+
+ Assert.assertTrue(!sequence.isDone());
+ Assert.assertTrue(sequence.isCancelled());
+
+ // Start the sequence
+ fExecutor.execute(sequence);
+
+ // Block and wait for sequence to bomplete.
+ try {
+ sequence.get();
+ } finally {
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(sequence.isCancelled());
+ }
+ Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$
+ }
+
+
+ @Test (expected = CancellationException.class)
+ public void cancelFromStepTest() throws InterruptedException, ExecutionException {
+ // Create a counter for tracking number of steps performed and steps
+ // rolled back.
+ class IntegerHolder { int fInteger; }
+ final IntegerHolder stepCounter = new IntegerHolder();
+ final IntegerHolder rollBackCounter = new IntegerHolder();
+
+ // Create the steps of the sequence
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+ requestMonitor.done();
+ }
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ rollBackCounter.fInteger++;
+ requestMonitor.done();
+ }
+ },
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ stepCounter.fInteger++;
+
+ // Perform the cancel!
+ getSequence().cancel(false);
+
+ requestMonitor.done();
+ }
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ rollBackCounter.fInteger++;
+ requestMonitor.done();
+ }
+ }
+ };
+
+ // Create and start sequence with a delay. Delay so that we call get() before
+ // cancel is called.
+ final Sequence sequence = new Sequence(fExecutor) {
+ @Override public Step[] getSteps() { return steps; }
+ };
+ fExecutor.schedule(sequence, 1, TimeUnit.MILLISECONDS);
+
+ // Block to retrieve data
+ try {
+ sequence.get();
+ } finally {
+ // Both steps should be performed
+ Assert.assertTrue(stepCounter.fInteger == 2);
+ // Both roll-backs should be performed since cancel does not take effect until
+ // after the step is completed.
+ Assert.assertTrue(rollBackCounter.fInteger == 2);
+
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(sequence.isCancelled());
+ }
+ Assert.assertTrue("CancellationException should have been thrown", false); //$NON-NLS-1$
+ }
+
+ @Test (expected = CancellationException.class)
+ public void cancelBeforeWithProgressManagerTest() throws InterruptedException, ExecutionException {
+ // Create the sequence
+ final Sequence.Step[] steps = new Sequence.Step[] {
+ new Sequence.Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ Assert.assertTrue("Sequence was cancelled, it should not be called.", false); //$NON-NLS-1$
+ }
+ }
+ };
+
+ // Create the progress monitor that we will cancel.
+ IProgressMonitor pm = new NullProgressMonitor();
+
+ // Create the seqeunce with our steps.
+ Sequence sequence = new Sequence(fExecutor, pm, "", "") { //$NON-NLS-1$ //$NON-NLS-2$
+ @Override public Step[] getSteps() { return steps; }
+ };
+
+ // Cancel the progress monitor before invoking the sequence. Note
+ // that the state of the sequence doesn't change yet, because the
+ // sequence does not check the progress monitor until it is executed.
+ pm.setCanceled(true);
+
+ // Start the sequence
+ fExecutor.execute(sequence);
+
+ // Block and wait for sequence to bomplete. Exception is thrown,
+ // which is expected.
+ try {
+ sequence.get();
+ } finally {
+ Assert.assertTrue(sequence.isDone());
+ Assert.assertTrue(sequence.isCancelled());
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/dm/DMContextsTest.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/dm/DMContextsTest.java
new file mode 100644
index 00000000000..86f33078888
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/dm/DMContextsTest.java
@@ -0,0 +1,185 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Ericsson 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:
+ * Ericsson - Initial Implementation
+ *******************************************************************************/
+package org.eclipse.cdt.tests.dsf.dm;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+
+public class DMContextsTest {
+
+ TestDsfExecutor fExecutor;
+ DsfSession fSession;
+
+ @Before public void startExecutor() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fSession = DsfSession.startSession(fExecutor, "DMContextsTest"); //$NON-NLS-1$
+ }}).get();
+
+ // Build a hierarchy of contexts to run the tests. Note that this hierarchy
+ // is not valid in the DSF model, but that is ok for these tests.
+ // Let's build the following:
+ //
+ // SecondType4
+ // |
+ // FirstType3 SecondType7
+ // | |
+ // ThirdType2 ThirdType6
+ // | / |
+ // FirstType1 ThirdType5
+ // | /
+ // FirstType0
+ c[7] = new SecondType(new IDMContext[0], 7);
+ c[6] = new ThirdType(new IDMContext[]{c[7]}, 6);
+ c[5] = new ThirdType(new IDMContext[]{c[6]}, 5);
+ c[4] = new SecondType(new IDMContext[0], 4);
+ c[3] = new FirstType(new IDMContext[]{c[4]}, 3);
+ c[2] = new ThirdType(new IDMContext[]{c[3]}, 2);
+ c[1] = new FirstType(new IDMContext[]{c[2],c[6]}, 1);
+ c[0] = new FirstType(new IDMContext[]{c[1],c[5]}, 0);
+ }
+
+ @After public void shutdownExecutor() throws ExecutionException, InterruptedException {
+ DsfSession.endSession(fSession);
+ fSession = null;
+
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fExecutor.shutdown();
+ }}).get();
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+
+ BaseContextType c[] = new BaseContextType[8];
+
+
+ private class BaseContextType extends AbstractDMContext {
+ final int fId;
+
+ public BaseContextType(IDMContext[] parents, int id) {
+ super(fSession.getId(), parents);
+ fId = id;
+ }
+
+ @Override
+ public String toString() { return baseToString() + ".[" + fId + "]"; } //$NON-NLS-1$ //$NON-NLS-2$
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.baseEquals(obj) && ((BaseContextType)obj).fId == fId;
+ }
+
+ @Override
+ public int hashCode() { return super.baseHashCode() ^ fId; }
+ }
+
+ private class FirstType extends BaseContextType {
+ public FirstType(IDMContext[] parents, int id) {
+ super(parents, id);
+ }
+ }
+
+ private class SecondType extends BaseContextType {
+ public SecondType(IDMContext[] parents, int id) {
+ super(parents, id);
+ }
+ }
+
+ private class ThirdType extends BaseContextType {
+ public ThirdType(IDMContext[] parents, int id) {
+ super(parents, id);
+ }
+ }
+
+ private interface UnknownType extends IDMContext {}
+
+ /**
+ * Test that we get the closest ancestor in terms of depth.
+ */
+ @Test
+ public void testClosestAncestor() throws Throwable {
+ BaseContextType ancestor = DMContexts.getAncestorOfType(c[0], FirstType.class);
+ assertTrue("Got unexpected null ancestor", ancestor != null);
+ assertTrue("Got ancestor " + ancestor.fId + " intead of 1", ancestor.fId == 0);
+
+ ancestor = DMContexts.getAncestorOfType(c[0], SecondType.class);
+ assertTrue("Got unexpected null ancestor", ancestor != null);
+ assertTrue("Got ancestor " + ancestor.fId + " intead of 8", ancestor.fId == 7);
+
+ ancestor = DMContexts.getAncestorOfType(c[0], ThirdType.class);
+ assertTrue("Got unexpected null ancestor", ancestor != null);
+ assertTrue("Got ancestor " + ancestor.fId + " intead of 6", ancestor.fId == 5);
+
+ ancestor = DMContexts.getAncestorOfType(c[1], SecondType.class);
+ assertTrue("Got unexpected null ancestor", ancestor != null);
+ assertTrue("Got ancestor " + ancestor.fId + " intead of 8", ancestor.fId == 7);
+
+ ancestor = DMContexts.getAncestorOfType(c[1], ThirdType.class);
+ assertTrue("Got unexpected null ancestor", ancestor != null);
+ assertTrue("Got ancestor " + ancestor.fId + " intead of 3", ancestor.fId == 2);
+
+ ancestor = DMContexts.getAncestorOfType(c[5], FirstType.class);
+ assertTrue("Got unexpected non-null ancestor", ancestor == null);
+ }
+
+ /**
+ * Test that we get all the ancestors in order of closest in terms of depth.
+ */
+ @Test
+ public void testAllClosestAncestors() throws Throwable {
+
+ checkAncestors(c[0], BaseContextType.class, new int[]{0,1,5,2,6,3,7,4});
+ checkAncestors(c[0], FirstType.class, new int[]{0,1,3});
+ checkAncestors(c[0], SecondType.class, new int[]{7,4});
+ checkAncestors(c[0], ThirdType.class, new int[]{5,2,6});
+
+ UnknownType[] exprAncestors = DMContexts.getAllAncestorsOfType(c[0], UnknownType.class);
+ assertTrue("Got unexpected non-null ancestor list", exprAncestors == null);
+ }
+
+ private <V extends IDMContext> void checkAncestors(BaseContextType ctx, Class<V> type, int[] expected) {
+ BaseContextType[] ancestors = (BaseContextType[])DMContexts.getAllAncestorsOfType(ctx, type);
+ assertTrue("Got unexpected null ancestor", ancestors != null);
+
+ String ancestorsStr = "", expectedStr = "";
+ for (int k=0;k<ancestors.length;k++) {
+ ancestorsStr += ancestors[k].fId + ",";
+ }
+ for (int j=0;j<expected.length;j++) {
+ expectedStr += expected[j] + ",";
+ }
+
+ assertTrue("Got " + ancestorsStr + " instead of " + expectedStr, ancestors.length == expected.length);
+ for (int i=0;i<expected.length;i++) {
+ if (ancestors[i].fId != expected[i]) {
+ assertTrue("Got " + ancestorsStr + " instead of " + expectedStr, false);
+ }
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/AbstractService.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/AbstractService.java
new file mode 100644
index 00000000000..2aa8af6699b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/AbstractService.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Test service class used to test event behavior. It has three types of events
+ * and three methods to receive the events.
+ *
+ */
+abstract public class AbstractService extends AbstractDsfService
+{
+ AbstractService(DsfSession session) {
+ super(session);
+ }
+
+ @Override protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ @Override public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ getSession().addServiceEventListener(this, null);
+ requestMonitor.done();
+ }
+
+ @Override public void shutdown(RequestMonitor requestMonitor) {
+ getSession().removeServiceEventListener(this);
+ super.shutdown(requestMonitor);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Test API
+ /** Records the number in the event 1 object when this service received the event. */
+ int fEvent1RecipientNumber;
+
+ /** Records the number in the event 2 object when this service received the event. */
+ int fEvent2RecipientNumber;
+
+ /** Records the number in the event 3 object when this service received the event. */
+ int fEvent3RecipientNumber;
+
+ /** Simple event class 1 */
+ public class Event1 {
+ // 1-based counter for the recipient of the event.
+ int fRecipientNumberCounter = 1;
+ }
+
+ /** Simple event class 2. Note it doesn't have any relation to event 1 */
+ public class Event2 {
+ int fRecipientNumberCounter = 1;
+ }
+
+ /** Simple event class 3. Note it does sub-class event 1 */
+ public class Event3 extends Event1 {}
+
+ @ThreadSafe
+ public void dispatchEvent1() {
+ getSession().dispatchEvent(new Event1(), getProperties());
+ }
+
+ @ThreadSafe
+ public void dispatchEvent2() {
+ getSession().dispatchEvent(new Event2(), getProperties());
+ }
+
+ @ThreadSafe
+ public void dispatchEvent3() {
+ getSession().dispatchEvent(new Event3(), getProperties());
+ }
+
+ /** Handles event 1 (and event 3 which derives from event 1) */
+ @DsfServiceEventHandler public void eventDispatched(Event1 e) {
+ fEvent1RecipientNumber = e.fRecipientNumberCounter++;
+ }
+
+ /** Handles event 2 only */
+ @DsfServiceEventHandler public void eventDispatched(Event2 e) {
+ fEvent2RecipientNumber = e.fRecipientNumberCounter++;
+ }
+
+ /** Handles event 3 only */
+ @DsfServiceEventHandler public void eventDispatched(Event3 e) {
+ fEvent3RecipientNumber = e.fRecipientNumberCounter++;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event1.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event1.java
new file mode 100644
index 00000000000..9ac2e055b40
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event1.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+
+public class Event1 {
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event2.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event2.java
new file mode 100644
index 00000000000..1cc5cb11afa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Event2.java
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+public class Event2 extends Event1 {
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/EventTest.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/EventTest.java
new file mode 100644
index 00000000000..2f4963c17a4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/EventTest.java
@@ -0,0 +1,147 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class EventTest {
+
+ DsfSession fSession;
+ TestDsfExecutor fExecutor;
+ DsfServicesTracker fTracker;
+ Service1 fService1;
+ Service2 fService2;
+ Service3 fService3;
+
+ @Before public void startServices() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fSession = DsfSession.startSession(fExecutor, "org.eclipse.cdt.tests.dsf"); //$NON-NLS-1$
+ }}).get();
+
+ StartupSequence startupSeq = new StartupSequence(fSession);
+ fExecutor.execute(startupSeq);
+ startupSeq.get();
+
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fTracker = new DsfServicesTracker(DsfTestPlugin.getBundleContext(), fSession.getId());
+ fService1 = fTracker.getService(Service1.class);
+ fService2 = fTracker.getService(Service2.class);
+ fService3 = fTracker.getService(Service3.class);
+ }}).get();
+ Assert.assertNotNull(fService1);
+ Assert.assertNotNull(fService2);
+ Assert.assertNotNull(fService3);
+ }
+
+ @After public void shutdownServices() throws ExecutionException, InterruptedException {
+ ShutdownSequence shutdownSeq = new ShutdownSequence(fSession);
+ fExecutor.execute(shutdownSeq);
+ shutdownSeq.get();
+
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fService1 = null;
+ fService2 = null;
+ fService3 = null;
+ fTracker.dispose();
+ fTracker = null;
+ DsfSession.endSession(fSession);
+ fSession = null;
+ fExecutor.shutdown();
+ }}).get();
+
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+ /**
+ * Test only the startup and shutdown sequences.
+ */
+ @Test public void startStopTest() {
+ }
+
+ /**
+ * Tests dispatching event 1. The goal of the test is to make sure that
+ * recipients are called in the correct order.
+ */
+ @Test public void event1Test() throws ExecutionException, InterruptedException {
+ fService1.dispatchEvent1();
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ Assert.assertTrue(1 == fService1.fEvent1RecipientNumber);
+ Assert.assertTrue(2 == fService2.fEvent1RecipientNumber);
+ Assert.assertTrue(3 == fService3.fEvent1RecipientNumber);
+ Assert.assertTrue(0 == fService1.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService2.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService3.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService1.fEvent3RecipientNumber);
+ Assert.assertTrue(0 == fService2.fEvent3RecipientNumber);
+ Assert.assertTrue(0 == fService3.fEvent3RecipientNumber);
+ }}).get();
+ }
+
+ /**
+ * Tests dispatching event 2. The goal of the test is to make sure that
+ * recipients are called in the correct order, and that the other events
+ * are not registered.
+ */
+ @Test public void event2Test() throws ExecutionException, InterruptedException {
+ fService1.dispatchEvent2();
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ Assert.assertTrue(0 == fService1.fEvent1RecipientNumber);
+ Assert.assertTrue(0 == fService2.fEvent1RecipientNumber);
+ Assert.assertTrue(0 == fService3.fEvent1RecipientNumber);
+ Assert.assertTrue(1 == fService1.fEvent2RecipientNumber);
+ Assert.assertTrue(2 == fService2.fEvent2RecipientNumber);
+ Assert.assertTrue(3 == fService3.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService1.fEvent3RecipientNumber);
+ Assert.assertTrue(0 == fService2.fEvent3RecipientNumber);
+ Assert.assertTrue(0 == fService3.fEvent3RecipientNumber);
+ }}).get();
+ }
+
+ /**
+ * Tests dispatching event 2. The goal of the test is to make sure that
+ * both event 2 and even 3 recipients are called for this event.
+ * <br>
+ * Note: When a single listener object has more than one method that that
+ * matches the event, both methods will be called. But there is currently
+ * no guaranteed order in which they should be called.
+ */
+ @Test public void event3Test() throws ExecutionException, InterruptedException {
+ fService1.dispatchEvent3();
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ Assert.assertTrue(1 == fService1.fEvent1RecipientNumber || 2 == fService1.fEvent1RecipientNumber);
+ Assert.assertTrue(3 == fService2.fEvent1RecipientNumber || 4 == fService2.fEvent1RecipientNumber);
+ Assert.assertTrue(5 == fService3.fEvent1RecipientNumber || 6 == fService3.fEvent1RecipientNumber);
+ Assert.assertTrue(0 == fService1.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService2.fEvent2RecipientNumber);
+ Assert.assertTrue(0 == fService3.fEvent2RecipientNumber);
+ Assert.assertTrue(1 == fService1.fEvent3RecipientNumber || 2 == fService1.fEvent3RecipientNumber);
+ Assert.assertTrue(3 == fService2.fEvent3RecipientNumber || 4 == fService2.fEvent3RecipientNumber);
+ Assert.assertTrue(5 == fService3.fEvent3RecipientNumber || 6 == fService3.fEvent3RecipientNumber);
+ }}).get();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service1.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service1.java
new file mode 100644
index 00000000000..89ab8c771b8
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service1.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+public class Service1 extends AbstractService {
+ Service1(DsfSession session) {
+ super(session);
+ }
+
+ @Override public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ register(new String[]{Service1.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override public void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service2.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service2.java
new file mode 100644
index 00000000000..bb70dc51186
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service2.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+public class Service2 extends AbstractService {
+ Service2(DsfSession session) {
+ super(session);
+ }
+
+ @Override public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ getServicesTracker().getService(Service1.class);
+ register(new String[]{Service2.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override public void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service3.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service3.java
new file mode 100644
index 00000000000..c16057e288c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/Service3.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.osgi.framework.BundleContext;
+
+public class Service3 extends AbstractService {
+ Service3(DsfSession session) {
+ super(session);
+ }
+
+ @Override protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ @Override public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ getServicesTracker().getService(Service1.class);
+ getServicesTracker().getService(Service2.class);
+ register(new String[]{Service3.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override public void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/ShutdownSequence.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/ShutdownSequence.java
new file mode 100644
index 00000000000..06f05dc329d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/ShutdownSequence.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+class ShutdownSequence extends Sequence {
+
+ DsfSession fSession;
+ DsfServicesTracker fTracker;
+
+ ShutdownSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ final Step[] fSteps = new Step[] {
+ new Step() {
+ @Override public void execute(RequestMonitor requestMonitor) {
+ fTracker = new DsfServicesTracker(DsfTestPlugin.getBundleContext(), fSession.getId());
+ requestMonitor.done();
+ }
+
+ @Override public void rollBack(RequestMonitor requestMonitor) {
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }
+ },
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ shutdownService(Service3.class, requestMonitor);
+ }},
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ shutdownService(Service2.class, requestMonitor);
+ }},
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ shutdownService(Service1.class, requestMonitor);
+ }},
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ fTracker.dispose();
+ fTracker = null;
+ requestMonitor.done();
+ }}
+ };
+
+ private void shutdownService(Class<? extends IDsfService> clazz, RequestMonitor requestMonitor) {
+ IDsfService service = fTracker.getService(clazz);
+ if (service != null) {
+ service.shutdown(requestMonitor);
+ }
+ else {
+ requestMonitor.setStatus(new Status(IStatus.ERROR, DsfTestPlugin.PLUGIN_ID, -1, "Service '" + clazz.getName() + "' not found.", null)); //$NON-NLS-1$//$NON-NLS-2$
+ requestMonitor.done();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/StartupSequence.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/StartupSequence.java
new file mode 100644
index 00000000000..408755c448b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/events/StartupSequence.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.events;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+class StartupSequence extends Sequence {
+ DsfSession fSession;
+
+ StartupSequence(DsfSession session) {
+ super(session.getExecutor());
+ fSession = session;
+ }
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ final Step[] fSteps = new Step[] {
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ new Service1(fSession).initialize(requestMonitor);
+ }},
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ new Service2(fSession).initialize(requestMonitor);
+ }},
+ new Step() { @Override public void execute(RequestMonitor requestMonitor) {
+ new Service3(fSession).initialize(requestMonitor);
+ }}
+ };
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/MultiInstanceTestService.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/MultiInstanceTestService.java
new file mode 100644
index 00000000000..283aae2e8ee
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/MultiInstanceTestService.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.service;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.osgi.framework.BundleContext;
+
+public class MultiInstanceTestService extends AbstractDsfService {
+
+ public static String PROP_INSTANCE_ID = "org.eclipse.cdt.dsf.tests.service.MultiInstanceTestService.id"; //$NON-NLS-1$
+ String fInstanceId;
+
+ public MultiInstanceTestService(DsfSession session, String instanceId) {
+ super(session);
+ fInstanceId = instanceId;
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ Hashtable<String,String> properties = new Hashtable<String,String>();
+ properties.put(PROP_INSTANCE_ID, fInstanceId);
+ register(new String[]{MultiInstanceTestService.class.getName()}, properties);
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/ServiceTests.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/ServiceTests.java
new file mode 100644
index 00000000000..9f6b830908b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/ServiceTests.java
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.service;
+
+import java.lang.reflect.Constructor;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Sequence;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.eclipse.cdt.tests.dsf.TestDsfExecutor;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+public class ServiceTests {
+ TestDsfExecutor fExecutor;
+
+ @Before public void startExecutor() throws ExecutionException, InterruptedException {
+ fExecutor = new TestDsfExecutor();
+ }
+
+ @After public void shutdownExecutor() throws ExecutionException, InterruptedException {
+ fExecutor.submit(new DsfRunnable() { public void run() {
+ fExecutor.shutdown();
+ }}).get();
+ if (fExecutor.exceptionsCaught()) {
+ Throwable[] exceptions = fExecutor.getExceptions();
+ throw new ExecutionException(exceptions[0]);
+ }
+ fExecutor = null;
+ }
+
+ private class CreateSessionStep extends Sequence.Step {
+ private DsfSession fSession;
+ @Override public void execute(RequestMonitor requestMonitor) {
+ fSession = DsfSession.startSession(fExecutor, "org.eclipse.cdt.dsf.tests"); //$NON-NLS-1$
+ requestMonitor.done();
+ }
+
+ DsfSession getSession() { return fSession; }
+ }
+
+ private class ShutdownSessionStep extends Sequence.Step {
+ private CreateSessionStep fCreateSessionStep;
+
+ ShutdownSessionStep(CreateSessionStep createSessionStep) {
+ fCreateSessionStep = createSessionStep;
+ }
+
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ DsfSession.endSession(fCreateSessionStep.getSession());
+ requestMonitor.done();
+ }
+ }
+
+ private class InitializeServiceStep extends Sequence.Step {
+ CreateSessionStep fCreateSessionStep;
+ Class<? extends IDsfService> fServiceClass;
+ IDsfService fService;
+
+ InitializeServiceStep(CreateSessionStep createSessionStep, Class<? extends IDsfService> serviceClass) {
+ fCreateSessionStep = createSessionStep;
+ fServiceClass = serviceClass;
+ }
+ IDsfService getService() { return fService; }
+
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ try {
+ Constructor<? extends IDsfService> c = fServiceClass.getConstructor(new Class[] {DsfSession.class});
+ fService = c.newInstance(new Object[] {fCreateSessionStep.getSession()});
+ } catch (Exception e) {
+ Assert.fail("Unexpected exception"); //$NON-NLS-1$
+ }
+ fService.initialize(requestMonitor);
+ }
+ }
+
+ private class InitializeMultiInstanceServiceStep extends InitializeServiceStep {
+ String fServiceId;
+
+ InitializeMultiInstanceServiceStep(CreateSessionStep createSessionStep, Class<? extends IDsfService> serviceClass, String serviceId) {
+ super(createSessionStep, serviceClass);
+ fServiceId = serviceId;
+ }
+ @Override
+ IDsfService getService() { return fService; }
+
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ try {
+ Constructor<? extends IDsfService> c =
+ fServiceClass.getConstructor(new Class[] {DsfSession.class, String.class});
+ fService = c.newInstance(new Object[] {fCreateSessionStep.getSession(), fServiceId});
+ } catch (Exception e) {
+ Assert.fail("Unexpected exception"); //$NON-NLS-1$
+ }
+ fService.initialize(requestMonitor);
+ }
+ }
+
+ private class ShutdownServiceStep extends Sequence.Step {
+ InitializeServiceStep fInitializeServiceStep;
+ ShutdownServiceStep(InitializeServiceStep initStep) {
+ fInitializeServiceStep = initStep;
+ }
+
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ fInitializeServiceStep.getService().shutdown(requestMonitor);
+ }
+ }
+
+
+ abstract private class TestRetrievingReferenceStep extends Sequence.Step {
+ String fClass;
+ boolean fShouldSucceed;
+
+ TestRetrievingReferenceStep(Class<?> clazz, boolean shouldSucceed) {
+ fClass = clazz.getName();
+ fShouldSucceed = shouldSucceed;
+ }
+
+ abstract String getFilter();
+
+ @Override
+ public void execute(RequestMonitor requestMonitor) {
+ ServiceReference[] refs = null;
+ try {
+ refs = DsfTestPlugin.getBundleContext().getServiceReferences(fClass, getFilter());
+ } catch (InvalidSyntaxException e) {
+ Assert.fail("Unexpected exception"); //$NON-NLS-1$
+ }
+ if (fShouldSucceed) {
+ Assert.assertTrue(refs != null);
+ Assert.assertTrue(refs.length == 1);
+ IDsfService service = (IDsfService)DsfTestPlugin.getBundleContext().getService(refs[0]);
+ Assert.assertTrue(service != null);
+ DsfTestPlugin.getBundleContext().ungetService(refs[0]);
+ } else {
+ Assert.assertTrue(refs == null);
+ }
+ requestMonitor.done();
+ }
+ }
+
+ private class TestRetrievingSimpleServiceReferenceStep extends TestRetrievingReferenceStep {
+ CreateSessionStep fCreateSessionStep;
+ TestRetrievingSimpleServiceReferenceStep(Class<?> clazz, boolean shouldSucceed, CreateSessionStep createSessionStep) {
+ super(clazz, shouldSucceed);
+ fCreateSessionStep = createSessionStep;
+ }
+ @Override
+ String getFilter() {
+ return "(" + IDsfService.PROP_SESSION_ID + "=" + fCreateSessionStep.getSession().getId() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ private class TestRetrievingMultiSessionServiceReferenceStep extends TestRetrievingSimpleServiceReferenceStep {
+ String fServiceId;
+ TestRetrievingMultiSessionServiceReferenceStep(Class<?> clazz, boolean shouldSucceed, CreateSessionStep createSessionStep,
+ String serviceId) {
+ super(clazz, shouldSucceed, createSessionStep);
+ fServiceId = serviceId;
+ }
+ @Override
+ String getFilter() {
+ return "(&" + //$NON-NLS-1$
+ "(" + IDsfService.PROP_SESSION_ID + "=" + fCreateSessionStep.getSession().getId() + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ "(" + MultiInstanceTestService.PROP_INSTANCE_ID + "=" + fServiceId + ")" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ ")"; //$NON-NLS-1$
+ }
+ }
+
+ @Test
+ public void singleServiceTest() throws InterruptedException, ExecutionException {
+ Sequence seq = new Sequence(fExecutor) {
+ CreateSessionStep fSessionStep;
+ InitializeServiceStep fServiceStep;
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ final private Step[] fSteps = new Step[]
+ {
+ fSessionStep = new CreateSessionStep(),
+ fServiceStep = new InitializeServiceStep(fSessionStep, SimpleTestService.class),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSessionStep),
+ new ShutdownServiceStep(fServiceStep),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSessionStep),
+ new ShutdownSessionStep(fSessionStep)
+ };
+ };
+ fExecutor.execute(seq);
+ seq.get();
+ }
+
+ /**
+ * Creates two sessions and starts a single service within each session.
+ * Then it tests retrieving the reference to the service.
+ */
+ @Test
+ public void singleServiceMultiSessionTest() throws InterruptedException, ExecutionException {
+ Sequence seq = new Sequence(fExecutor) {
+ CreateSessionStep fSession1Step;
+ CreateSessionStep fSession2Step;
+ InitializeServiceStep fSession1ServiceStep;
+ InitializeServiceStep fSession2ServiceStep;
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ final private Step[] fSteps = new Step[]
+ {
+ fSession1Step = new CreateSessionStep(),
+ fSession2Step = new CreateSessionStep(),
+ fSession1ServiceStep = new InitializeServiceStep(fSession1Step, SimpleTestService.class),
+ fSession2ServiceStep = new InitializeServiceStep(fSession2Step, SimpleTestService.class),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSession1Step),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, true, fSession2Step),
+ new ShutdownServiceStep(fSession1ServiceStep),
+ new ShutdownServiceStep(fSession2ServiceStep),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSession1Step),
+ new TestRetrievingSimpleServiceReferenceStep(SimpleTestService.class, false, fSession2Step),
+ new ShutdownSessionStep(fSession1Step),
+ new ShutdownSessionStep(fSession2Step)
+ };
+ };
+ fExecutor.execute(seq);
+ seq.get();
+ }
+
+ @Test
+ public void multiServiceServiceTest() throws InterruptedException, ExecutionException {
+ Sequence seq = new Sequence(fExecutor) {
+ CreateSessionStep fSessionStep;
+ InitializeServiceStep fService1Step;
+ InitializeServiceStep fService2Step;
+
+ @Override
+ public Step[] getSteps() { return fSteps; }
+
+ final private Step[] fSteps = new Step[]
+ {
+ fSessionStep = new CreateSessionStep(),
+ fService1Step = new InitializeMultiInstanceServiceStep(fSessionStep, MultiInstanceTestService.class, "1"), //$NON-NLS-1$
+ fService2Step = new InitializeMultiInstanceServiceStep(fSessionStep, MultiInstanceTestService.class, "2"), //$NON-NLS-1$
+ new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, true, fSessionStep, "1"), //$NON-NLS-1$
+ new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, true, fSessionStep, "2"), //$NON-NLS-1$
+ new ShutdownServiceStep(fService1Step),
+ new ShutdownServiceStep(fService2Step),
+ new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, false, fSessionStep, "1"), //$NON-NLS-1$
+ new TestRetrievingMultiSessionServiceReferenceStep(MultiInstanceTestService.class, false, fSessionStep, "2"), //$NON-NLS-1$
+ new ShutdownSessionStep(fSessionStep)
+ };
+ };
+ fExecutor.execute(seq);
+ seq.get();
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/SimpleTestService.java b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/SimpleTestService.java
new file mode 100644
index 00000000000..83737c13967
--- /dev/null
+++ b/dsf/org.eclipse.cdt.tests.dsf/src/org/eclipse/cdt/tests/dsf/service/SimpleTestService.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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.cdt.tests.dsf.service;
+
+import java.util.Hashtable;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.tests.dsf.DsfTestPlugin;
+import org.osgi.framework.BundleContext;
+
+public class SimpleTestService extends AbstractDsfService {
+
+ public SimpleTestService(DsfSession session) {
+ super(session);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfTestPlugin.getBundleContext();
+ }
+
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ public void handleSuccess() {
+ doInitialize(requestMonitor);
+ }
+ });
+ }
+
+ private void doInitialize(RequestMonitor requestMonitor) {
+ register(new String[]{SimpleTestService.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(RequestMonitor requestMonitor) {
+ unregister();
+ super.shutdown(requestMonitor);
+ }
+}

Back to the top