Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views')
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/PinTmfViewAction.java37
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfChartView.java118
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfView.java149
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TracingPerspectiveFactory.java79
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/AbstractCallStackAnalysis.java67
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEntry.java192
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEvent.java40
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java153
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java1569
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/FunctionNameMapper.java177
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSetting.java214
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsManager.java153
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsXML.java221
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorsView.java588
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/IColorSettingsListener.java30
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/BaseDistributionData.java243
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/IBaseDistributionModel.java35
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CopyHandler.java79
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CutHandler.java43
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/DeleteHandler.java75
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDialog.java81
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDragSourceAdapter.java70
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDropTargetAdapter.java124
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterEditUtils.java48
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterManager.java78
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeContentProvider.java71
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeLabelProvider.java126
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterView.java309
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterViewer.java1124
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/PasteHandler.java89
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/FullTraceHistogram.java224
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Histogram.java1045
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramBucket.java175
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramCurrentTimeControl.java130
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramDataModel.java717
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramRequest.java115
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramScaledData.java210
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionEndControl.java43
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionStartControl.java47
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTextControl.java280
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTimeRangeControl.java106
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramView.java887
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramZoom.java210
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramDataModel.java48
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramModelListener.java27
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Messages.java95
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/TimeRangeHistogram.java217
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/messages.properties21
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/Messages.java86
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemExplorer.java107
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemViewer.java463
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/messages.properties28
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/Messages.java41
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/TmfStatisticsView.java230
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/messages.properties13
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/Messages.java33
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/TmfSynchronizationView.java156
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/messages.properties13
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisEntry.java277
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisProvider.java108
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartDecorationProvider.java141
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartEvent.java375
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java754
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java1271
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/Messages.java38
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/messages.properties16
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DiagramToolTip.java131
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DrawableToolTip.java305
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ITimeCompressionListener.java42
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/NGC.java988
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDView.java1181
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidget.java2066
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidgetSelectionProvider.java88
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ScrollView.java2067
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/TimeCompressionBar.java1028
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessage.java469
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessageReturn.java112
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BaseMessage.java724
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicExecutionOccurrence.java275
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicFrame.java633
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/EllipsisMessage.java141
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ExecutionOccurrence.java267
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Frame.java1215
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/GraphNode.java906
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/HotSpot.java193
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ITimeRange.java46
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Lifeline.java534
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/LifelineCategories.java81
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Metrics.java332
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SDTimeEvent.java91
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Stop.java167
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessage.java296
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessageReturn.java112
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/Criteria.java415
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterCriteria.java273
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterListDialog.java518
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/MinMaxDialog.java190
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/PagesDialog.java204
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialog.java174
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialogUI.java1424
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SearchFilterDialog.java451
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/TabContents.java476
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IColor.java36
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IFont.java36
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IGC.java375
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IImage.java37
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ColorImpl.java92
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/FontImpl.java89
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ImageImpl.java105
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/BaseSDAction.java89
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ConfigureMinMax.java46
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/FirstPage.java68
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/KeyBindingsManager.java302
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/LastPage.java68
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDDown.java70
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDLeft.java72
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDRight.java73
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDUp.java71
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveToMessage.java113
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/NextPage.java68
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFiltersDialog.java75
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFindDialog.java93
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDPagesDialog.java80
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/PrevPage.java70
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Print.java60
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeEnd.java89
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeStart.java89
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Zoom.java239
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFilterProvider.java37
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFindProvider.java38
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDAdvancedPagingProvider.java51
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDCollapseProvider.java36
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDExtendedActionBarProvider.java37
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFilterProvider.java43
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFindProvider.java46
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDGraphNodeSupporter.java83
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPagingProvider.java61
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPropertiesProvider.java35
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/IUml2SDLoader.java46
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/LoadersManager.java397
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/Messages.java49
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfAsyncMessage.java68
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfSyncMessage.java68
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfUml2SDSyncLoader.java1485
-rw-r--r--org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/messages.properties22
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/ISDPreferences.java147
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewPref.java527
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewerPage.java431
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/Messages.java157
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncForBackward.java96
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncMessageComparator.java94
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortSyncMessageComparator.java61
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/TimeEventComparator.java53
-rwxr-xr-xorg.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/messages.properties132
154 files changed, 40649 insertions, 0 deletions
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/PinTmfViewAction.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/PinTmfViewAction.java
new file mode 100644
index 0000000000..4eb11629b7
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/PinTmfViewAction.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+
+/**
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ * @since 2.0
+ */
+public class PinTmfViewAction extends Action {
+ /**
+ * Creates a new <code>PinPropertySheetAction</code>.
+ */
+ public PinTmfViewAction() {
+ super(Messages.TmfView_PinActionNameText, IAction.AS_CHECK_BOX);
+
+ setId("org.eclipse.linuxtools.tmf.ui.views.PinTmfViewAction"); //$NON-NLS-1$
+ setToolTipText(Messages.TmfView_PinActionToolTipText);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PIN_VIEW));
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfChartView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfChartView.java
new file mode 100644
index 0000000000..99c692fb87
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfChartView.java
@@ -0,0 +1,118 @@
+/**********************************************************************
+ * Copyright (c) 2013, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer;
+
+/**
+ * Base class to be used with a chart viewer {@link TmfXYChartViewer}.
+ * It is responsible to instantiate the viewer class and load the trace
+ * into the viewer when the view is created.
+ *
+ * @author Bernd Hufmann
+ * @since 3.0
+ */
+abstract public class TmfChartView extends TmfView {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /** The TMF XY Chart reference */
+ private TmfXYChartViewer fChartViewer;
+ /** The Trace reference */
+ private ITmfTrace fTrace;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Standard Constructor
+ *
+ * @param viewName
+ * The view name
+ */
+ public TmfChartView(String viewName) {
+ super(viewName);
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+ /**
+ * Returns the TMF XY chart viewer implementation.
+ *
+ * @return the TMF XY chart viewer {@link TmfXYChartViewer}
+ */
+ protected TmfXYChartViewer getChartViewer() {
+ return fChartViewer;
+ }
+
+ /**
+ * Sets the TMF XY chart viewer implementation.
+ *
+ * @param chartViewer
+ * The TMF XY chart viewer {@link TmfXYChartViewer}
+ */
+ protected void setChartViewer(TmfXYChartViewer chartViewer) {
+ fChartViewer = chartViewer;
+ }
+
+ /**
+ * Returns the ITmfTrace implementation
+ *
+ * @return the ITmfTrace implementation {@link ITmfTrace}
+ */
+ protected ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Sets the ITmfTrace implementation
+ *
+ * @param trace
+ * The ITmfTrace implementation {@link ITmfTrace}
+ */
+ protected void setTrace(ITmfTrace trace) {
+ fTrace = trace;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+ @Override
+ public void createPartControl(Composite parent) {
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ setTrace(trace);
+ loadTrace();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (fChartViewer != null) {
+ fChartViewer.dispose();
+ }
+ }
+
+ /**
+ * Load the trace into view.
+ */
+ protected void loadTrace() {
+ if (fChartViewer != null) {
+ fChartViewer.loadTrace(fTrace);
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfView.java
new file mode 100644
index 0000000000..cc874e32f9
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TmfView.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Added possibility to pin view
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views;
+
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.tracecompass.tmf.core.component.ITmfComponent;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchActionConstants;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * Basic abstract TMF view class implementation.
+ *
+ * It registers any sub class to the signal manager for receiving and sending
+ * TMF signals.
+ *
+ * @version 1.2
+ * @author Francois Chouinard
+ */
+public abstract class TmfView extends ViewPart implements ITmfComponent {
+
+ private final String fName;
+
+ /**
+ * Action class for pinning of TmfView.
+ * @since 2.0
+ */
+ protected PinTmfViewAction fPinAction;
+
+ /**
+ * Reference to the trace manager
+ * @since 2.0
+ */
+ protected final TmfTraceManager fTraceManager;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor. Creates a TMF view and registers to the signal manager.
+ *
+ * @param viewName
+ * A view name
+ */
+ public TmfView(String viewName) {
+ super();
+ fName = viewName;
+ fTraceManager = TmfTraceManager.getInstance();
+ TmfSignalManager.register(this);
+ }
+
+ /**
+ * Disposes this view and de-registers itself from the signal manager
+ */
+ @Override
+ public void dispose() {
+ TmfSignalManager.deregister(this);
+ super.dispose();
+ }
+
+ // ------------------------------------------------------------------------
+ // ITmfComponent
+ // ------------------------------------------------------------------------
+
+ @Override
+ public String getName() {
+ return fName;
+ }
+
+ @Override
+ public void broadcast(TmfSignal signal) {
+ TmfSignalManager.dispatchSignal(signal);
+ }
+
+ /**
+ * @since 3.0
+ */
+ @Override
+ public void broadcastAsync(TmfSignal signal) {
+ TmfSignalManager.dispatchSignalAsync(signal);
+ }
+
+ // ------------------------------------------------------------------------
+ // View pinning support
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns whether the pin flag is set.
+ * For example, this flag can be used to ignore time synchronization signals from other TmfViews.
+ *
+ * @return pin flag
+ * @since 2.0
+ */
+ public boolean isPinned() {
+ return ((fPinAction != null) && (fPinAction.isChecked()));
+ }
+
+ /**
+ * Method adds a pin action to the TmfView. The pin action allows to toggle the <code>fIsPinned</code> flag.
+ * For example, this flag can be used to ignore time synchronization signals from other TmfViews.
+ *
+ * @since 2.0
+ */
+ protected void contributePinActionToToolBar() {
+ if (fPinAction == null) {
+ fPinAction = new PinTmfViewAction();
+
+ IToolBarManager toolBarManager = getViewSite().getActionBars()
+ .getToolBarManager();
+ toolBarManager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ toolBarManager.add(fPinAction);
+ }
+ }
+
+ /**
+ * Get the currently selected trace, or 'null' if the active editor is not a
+ * TMF trace.
+ *
+ * @return The active trace, or 'null' if not a trace
+ * @since 2.0
+ */
+ public ITmfTrace getActiveTrace() {
+ IEditorPart editor = getSite().getPage().getActiveEditor();
+ if (editor instanceof ITmfTraceEditor) {
+ ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
+ return trace;
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TracingPerspectiveFactory.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TracingPerspectiveFactory.java
new file mode 100644
index 0000000000..2cc89f70f5
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/TracingPerspectiveFactory.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views;
+
+import org.eclipse.tracecompass.tmf.ui.project.wizards.NewTmfProjectWizard;
+import org.eclipse.tracecompass.tmf.ui.views.histogram.HistogramView;
+import org.eclipse.tracecompass.tmf.ui.views.statistics.TmfStatisticsView;
+import org.eclipse.ui.IFolderLayout;
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+/**
+ * The tracing perspective definition.
+ *
+ * @version 1.0
+ * @author Francois Chouinard
+ */
+public class TracingPerspectiveFactory implements IPerspectiveFactory {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /** The Perspective ID */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.perspective"; //$NON-NLS-1$
+
+ // Standard TMF views
+ private static final String HISTOGRAM_VIEW_ID = HistogramView.ID;
+
+ // Standard Eclipse views
+ private static final String PROJECT_VIEW_ID = IPageLayout.ID_PROJECT_EXPLORER;
+ private static final String STATISTICS_VIEW_ID = TmfStatisticsView.ID;
+ private static final String PROPERTIES_VIEW_ID = IPageLayout.ID_PROP_SHEET;
+ private static final String BOOKMARKS_VIEW_ID = IPageLayout.ID_BOOKMARKS;
+
+
+ // ------------------------------------------------------------------------
+ // IPerspectiveFactory
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createInitialLayout(IPageLayout layout) {
+
+ // Editor area
+ layout.setEditorAreaVisible(true);
+
+ // Create the top left folder
+ IFolderLayout topLeftFolder = layout.createFolder(
+ "topLeftFolder", IPageLayout.LEFT, 0.15f, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
+ topLeftFolder.addView(PROJECT_VIEW_ID);
+
+ // Create the middle right folder
+ IFolderLayout middleRightFolder = layout.createFolder(
+ "middleRightFolder", IPageLayout.BOTTOM, 0.50f, IPageLayout.ID_EDITOR_AREA); //$NON-NLS-1$
+ middleRightFolder.addView(STATISTICS_VIEW_ID);
+
+ // Create the bottom right folder
+ IFolderLayout bottomRightFolder = layout.createFolder(
+ "bottomRightFolder", IPageLayout.BOTTOM, 0.55f, "middleRightFolder"); //$NON-NLS-1$ //$NON-NLS-2$
+ bottomRightFolder.addView(HISTOGRAM_VIEW_ID);
+ bottomRightFolder.addView(PROPERTIES_VIEW_ID);
+ bottomRightFolder.addView(BOOKMARKS_VIEW_ID);
+
+ // Populate menus, etc
+ layout.addPerspectiveShortcut(ID);
+ layout.addNewWizardShortcut(NewTmfProjectWizard.ID);
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/AbstractCallStackAnalysis.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/AbstractCallStackAnalysis.java
new file mode 100644
index 0000000000..7ccc51977d
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/AbstractCallStackAnalysis.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Montplaisir - Initial API and implementation
+ * Patrick Tasse - Add methods to get attribute paths
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import org.eclipse.tracecompass.tmf.core.callstack.CallStackStateProvider;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.tracecompass.tmf.ui.analysis.TmfAnalysisViewOutput;
+
+/**
+ * The base classes for analyses who want to populate the CallStack View.
+ *
+ * @author Alexandre Montplaisir
+ * @since 3.0
+ */
+public abstract class AbstractCallStackAnalysis extends TmfStateSystemAnalysisModule {
+
+ private static final String[] DEFAULT_THREADS_PATTERN =
+ new String[] { CallStackStateProvider.THREADS, "*" }; //$NON-NLS-1$;
+
+ private static final String[] DEFAULT_CALL_STACK_PATH =
+ new String[] { CallStackStateProvider.CALL_STACK };
+
+ /**
+ * Abstract constructor (should only be called via the sub-classes'
+ * constructors.
+ */
+ public AbstractCallStackAnalysis() {
+ super();
+ registerOutput(new TmfAnalysisViewOutput(CallStackView.ID));
+ }
+
+ /**
+ * Get the pattern of thread attributes. Override this method if the state
+ * system attributes do not match the default pattern defined by
+ * {@link CallStackStateProvider}.
+ *
+ * @return the absolute pattern of the thread attributes
+ * @since 3.1
+ */
+ public String[] getThreadsPattern() {
+ return DEFAULT_THREADS_PATTERN;
+ }
+
+ /**
+ * Get the call stack attribute path relative to a thread attribute found by
+ * {@link #getThreadsPattern()}. Override this method if the state system
+ * attributes do not match the default pattern defined by
+ * {@link CallStackStateProvider}.
+ *
+ * @return the relative path of the call stack attribute
+ * @since 3.1
+ */
+ public String[] getCallStackPath() {
+ return DEFAULT_CALL_STACK_PATH;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEntry.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEntry.java
new file mode 100644
index 0000000000..31c831527b
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEntry.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+
+/**
+ * An entry, or row, in the Call Stack view
+ *
+ * @author Patrick Tasse
+ * @since 2.0
+ */
+public class CallStackEntry extends TimeGraphEntry {
+
+ private final int fQuark;
+ private final int fStackLevel;
+ private final ITmfTrace fTrace;
+ private String fFunctionName;
+ private long fFunctionEntryTime;
+ private long fFunctionExitTime;
+ private @NonNull ITmfStateSystem fSS;
+
+ /**
+ * Standard constructor
+ *
+ * @param quark
+ * The call stack quark
+ * @param stackLevel
+ * The stack level
+ * @param trace
+ * The trace that this view is talking about
+ * @deprecated Use {@link #CallStackEntry(String, int, int, ITmfTrace, ITmfStateSystem)}
+ */
+ @Deprecated
+ public CallStackEntry(int quark, int stackLevel, ITmfTrace trace) {
+ super(null, 0, 0);
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Standard constructor
+ *
+ * @param name
+ * The parent thread name
+ * @param quark
+ * The call stack quark
+ * @param stackLevel
+ * The stack level
+ * @param trace
+ * The trace that this view is talking about
+ * @param ss
+ * The call stack state system
+ * @since 3.1
+ */
+ public CallStackEntry(String name, int quark, int stackLevel, ITmfTrace trace, @NonNull ITmfStateSystem ss) {
+ super(name, 0, 0);
+ fQuark = quark;
+ fStackLevel = stackLevel;
+ fTrace = trace;
+ fFunctionName = ""; //$NON-NLS-1$
+ fSS = ss;
+ }
+
+ /**
+ * Get the function name of the call stack entry
+ * @return the function name
+ */
+ public String getFunctionName() {
+ return fFunctionName;
+ }
+
+ /**
+ * Set the function name of the call stack entry
+ * @param functionName the function name
+ */
+ public void setFunctionName(String functionName) {
+ fFunctionName = functionName;
+ }
+
+ /**
+ * Set the start time of the call stack entry
+ * @param startTime the start time
+ * @deprecated Use {@link #setFunctionEntryTime(long)}
+ */
+ @Deprecated
+ public void setStartTime(long startTime) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Set the end time of the call stack entry
+ * @param endTime the end time
+ * @deprecated Use {@link #setFunctionExitTime(long)}
+ */
+ @Deprecated
+ public void setEndTime(long endTime) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Set the selected function entry time
+ *
+ * @param entryTime
+ * the function entry time
+ * @since 3.1
+ */
+ public void setFunctionEntryTime(long entryTime) {
+ fFunctionEntryTime = entryTime;
+ }
+
+ /**
+ * Get the selected function entry time
+ *
+ * @return the function entry time
+ * @since 3.1
+ */
+ public long getFunctionEntryTime() {
+ return fFunctionEntryTime;
+ }
+
+ /**
+ * Set the selected function exit time
+ *
+ * @param exitTime
+ * the function exit time
+ * @since 3.1
+ */
+ public void setFunctionExitTime(long exitTime) {
+ fFunctionExitTime = exitTime;
+ }
+
+ /**
+ * Get the selected function exit time
+ *
+ * @return the function exit time
+ * @since 3.1
+ */
+ public long getFunctionExitTime() {
+ return fFunctionExitTime;
+ }
+
+ /**
+ * Retrieve the attribute quark that's represented by this entry.
+ *
+ * @return The integer quark
+ */
+ public int getQuark() {
+ return fQuark;
+ }
+
+ /**
+ * Retrieve the stack level associated with this entry.
+ *
+ * @return The stack level or 0
+ */
+ public int getStackLevel() {
+ return fStackLevel;
+ }
+
+ /**
+ * Retrieve the trace that is associated to this view.
+ *
+ * @return The trace
+ */
+ public ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Retrieve the call stack state system associated with this entry.
+ *
+ * @return The call stack state system
+ * @since 3.1
+ */
+ public @NonNull ITmfStateSystem getStateSystem() {
+ return fSS;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEvent.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEvent.java
new file mode 100644
index 0000000000..05fc4ae20f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackEvent.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
+
+/**
+ * Time Event implementation specific to the Call Stack View
+ *
+ * @author Patrick Tasse
+ * @since 2.0
+ */
+public class CallStackEvent extends TimeEvent {
+
+ /**
+ * Standard constructor
+ *
+ * @param entry
+ * The entry that this event affects
+ * @param time
+ * The start time of the event
+ * @param duration
+ * The duration of the event
+ * @param value
+ * The event value (1-256)
+ */
+ public CallStackEvent(CallStackEntry entry, long time, long duration, int value) {
+ super(entry, time, duration, value);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java
new file mode 100644
index 0000000000..e23e399652
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackPresentationProvider.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils;
+
+/**
+ * Presentation provider for the Call Stack view, based on the generic TMF
+ * presentation provider.
+ *
+ * @author Patrick Tasse
+ * @since 2.0
+ */
+public class CallStackPresentationProvider extends TimeGraphPresentationProvider {
+
+ /** Number of colors used for call stack events */
+ public static final int NUM_COLORS = 360;
+
+ private final CallStackView fView;
+
+ private Integer fAverageCharWidth;
+
+ private enum State {
+ MULTIPLE (new RGB(100, 100, 100)),
+ EXEC (new RGB(0, 200, 0));
+
+ private final RGB rgb;
+
+ private State (RGB rgb) {
+ this.rgb = rgb;
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view
+ * The callstack view that will contain the time events
+ * @since 3.0
+ */
+ public CallStackPresentationProvider(CallStackView view) {
+ fView = view;
+ }
+
+ @Override
+ public String getStateTypeName(ITimeGraphEntry entry) {
+ return Messages.CallStackPresentationProvider_Thread;
+ }
+
+ @Override
+ public StateItem[] getStateTable() {
+ final float saturation = 0.6f;
+ final float brightness = 0.6f;
+ StateItem[] stateTable = new StateItem[NUM_COLORS + 1];
+ stateTable[0] = new StateItem(State.MULTIPLE.rgb, State.MULTIPLE.toString());
+ for (int i = 0; i < NUM_COLORS; i++) {
+ RGB rgb = new RGB(i, saturation, brightness);
+ stateTable[i + 1] = new StateItem(rgb, State.EXEC.toString());
+ }
+ return stateTable;
+ }
+
+ @Override
+ public int getStateTableIndex(ITimeEvent event) {
+ if (event instanceof CallStackEvent) {
+ CallStackEvent callStackEvent = (CallStackEvent) event;
+ return callStackEvent.getValue() + 1;
+ } else if (event instanceof NullTimeEvent) {
+ return INVISIBLE;
+ }
+ return State.MULTIPLE.ordinal();
+ }
+
+ @Override
+ public String getEventName(ITimeEvent event) {
+ if (event instanceof CallStackEvent) {
+ CallStackEntry entry = (CallStackEntry) event.getEntry();
+ ITmfStateSystem ss = entry.getStateSystem();
+ try {
+ ITmfStateValue value = ss.querySingleState(event.getTime(), entry.getQuark()).getStateValue();
+ if (!value.isNull()) {
+ String address = value.toString();
+ return fView.getFunctionName(address);
+ }
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (TimeRangeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ return null;
+ }
+ return State.MULTIPLE.toString();
+ }
+
+ @Override
+ public void postDrawEvent(ITimeEvent event, Rectangle bounds, GC gc) {
+ if (fAverageCharWidth == null) {
+ fAverageCharWidth = gc.getFontMetrics().getAverageCharWidth();
+ }
+ if (bounds.width <= fAverageCharWidth) {
+ return;
+ }
+ if (!(event instanceof CallStackEvent)) {
+ return;
+ }
+ CallStackEntry entry = (CallStackEntry) event.getEntry();
+ ITmfStateSystem ss = entry.getStateSystem();
+ try {
+ ITmfStateValue value = ss.querySingleState(event.getTime(), entry.getQuark()).getStateValue();
+ if (!value.isNull()) {
+ String address = value.toString();
+ String name = fView.getFunctionName(address);
+ gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
+ Utils.drawText(gc, name, bounds.x, bounds.y - 2, bounds.width, true, true);
+ }
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (TimeRangeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java
new file mode 100644
index 0000000000..58be6c2a22
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/CallStackView.java
@@ -0,0 +1,1569 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated signal handling
+ * Marc-Andre Laperle - Map from binary file
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+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.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.IDialogSettings;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue.Type;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.NullTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphControl;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphSelection;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorPart;
+
+/**
+ * Main implementation for the Call Stack view
+ *
+ * @author Patrick Tasse
+ * @since 2.0
+ */
+public class CallStackView extends TmfView {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /** View ID. */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.callstack"; //$NON-NLS-1$
+
+ /**
+ * Redraw state enum
+ */
+ private enum State {
+ IDLE, BUSY, PENDING
+ }
+
+ private static final String[] COLUMN_TIMES = new String[] {
+ Messages.CallStackView_FunctionColumn,
+ Messages.CallStackView_DepthColumn,
+ Messages.CallStackView_EntryTimeColumn,
+ Messages.CallStackView_ExitTimeColumn,
+ Messages.CallStackView_DurationColumn
+ };
+
+ private static final int[] COLUMN_WIDTHS = new int[] {
+ 200,
+ 50,
+ 120,
+ 120,
+ 120
+ };
+
+ /** Timeout between updates in the build thread in ms */
+ private static final long BUILD_UPDATE_TIMEOUT = 500;
+
+ // Fraction of a function duration to be added as spacing
+ private static final double SPACING_RATIO = 0.01;
+
+ private static final Image THREAD_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/thread_obj.gif"); //$NON-NLS-1$
+ private static final Image STACKFRAME_IMAGE = Activator.getDefault().getImageFromPath("icons/obj16/stckframe_obj.gif"); //$NON-NLS-1$
+
+ private static final String IMPORT_MAPPING_ICON_PATH = "icons/etool16/import.gif"; //$NON-NLS-1$
+ private static final String IMPORT_BINARY_ICON_PATH = "icons/obj16/binaries_obj.gif"; //$NON-NLS-1$
+
+ private static final ImageDescriptor SORT_BY_NAME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha.gif"); //$NON-NLS-1$
+ private static final ImageDescriptor SORT_BY_NAME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_alpha_rev.gif"); //$NON-NLS-1$
+ private static final ImageDescriptor SORT_BY_ID_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num.gif"); //$NON-NLS-1$
+ private static final ImageDescriptor SORT_BY_ID_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_num_rev.gif"); //$NON-NLS-1$
+ private static final ImageDescriptor SORT_BY_TIME_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time.gif"); //$NON-NLS-1$
+ private static final ImageDescriptor SORT_BY_TIME_REV_ICON = Activator.getDefault().getImageDescripterFromPath("icons/etool16/sort_time_rev.gif"); //$NON-NLS-1$
+ private static final String SORT_OPTION_KEY = "sort.option"; //$NON-NLS-1$
+
+ private enum SortOption {
+ BY_NAME, BY_NAME_REV, BY_ID, BY_ID_REV, BY_TIME, BY_TIME_REV
+ }
+
+ private SortOption fSortOption;
+ private Comparator<ITimeGraphEntry> fThreadComparator = null;
+ private Action fSortByNameAction;
+ private Action fSortByIdAction;
+ private Action fSortByTimeAction;
+
+ // ------------------------------------------------------------------------
+ // Fields
+ // ------------------------------------------------------------------------
+
+ // The time graph combo
+ private TimeGraphCombo fTimeGraphCombo;
+
+ // The selected trace
+ private ITmfTrace fTrace;
+
+ // The selected thread map
+ private final Map<ITmfTrace, String> fSelectedThreadMap = new HashMap<>();
+
+ // The time graph entry list
+ private List<TraceEntry> fEntryList;
+
+ // The trace to entry list hash map
+ private final Map<ITmfTrace, List<TraceEntry>> fEntryListMap = new HashMap<>();
+
+ // The trace to build thread hash map
+ private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
+
+ /** The map to map function addresses to function names */
+ private Map<String, String> fNameMapping;
+
+ // The start time
+ private long fStartTime;
+
+ // The end time
+ private long fEndTime;
+
+ // The display width
+ private int fDisplayWidth;
+
+ // The next event action
+ private Action fNextEventAction;
+
+ // The previous event action
+ private Action fPrevEventAction;
+
+ // The next item action
+ private Action fNextItemAction;
+
+ // The previous item action
+ private Action fPreviousItemAction;
+
+ // The action to import a function-name mapping file
+ private Action fImportMappingAction;
+
+ // The action to import a binary file mapping */
+ private Action fImportBinaryFileMappingAction;
+
+ // The zoom thread
+ private ZoomThread fZoomThread;
+
+ // The redraw state used to prevent unnecessary queuing of display runnables
+ private State fRedrawState = State.IDLE;
+
+ // The redraw synchronization object
+ private final Object fSyncObj = new Object();
+
+ // The saved time sync. signal used when switching off the pinning of a view
+ private TmfTimeSynchSignal fSavedTimeSyncSignal;
+
+ // The saved time range sync. signal used when switching off the pinning of
+ // a view
+ private TmfRangeSynchSignal fSavedRangeSyncSignal;
+
+ // ------------------------------------------------------------------------
+ // Classes
+ // ------------------------------------------------------------------------
+
+ private class TraceEntry extends TimeGraphEntry {
+ public TraceEntry(String name, long startTime, long endTime) {
+ super(name, startTime, endTime);
+ }
+
+ @Override
+ public boolean hasTimeEvents() {
+ return false;
+ }
+ }
+
+ private class ThreadEntry extends TimeGraphEntry {
+ // The call stack quark
+ private final int fCallStackQuark;
+ // The state system from which this entry comes
+ private final ITmfStateSystem fSS;
+ // The thread id
+ private final long fThreadId;
+
+ public ThreadEntry(ITmfStateSystem ss, String name, long threadId, int callStackQuark, long startTime, long endTime) {
+ super(name, startTime, endTime);
+ fCallStackQuark = callStackQuark;
+ fThreadId = threadId;
+ fSS = ss;
+ }
+
+ @Override
+ public boolean hasTimeEvents() {
+ return false;
+ }
+
+ public int getCallStackQuark() {
+ return fCallStackQuark;
+ }
+
+ public long getThreadId() {
+ return fThreadId;
+ }
+
+ @Nullable
+ public ITmfStateSystem getStateSystem() {
+ return fSS;
+ }
+ }
+
+ private class ThreadNameComparator implements Comparator<ITimeGraphEntry> {
+ private boolean reverse;
+
+ public ThreadNameComparator(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ @Override
+ public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
+ return reverse ? o2.getName().compareTo(o1.getName()) :
+ o1.getName().compareTo(o2.getName());
+ }
+ }
+
+ private class ThreadIdComparator implements Comparator<ITimeGraphEntry> {
+ private boolean reverse;
+
+ public ThreadIdComparator(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ @Override
+ public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
+ ThreadEntry t1 = (ThreadEntry) o1;
+ ThreadEntry t2 = (ThreadEntry) o2;
+ return reverse ? Long.compare(t2.getThreadId(), t1.getThreadId()) :
+ Long.compare(t1.getThreadId(), t2.getThreadId());
+ }
+ }
+
+ private class ThreadTimeComparator implements Comparator<ITimeGraphEntry> {
+ private boolean reverse;
+
+ public ThreadTimeComparator(boolean reverse) {
+ this.reverse = reverse;
+ }
+
+ @Override
+ public int compare(ITimeGraphEntry o1, ITimeGraphEntry o2) {
+ return reverse ? Long.compare(o2.getStartTime(), o1.getStartTime()) :
+ Long.compare(o1.getStartTime(), o2.getStartTime());
+ }
+ }
+
+ private class TreeContentProvider implements ITreeContentProvider {
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement != null) {
+ try {
+ return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]);
+ } catch (ClassCastException e) {
+ }
+ }
+ return new ITimeGraphEntry[0];
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;
+ return entry.getChildren().toArray();
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) element;
+ return entry.getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) element;
+ return entry.hasChildren();
+ }
+
+ }
+
+ private class TreeLabelProvider implements ITableLabelProvider {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (columnIndex == 0) {
+ if (element instanceof ThreadEntry) {
+ return THREAD_IMAGE;
+ } else if (element instanceof CallStackEntry) {
+ CallStackEntry entry = (CallStackEntry) element;
+ if (entry.getFunctionName().length() > 0) {
+ return STACKFRAME_IMAGE;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof CallStackEntry) {
+ CallStackEntry entry = (CallStackEntry) element;
+ if (columnIndex == 0) {
+ return entry.getFunctionName();
+ } else if (columnIndex == 1 && entry.getFunctionName().length() > 0) {
+ int depth = entry.getStackLevel();
+ return Integer.toString(depth);
+ } else if (columnIndex == 2 && entry.getFunctionName().length() > 0) {
+ ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ return ts.toString();
+ } else if (columnIndex == 3 && entry.getFunctionName().length() > 0) {
+ ITmfTimestamp ts = new TmfTimestamp(entry.getFunctionExitTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ return ts.toString();
+ } else if (columnIndex == 4 && entry.getFunctionName().length() > 0) {
+ ITmfTimestamp ts = new TmfTimestampDelta(entry.getFunctionExitTime() - entry.getFunctionEntryTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ return ts.toString();
+ }
+ } else if (element instanceof ITimeGraphEntry) {
+ if (columnIndex == 0) {
+ return ((ITimeGraphEntry) element).getName();
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ }
+
+ private class TimeGraphContentProvider implements ITimeGraphContentProvider {
+
+ @Override
+ public ITimeGraphEntry[] getElements(Object inputElement) {
+ if (inputElement != null) {
+ try {
+ return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]);
+ } catch (ClassCastException e) {
+ }
+ }
+ return new ITimeGraphEntry[0];
+ }
+
+ }
+
+ private class BuildThread extends Thread {
+ private final ITmfTrace fBuildTrace;
+ private final ITmfTrace fParentTrace;
+ private final IProgressMonitor fMonitor;
+
+ public BuildThread(ITmfTrace trace, ITmfTrace parentTrace) {
+ super("CallStackView build"); //$NON-NLS-1$
+ fBuildTrace = trace;
+ fParentTrace = parentTrace;
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ buildThreadList(fBuildTrace, fParentTrace, fMonitor);
+ synchronized (fBuildThreadMap) {
+ fBuildThreadMap.remove(fBuildTrace);
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ private class ZoomThread extends Thread {
+ private final List<TraceEntry> fZoomEntryList;
+ private final long fZoomStartTime;
+ private final long fZoomEndTime;
+ private final IProgressMonitor fMonitor;
+
+ public ZoomThread(List<TraceEntry> entryList, long startTime, long endTime) {
+ super("CallStackView zoom"); //$NON-NLS-1$
+ fZoomEntryList = entryList;
+ fZoomStartTime = startTime;
+ fZoomEndTime = endTime;
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ if (fZoomEntryList == null) {
+ return;
+ }
+ long resolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
+ for (TraceEntry traceEntry : fZoomEntryList) {
+ for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
+ ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
+ if (ss == null) {
+ continue;
+ }
+ ss.waitUntilBuilt();
+ if (ss.isCancelled()) {
+ continue;
+ }
+ for (ITimeGraphEntry child : threadEntry.getChildren()) {
+ if (fMonitor.isCanceled()) {
+ break;
+ }
+ CallStackEntry entry = (CallStackEntry) child;
+ if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
+ entry.setZoomedEventList(null);
+ } else {
+ List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, resolution, fMonitor);
+ if (zoomedEventList != null) {
+ entry.setZoomedEventList(zoomedEventList);
+ }
+ }
+ redraw();
+ }
+ }
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public CallStackView() {
+ super(ID);
+ fDisplayWidth = Display.getDefault().getBounds().width;
+ }
+
+ // ------------------------------------------------------------------------
+ // ViewPart
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite parent) {
+ fTimeGraphCombo = new TimeGraphCombo(parent, SWT.NONE);
+
+ fTimeGraphCombo.setTreeContentProvider(new TreeContentProvider());
+
+ fTimeGraphCombo.setTreeLabelProvider(new TreeLabelProvider());
+
+ fTimeGraphCombo.setTreeColumns(COLUMN_TIMES);
+
+ fTimeGraphCombo.getTreeViewer().getTree().getColumn(0).setWidth(COLUMN_WIDTHS[0]);
+ fTimeGraphCombo.getTreeViewer().getTree().getColumn(1).setWidth(COLUMN_WIDTHS[1]);
+ fTimeGraphCombo.getTreeViewer().getTree().getColumn(2).setWidth(COLUMN_WIDTHS[2]);
+ fTimeGraphCombo.getTreeViewer().getTree().getColumn(3).setWidth(COLUMN_WIDTHS[3]);
+ fTimeGraphCombo.getTreeViewer().getTree().getColumn(4).setWidth(COLUMN_WIDTHS[4]);
+
+ fTimeGraphCombo.setTimeGraphContentProvider(new TimeGraphContentProvider());
+ fTimeGraphCombo.setTimeGraphProvider(new CallStackPresentationProvider(this));
+ fTimeGraphCombo.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
+
+ fTimeGraphCombo.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
+ @Override
+ public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
+ long startTime = event.getStartTime();
+ long endTime = event.getEndTime();
+ TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
+ broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
+ startZoomThread(startTime, endTime);
+ }
+ });
+
+ fTimeGraphCombo.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
+ @Override
+ public void timeSelected(TimeGraphTimeEvent event) {
+ long beginTime = event.getBeginTime();
+ long endTime = event.getEndTime();
+ synchingToTime(beginTime);
+ broadcast(new TmfTimeSynchSignal(CallStackView.this, new TmfNanoTimestamp(beginTime), new TmfNanoTimestamp(endTime)));
+ }
+ });
+
+ fTimeGraphCombo.getTimeGraphViewer().getControl().addControlListener(new ControlAdapter() {
+ @Override
+ public void controlResized(ControlEvent e) {
+ fDisplayWidth = fTimeGraphCombo.getTimeGraphViewer().getControl().getSize().x;
+ if (fEntryList != null) {
+ startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
+ }
+ }
+ });
+
+ fTimeGraphCombo.getTreeViewer().addDoubleClickListener(new IDoubleClickListener() {
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ Object selection = ((IStructuredSelection) event.getSelection()).getFirstElement();
+ if (selection instanceof CallStackEntry) {
+ CallStackEntry entry = (CallStackEntry) selection;
+ if (entry.getFunctionName().length() > 0) {
+ long entryTime = entry.getFunctionEntryTime();
+ long exitTime = entry.getFunctionExitTime();
+ long spacingTime = (long) ((exitTime - entryTime) * SPACING_RATIO);
+ entryTime -= spacingTime;
+ exitTime += spacingTime;
+ TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(entryTime), new TmfNanoTimestamp(exitTime));
+ broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
+ fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(entryTime, exitTime);
+ startZoomThread(entryTime, exitTime);
+ }
+ }
+ }
+ });
+
+ fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ TimeGraphControl timeGraphControl = fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl();
+ ISelection selection = timeGraphControl.getSelection();
+ if (selection instanceof TimeGraphSelection) {
+ Object o = ((TimeGraphSelection) selection).getFirstElement();
+ if (o instanceof CallStackEvent) {
+ CallStackEvent event = (CallStackEvent) o;
+ long startTime = event.getTime();
+ long endTime = startTime + event.getDuration();
+ long spacingTime = (long) ((endTime - startTime) * SPACING_RATIO);
+ startTime -= spacingTime;
+ endTime += spacingTime;
+ TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
+ broadcast(new TmfRangeSynchSignal(CallStackView.this, range));
+ fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+ startZoomThread(startTime, endTime);
+ }
+ }
+ }
+ });
+
+ IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
+ fTimeGraphCombo.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
+
+ // View Action Handling
+ makeActions();
+ contributeToActionBars();
+ createContextMenu();
+ loadSortOption();
+
+ IEditorPart editor = getSite().getPage().getActiveEditor();
+ if (editor instanceof ITmfTraceEditor) {
+ ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ fTimeGraphCombo.setFocus();
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+ /**
+ * Handler for the trace opened signal.
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+
+ /**
+ * Handler for the trace selected signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void traceSelected(final TmfTraceSelectedSignal signal) {
+ if (signal.getTrace() == fTrace) {
+ return;
+ }
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+
+ /**
+ * Trace is closed: clear the data structures and the view
+ *
+ * @param signal
+ * the signal received
+ */
+ @TmfSignalHandler
+ public void traceClosed(final TmfTraceClosedSignal signal) {
+ synchronized (fBuildThreadMap) {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(signal.getTrace());
+ for (ITmfTrace trace : traces) {
+ BuildThread buildThread = fBuildThreadMap.remove(trace);
+ if (buildThread != null) {
+ buildThread.cancel();
+ }
+ }
+ }
+ synchronized (fEntryListMap) {
+ fEntryListMap.remove(signal.getTrace());
+ }
+ fSelectedThreadMap.remove(signal.getTrace());
+ if (signal.getTrace() == fTrace) {
+ fTrace = null;
+ fStartTime = 0;
+ fEndTime = 0;
+ refresh();
+ }
+ }
+
+ /**
+ * Handler for the TimeSynch signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void synchToTime(final TmfTimeSynchSignal signal) {
+
+ fSavedTimeSyncSignal = isPinned() ? new TmfTimeSynchSignal(signal.getSource(), signal.getBeginTime(), signal.getEndTime()) : null;
+
+ if (signal.getSource() == this || fTrace == null || isPinned()) {
+ return;
+ }
+ final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ if (beginTime == endTime) {
+ fTimeGraphCombo.getTimeGraphViewer().setSelectedTime(beginTime, true);
+ } else {
+ fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
+ }
+ synchingToTime(beginTime);
+ startZoomThread(fTimeGraphCombo.getTimeGraphViewer().getTime0(), fTimeGraphCombo.getTimeGraphViewer().getTime1());
+ if (fEntryList == null) {
+ return;
+ }
+ TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
+ for (TraceEntry traceEntry : fEntryList) {
+ for (ITimeGraphEntry child : traceEntry.getChildren()) {
+ ThreadEntry threadEntry = (ThreadEntry) child;
+ ITmfStateSystem ss = threadEntry.getStateSystem();
+ if (ss == null || beginTime < ss.getStartTime() || beginTime > ss.getCurrentEndTime()) {
+ continue;
+ }
+ try {
+ int quark = threadEntry.getCallStackQuark();
+ ITmfStateInterval stackInterval = ss.querySingleState(beginTime, quark);
+ if (beginTime == stackInterval.getStartTime()) {
+ int stackLevel = stackInterval.getStateValue().unboxInt();
+ ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
+ fTimeGraphCombo.setSelection(selectedEntry);
+ viewer.getTimeGraphControl().fireSelectionChanged();
+ break;
+ }
+ } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Handler for the RangeSynch signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void synchToRange(final TmfRangeSynchSignal signal) {
+
+ if (isPinned()) {
+ fSavedRangeSyncSignal =
+ new TmfRangeSynchSignal(signal.getSource(), new TmfTimeRange(signal.getCurrentRange().getStartTime(), signal.getCurrentRange().getEndTime()));
+
+ fSavedTimeSyncSignal = null;
+ }
+
+ if (signal.getSource() == this || fTrace == null || isPinned()) {
+ return;
+ }
+ if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
+ return;
+ }
+ final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+ startZoomThread(startTime, endTime);
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Internal
+ // ------------------------------------------------------------------------
+
+ private void loadTrace() {
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ fStartTime = Long.MAX_VALUE;
+ fEndTime = Long.MIN_VALUE;
+ synchronized (fBuildThreadMap) {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ for (ITmfTrace trace : traces) {
+ BuildThread buildThread = new BuildThread(trace, fTrace);
+ fBuildThreadMap.put(trace, buildThread);
+ buildThread.start();
+ }
+ }
+ } else {
+ fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ refresh();
+ }
+ }
+ }
+
+ private void buildThreadList(final ITmfTrace trace, final ITmfTrace parentTrace, IProgressMonitor monitor) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ AbstractCallStackAnalysis module = getCallStackModule(trace);
+ if (module == null) {
+ addUnavailableEntry(trace, parentTrace);
+ return;
+ }
+ ITmfStateSystem ss = module.getStateSystem();
+ if (ss == null) {
+ addUnavailableEntry(trace, parentTrace);
+ return;
+ }
+
+ Map<ITmfTrace, TraceEntry> traceEntryMap = new HashMap<>();
+ Map<Integer, ThreadEntry> threadEntryMap = new HashMap<>();
+ String[] threadPaths = module.getThreadsPattern();
+
+ long start = ss.getStartTime();
+
+ boolean complete = false;
+ while (!complete) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ complete = ss.waitUntilBuilt(BUILD_UPDATE_TIMEOUT);
+ if (ss.isCancelled()) {
+ return;
+ }
+ long end = ss.getCurrentEndTime();
+ if (start == end && !complete) { // when complete execute one last time regardless of end time
+ continue;
+ }
+ List<Integer> threadQuarks = ss.getQuarks(threadPaths);
+ TraceEntry traceEntry = traceEntryMap.get(trace);
+ if (traceEntry == null) {
+ traceEntry = new TraceEntry(trace.getName(), start, end + 1);
+ traceEntryMap.put(trace, traceEntry);
+ traceEntry.sortChildren(fThreadComparator);
+ addToEntryList(parentTrace, Collections.singletonList(traceEntry));
+ } else {
+ traceEntry.updateEndTime(end);
+ }
+ for (int i = 0; i < threadQuarks.size(); i++) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ int threadQuark = threadQuarks.get(i);
+ try {
+ String[] callStackPath = module.getCallStackPath();
+ int callStackQuark = ss.getQuarkRelative(threadQuark, callStackPath);
+ String threadName = ss.getAttributeName(threadQuark);
+ long threadEnd = end + 1;
+ ITmfStateInterval endInterval = ss.querySingleState(ss.getCurrentEndTime(), callStackQuark);
+ if (endInterval.getStateValue().isNull() && endInterval.getStartTime() != ss.getStartTime()) {
+ threadEnd = endInterval.getStartTime();
+ }
+ ThreadEntry threadEntry = threadEntryMap.get(threadQuark);
+ if (threadEntry == null) {
+ long threadId = ss.querySingleState(ss.getCurrentEndTime(), threadQuark).getStateValue().unboxLong();
+ long threadStart = start;
+ ITmfStateInterval startInterval = ss.querySingleState(start, callStackQuark);
+ if (startInterval.getStateValue().isNull()) {
+ threadStart = Math.min(startInterval.getEndTime() + 1, end + 1);
+ }
+ threadEntry = new ThreadEntry(ss, threadName, threadId, callStackQuark, threadStart, threadEnd);
+ threadEntryMap.put(threadQuark, threadEntry);
+ traceEntry.addChild(threadEntry);
+ } else {
+ threadEntry.updateEndTime(threadEnd);
+ }
+ int level = 1;
+ for (int stackLevelQuark : ss.getSubAttributes(callStackQuark, false)) {
+ if (level > threadEntry.getChildren().size()) {
+ CallStackEntry callStackEntry = new CallStackEntry(threadName, stackLevelQuark, level, trace, ss);
+ threadEntry.addChild(callStackEntry);
+ }
+ level++;
+ }
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+ if (parentTrace == fTrace) {
+ synchronized (fEntryListMap) {
+ fStartTime = Math.min(fStartTime, start);
+ fEndTime = Math.max(fEndTime, end + 1);
+ }
+ refresh();
+ }
+ for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
+ for (ITimeGraphEntry callStackEntry : threadEntry.getChildren()) {
+ if (monitor.isCanceled()) {
+ return;
+ }
+ buildStatusEvents(parentTrace, (CallStackEntry) callStackEntry, monitor, start, end);
+ }
+ }
+ start = end;
+ }
+ }
+
+ private void addToEntryList(ITmfTrace trace, List<TraceEntry> list) {
+ synchronized (fEntryListMap) {
+ List<TraceEntry> entryList = fEntryListMap.get(trace);
+ if (entryList == null) {
+ fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
+ } else {
+ entryList.addAll(list);
+ }
+ }
+ }
+
+ private void addUnavailableEntry(ITmfTrace trace, ITmfTrace parentTrace) {
+ String name = Messages.CallStackView_StackInfoNotAvailable + ' ' + '(' + trace.getName() + ')';
+ TraceEntry unavailableEntry = new TraceEntry(name, 0, 0);
+ addToEntryList(parentTrace, Collections.singletonList(unavailableEntry));
+ if (parentTrace == fTrace) {
+ refresh();
+ }
+ }
+
+ private void buildStatusEvents(ITmfTrace trace, CallStackEntry entry, IProgressMonitor monitor, long start, long end) {
+ ITmfStateSystem ss = entry.getStateSystem();
+ long resolution = Math.max(1, (end - ss.getStartTime()) / fDisplayWidth);
+ List<ITimeEvent> eventList = getEventList(entry, start, end + 1, resolution, monitor);
+ if (eventList != null) {
+ for (ITimeEvent event : eventList) {
+ entry.addEvent(event);
+ }
+ }
+ if (trace == fTrace) {
+ redraw();
+ }
+ }
+
+ private static List<ITimeEvent> getEventList(CallStackEntry entry,
+ long startTime, long endTime, long resolution,
+ IProgressMonitor monitor) {
+ ITmfStateSystem ss = entry.getStateSystem();
+ long start = Math.max(startTime, ss.getStartTime());
+ long end = Math.min(endTime, ss.getCurrentEndTime() + 1);
+ if (end <= start) {
+ return null;
+ }
+ List<ITimeEvent> eventList = null;
+ try {
+ List<ITmfStateInterval> stackIntervals = ss.queryHistoryRange(entry.getQuark(), start, end - 1, resolution, monitor);
+ eventList = new ArrayList<>(stackIntervals.size());
+ long lastEndTime = -1;
+ boolean lastIsNull = true;
+ for (ITmfStateInterval statusInterval : stackIntervals) {
+ if (monitor.isCanceled()) {
+ return null;
+ }
+ long time = statusInterval.getStartTime();
+ long duration = statusInterval.getEndTime() - time + 1;
+ if (!statusInterval.getStateValue().isNull()) {
+ final int modulo = CallStackPresentationProvider.NUM_COLORS / 2;
+ int value = statusInterval.getStateValue().toString().hashCode() % modulo + modulo;
+ eventList.add(new CallStackEvent(entry, time, duration, value));
+ lastIsNull = false;
+ } else {
+ if (lastEndTime == -1) {
+ // add null event if it intersects the start time
+ eventList.add(new NullTimeEvent(entry, time, duration));
+ } else {
+ if (lastEndTime != time && lastIsNull) {
+ // add unknown event if between two null states
+ eventList.add(new TimeEvent(entry, lastEndTime, time - lastEndTime));
+ }
+ if (time + duration >= endTime) {
+ // add null event if it intersects the end time
+ eventList.add(new NullTimeEvent(entry, time, duration));
+ }
+ }
+ lastIsNull = true;
+ }
+ lastEndTime = time + duration;
+ }
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (TimeRangeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ return eventList;
+ }
+
+ private void synchingToTime(long time) {
+ if (fEntryList == null) {
+ return;
+ }
+ for (TraceEntry traceEntry : fEntryList) {
+ for (ITimeGraphEntry threadEntry : traceEntry.getChildren()) {
+ ITmfStateSystem ss = ((ThreadEntry) threadEntry).getStateSystem();
+ if (ss == null) {
+ continue;
+ }
+ if (ss.isCancelled()) {
+ continue;
+ }
+ if (time < ss.getStartTime() || time > ss.getCurrentEndTime()) {
+ continue;
+ }
+ for (ITimeGraphEntry child : threadEntry.getChildren()) {
+ CallStackEntry callStackEntry = (CallStackEntry) child;
+ try {
+ ITmfStateInterval stackLevelInterval = ss.querySingleState(time, callStackEntry.getQuark());
+ ITmfStateValue nameValue = stackLevelInterval.getStateValue();
+ String name = ""; //$NON-NLS-1$
+ try {
+ if (nameValue.getType() == Type.STRING) {
+ String address = nameValue.unboxStr();
+ name = getFunctionName(address);
+ } else if (nameValue.getType() == Type.INTEGER) {
+ name = "0x" + Integer.toHexString(nameValue.unboxInt()); //$NON-NLS-1$
+ } else if (nameValue.getType() == Type.LONG) {
+ name = "0x" + Long.toHexString(nameValue.unboxLong()); //$NON-NLS-1$
+ }
+ } catch (StateValueTypeException e) {
+ }
+ callStackEntry.setFunctionName(name);
+ if (name.length() > 0) {
+ callStackEntry.setFunctionEntryTime(stackLevelInterval.getStartTime());
+ callStackEntry.setFunctionExitTime(stackLevelInterval.getEndTime() + 1);
+ }
+ } catch (AttributeNotFoundException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+ }
+ }
+ fTimeGraphCombo.refresh();
+ }
+
+ private void refresh() {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ fEntryList = new ArrayList<>();
+ }
+ for (TraceEntry traceEntry : fEntryList) {
+ traceEntry.sortChildren(fThreadComparator);
+ }
+ }
+ if (fEntryList != fTimeGraphCombo.getInput()) {
+ fTimeGraphCombo.setInput(fEntryList);
+ } else {
+ fTimeGraphCombo.refresh();
+ }
+ fTimeGraphCombo.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
+
+ long selectionBeginTime = fTrace == null ? 0 : fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long selectionEndTime = fTrace == null ? 0 : fTraceManager.getSelectionEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long startTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long endTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ startTime = Math.max(startTime, fStartTime);
+ endTime = Math.min(endTime, fEndTime);
+ fTimeGraphCombo.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
+ synchingToTime(selectionBeginTime);
+ fTimeGraphCombo.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+ startZoomThread(startTime, endTime);
+ }
+ });
+ }
+
+ private void redraw() {
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.IDLE) {
+ fRedrawState = State.BUSY;
+ } else {
+ fRedrawState = State.PENDING;
+ return;
+ }
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphCombo.isDisposed()) {
+ return;
+ }
+ fTimeGraphCombo.redraw();
+ fTimeGraphCombo.update();
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.PENDING) {
+ fRedrawState = State.IDLE;
+ redraw();
+ } else {
+ fRedrawState = State.IDLE;
+ }
+ }
+ }
+ });
+ }
+
+ private void startZoomThread(long startTime, long endTime) {
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ fZoomThread = new ZoomThread(fEntryList, startTime, endTime);
+ fZoomThread.start();
+ }
+
+ private void makeActions() {
+ fPreviousItemAction = fTimeGraphCombo.getTimeGraphViewer().getPreviousItemAction();
+ fPreviousItemAction.setText(Messages.TmfTimeGraphViewer_PreviousItemActionNameText);
+ fPreviousItemAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousItemActionToolTipText);
+ fNextItemAction = fTimeGraphCombo.getTimeGraphViewer().getNextItemAction();
+ fNextItemAction.setText(Messages.TmfTimeGraphViewer_NextItemActionNameText);
+ fNextItemAction.setToolTipText(Messages.TmfTimeGraphViewer_NextItemActionToolTipText);
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ fillLocalToolBar(bars.getToolBarManager());
+
+ // Create pin action
+ contributePinActionToToolBar();
+ fPinAction.addPropertyChangeListener(new IPropertyChangeListener() {
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (IAction.CHECKED.equals(event.getProperty()) && !isPinned()) {
+ if (fSavedRangeSyncSignal != null) {
+ synchToRange(fSavedRangeSyncSignal);
+ fSavedRangeSyncSignal = null;
+ }
+
+ if (fSavedTimeSyncSignal != null) {
+ synchToTime(fSavedTimeSyncSignal);
+ fSavedTimeSyncSignal = null;
+ }
+ }
+ }
+ });
+ }
+
+ private void fillLocalToolBar(IToolBarManager manager) {
+ manager.add(getImportBinaryAction());
+ manager.add(getImportMappingAction());
+ manager.add(new Separator());
+ manager.add(getSortByNameAction());
+ manager.add(getSortByIdAction());
+ manager.add(getSortByTimeAction());
+ manager.add(new Separator());
+ manager.add(fTimeGraphCombo.getTimeGraphViewer().getResetScaleAction());
+ manager.add(getPreviousEventAction());
+ manager.add(getNextEventAction());
+ manager.add(fPreviousItemAction);
+ manager.add(fNextItemAction);
+ manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomInAction());
+ manager.add(fTimeGraphCombo.getTimeGraphViewer().getZoomOutAction());
+ manager.add(new Separator());
+ }
+
+ private void createContextMenu() {
+ final MenuManager contextMenu = new MenuManager();
+ contextMenu.add(getSortByNameAction());
+ contextMenu.add(getSortByIdAction());
+ contextMenu.add(getSortByTimeAction());
+
+ Tree tree = fTimeGraphCombo.getTreeViewer().getTree();
+ Menu menu = contextMenu.createContextMenu(tree);
+ tree.setMenu(menu);
+ }
+
+ /**
+ * Get the the next event action.
+ *
+ * @return The action object
+ */
+ private Action getNextEventAction() {
+ if (fNextEventAction == null) {
+ fNextEventAction = new Action() {
+ @Override
+ public void run() {
+ TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
+ ITimeGraphEntry entry = viewer.getSelection();
+ if (entry instanceof CallStackEntry) {
+ try {
+ CallStackEntry callStackEntry = (CallStackEntry) entry;
+ ITmfStateSystem ss = callStackEntry.getStateSystem();
+ long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
+ ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
+ int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
+ ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
+ long newTime = stackInterval.getEndTime() + 1;
+ viewer.setSelectedTimeNotify(newTime, true);
+ stackInterval = ss.querySingleState(Math.min(ss.getCurrentEndTime(), newTime), quark);
+ int stackLevel = stackInterval.getStateValue().unboxInt();
+ ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
+ fTimeGraphCombo.setSelection(selectedEntry);
+ viewer.getTimeGraphControl().fireSelectionChanged();
+ startZoomThread(viewer.getTime0(), viewer.getTime1());
+
+ } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ }
+ }
+ }
+ };
+
+ fNextEventAction.setText(Messages.TmfTimeGraphViewer_NextEventActionNameText);
+ fNextEventAction.setToolTipText(Messages.TmfTimeGraphViewer_NextEventActionToolTipText);
+ fNextEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_EVENT));
+ }
+
+ return fNextEventAction;
+ }
+
+ /**
+ * Get the previous event action.
+ *
+ * @return The Action object
+ */
+ private Action getPreviousEventAction() {
+ if (fPrevEventAction == null) {
+ fPrevEventAction = new Action() {
+ @Override
+ public void run() {
+ TimeGraphViewer viewer = fTimeGraphCombo.getTimeGraphViewer();
+ ITimeGraphEntry entry = viewer.getSelection();
+ if (entry instanceof CallStackEntry) {
+ try {
+ CallStackEntry callStackEntry = (CallStackEntry) entry;
+ ITmfStateSystem ss = callStackEntry.getStateSystem();
+ long time = Math.max(ss.getStartTime(), Math.min(ss.getCurrentEndTime(), viewer.getSelectionBegin()));
+ ThreadEntry threadEntry = (ThreadEntry) callStackEntry.getParent();
+ int quark = ss.getParentAttributeQuark(callStackEntry.getQuark());
+ ITmfStateInterval stackInterval = ss.querySingleState(time, quark);
+ if (stackInterval.getStartTime() == time && time > ss.getStartTime()) {
+ stackInterval = ss.querySingleState(time - 1, quark);
+ }
+ viewer.setSelectedTimeNotify(stackInterval.getStartTime(), true);
+ int stackLevel = stackInterval.getStateValue().unboxInt();
+ ITimeGraphEntry selectedEntry = threadEntry.getChildren().get(Math.max(0, stackLevel - 1));
+ fTimeGraphCombo.setSelection(selectedEntry);
+ viewer.getTimeGraphControl().fireSelectionChanged();
+ startZoomThread(viewer.getTime0(), viewer.getTime1());
+
+ } catch (AttributeNotFoundException | TimeRangeException | StateSystemDisposedException | StateValueTypeException e) {
+ Activator.getDefault().logError("Error querying state system", e); //$NON-NLS-1$
+ }
+ }
+ }
+ };
+
+ fPrevEventAction.setText(Messages.TmfTimeGraphViewer_PreviousEventActionNameText);
+ fPrevEventAction.setToolTipText(Messages.TmfTimeGraphViewer_PreviousEventActionToolTipText);
+ fPrevEventAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_EVENT));
+ }
+
+ return fPrevEventAction;
+ }
+
+ private static @Nullable AbstractCallStackAnalysis getCallStackModule(ITmfTrace trace) {
+ /*
+ * Since we cannot know the exact analysis ID (in separate plugins), we
+ * will search using the analysis type.
+ */
+ Iterable<AbstractCallStackAnalysis> modules =
+ trace.getAnalysisModulesOfClass(AbstractCallStackAnalysis.class);
+ Iterator<AbstractCallStackAnalysis> it = modules.iterator();
+ if (!it.hasNext()) {
+ /* This trace does not provide a call-stack analysis */
+ return null;
+ }
+
+ /*
+ * We only look at the first module we find.
+ *
+ * TODO Handle the advanced case where one trace provides more than one
+ * call-stack analysis.
+ */
+ AbstractCallStackAnalysis module = it.next();
+ /* This analysis is not automatic, we need to schedule it on-demand */
+ module.schedule();
+ module.waitForInitialization();
+ return module;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods related to function name mapping
+ // ------------------------------------------------------------------------
+
+ /**
+ * Common code for all import file mapping actions
+ */
+ private abstract class AbstractImportFileMappingAction extends Action {
+ private final String fDialogTitle;
+
+ private AbstractImportFileMappingAction(String dialogTitle) {
+ fDialogTitle = dialogTitle;
+ }
+
+ @Override
+ public void run() {
+ FileDialog dialog = new FileDialog(getViewSite().getShell());
+ dialog.setText(fDialogTitle);
+ final String filePath = dialog.open();
+ if (filePath == null) {
+ /* No file was selected, don't change anything */
+ return;
+ }
+
+ /*
+ * Start the mapping import in a separate thread (we do not want to
+ * UI thread to do this).
+ */
+ Job job = new Job(Messages.CallStackView_ImportMappingJobName) {
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ fNameMapping = doMapping(new File(filePath));
+
+ /* Refresh call stack entries and event labels */
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ synchingToTime(fTimeGraphCombo.getTimeGraphViewer().getSelectionBegin());
+ }
+ });
+ return Status.OK_STATUS;
+ }
+ };
+ job.schedule();
+ }
+
+ abstract Map<String, String> doMapping(File file);
+ }
+
+ /**
+ * Toolbar icon to import the function address-to-name mapping file.
+ */
+ private Action getImportMappingAction() {
+ if (fImportMappingAction != null) {
+ return fImportMappingAction;
+ }
+ fImportMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportMappingDialogTitle) {
+ @Override
+ Map<String, String> doMapping(File file) {
+ return FunctionNameMapper.mapFromNmTextFile(file);
+ }
+ };
+
+ fImportMappingAction.setText(Messages.CallStackView_ImportMappingButtonText);
+ fImportMappingAction.setToolTipText(Messages.CallStackView_ImportMappingButtonTooltip);
+ fImportMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_MAPPING_ICON_PATH));
+
+ return fImportMappingAction;
+ }
+
+ private Action getSortByNameAction() {
+ if (fSortByNameAction == null) {
+ fSortByNameAction = new Action(Messages.CallStackView_SortByThreadName, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ if (fSortOption == SortOption.BY_NAME) {
+ saveSortOption(SortOption.BY_NAME_REV);
+ } else {
+ saveSortOption(SortOption.BY_NAME);
+ }
+ }
+ };
+ fSortByNameAction.setToolTipText(Messages.CallStackView_SortByThreadName);
+ fSortByNameAction.setImageDescriptor(SORT_BY_NAME_ICON);
+ }
+ return fSortByNameAction;
+ }
+
+ private Action getSortByIdAction() {
+ if (fSortByIdAction == null) {
+ fSortByIdAction = new Action(Messages.CallStackView_SortByThreadId, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ if (fSortOption == SortOption.BY_ID) {
+ saveSortOption(SortOption.BY_ID_REV);
+ } else {
+ saveSortOption(SortOption.BY_ID);
+ }
+ }
+ };
+ fSortByIdAction.setToolTipText(Messages.CallStackView_SortByThreadId);
+ fSortByIdAction.setImageDescriptor(SORT_BY_ID_ICON);
+ }
+ return fSortByIdAction;
+ }
+
+ private Action getSortByTimeAction() {
+ if (fSortByTimeAction == null) {
+ fSortByTimeAction = new Action(Messages.CallStackView_SortByThreadTime, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ if (fSortOption == SortOption.BY_TIME) {
+ saveSortOption(SortOption.BY_TIME_REV);
+ } else {
+ saveSortOption(SortOption.BY_TIME);
+ }
+ }
+ };
+ fSortByTimeAction.setToolTipText(Messages.CallStackView_SortByThreadTime);
+ fSortByTimeAction.setImageDescriptor(SORT_BY_TIME_ICON);
+ }
+ return fSortByTimeAction;
+ }
+
+ private void loadSortOption() {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(getClass().getName());
+ if (section == null) {
+ return;
+ }
+ String sortOption = section.get(SORT_OPTION_KEY);
+ if (sortOption == null) {
+ return;
+ }
+
+ // reset defaults
+ getSortByNameAction().setChecked(false);
+ getSortByNameAction().setImageDescriptor(SORT_BY_NAME_ICON);
+ getSortByIdAction().setChecked(false);
+ getSortByIdAction().setImageDescriptor(SORT_BY_ID_ICON);
+ getSortByTimeAction().setChecked(false);
+ getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_ICON);
+
+ if (sortOption.equals(SortOption.BY_NAME.name())) {
+ fSortOption = SortOption.BY_NAME;
+ fThreadComparator = new ThreadNameComparator(false);
+ getSortByNameAction().setChecked(true);
+ } else if (sortOption.equals(SortOption.BY_NAME_REV.name())) {
+ fSortOption = SortOption.BY_NAME_REV;
+ fThreadComparator = new ThreadNameComparator(true);
+ getSortByNameAction().setChecked(true);
+ getSortByNameAction().setImageDescriptor(SORT_BY_NAME_REV_ICON);
+ } else if (sortOption.equals(SortOption.BY_ID.name())) {
+ fSortOption = SortOption.BY_ID;
+ fThreadComparator = new ThreadIdComparator(false);
+ getSortByIdAction().setChecked(true);
+ } else if (sortOption.equals(SortOption.BY_ID_REV.name())) {
+ fSortOption = SortOption.BY_ID_REV;
+ fThreadComparator = new ThreadIdComparator(true);
+ getSortByIdAction().setChecked(true);
+ getSortByIdAction().setImageDescriptor(SORT_BY_ID_REV_ICON);
+ } else if (sortOption.equals(SortOption.BY_TIME.name())) {
+ fSortOption = SortOption.BY_TIME;
+ fThreadComparator = new ThreadTimeComparator(false);
+ getSortByTimeAction().setChecked(true);
+ } else if (sortOption.equals(SortOption.BY_TIME_REV.name())) {
+ fSortOption = SortOption.BY_TIME_REV;
+ fThreadComparator = new ThreadTimeComparator(true);
+ getSortByTimeAction().setChecked(true);
+ getSortByTimeAction().setImageDescriptor(SORT_BY_TIME_REV_ICON);
+ }
+ }
+
+ private void saveSortOption(SortOption sortOption) {
+ IDialogSettings settings = Activator.getDefault().getDialogSettings();
+ IDialogSettings section = settings.getSection(getClass().getName());
+ if (section == null) {
+ section = settings.addNewSection(getClass().getName());
+ }
+ section.put(SORT_OPTION_KEY, sortOption.name());
+ loadSortOption();
+ if (fEntryList == null) {
+ return;
+ }
+ for (TraceEntry traceEntry : fEntryList) {
+ traceEntry.sortChildren(fThreadComparator);
+ }
+ refresh();
+ }
+
+ /**
+ * Toolbar icon to import the function address-to-name mapping binary file.
+ */
+ private Action getImportBinaryAction() {
+ if (fImportBinaryFileMappingAction != null) {
+ return fImportBinaryFileMappingAction;
+ }
+
+ fImportBinaryFileMappingAction = new AbstractImportFileMappingAction(Messages.CallStackView_ImportBinaryFileDialogTitle) {
+ @Override
+ Map<String, String> doMapping(File file) {
+ return FunctionNameMapper.mapFromBinaryFile(file);
+ }
+ };
+
+ fImportBinaryFileMappingAction.setText(Messages.CallStackView_ImportBinaryFileButtonText);
+ fImportBinaryFileMappingAction.setToolTipText(Messages.CallStackView_ImportBinaryFileButtonTooltip);
+ fImportBinaryFileMappingAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(IMPORT_BINARY_ICON_PATH));
+
+ return fImportBinaryFileMappingAction;
+ }
+
+ String getFunctionName(String address) {
+ if (fNameMapping == null) {
+ /* No mapping available, just print the addresses */
+ return address;
+ }
+ String ret = fNameMapping.get(address);
+ if (ret == null) {
+ /*
+ * We didn't find this address in the mapping file, just use the
+ * address
+ */
+ return address;
+ }
+ return ret;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/FunctionNameMapper.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/FunctionNameMapper.java
new file mode 100644
index 0000000000..2c421a799b
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/callstack/FunctionNameMapper.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Montplaisir - Initial API and implementation
+ * Marc-Andre Laperle - Map from binary file
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.callstack;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.IBinaryParser;
+import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
+import org.eclipse.cdt.core.IBinaryParser.ISymbol;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+
+/**
+ * Class containing the different methods to import an address->name mapping.
+ *
+ * @author Alexandre Montplaisir
+ */
+class FunctionNameMapper {
+
+ public static @Nullable Map<String, String> mapFromNmTextFile(File mappingFile) {
+ Map<String, String> map = new HashMap<>();
+
+ try (FileReader fr = new FileReader(mappingFile);
+ BufferedReader reader = new BufferedReader(fr);) {
+ for (String line = reader.readLine(); line != null; line = reader.readLine()) {
+ String[] elems = line.split(" "); //$NON-NLS-1$
+ /* Only lines with 3 elements contain addresses */
+ if (elems.length == 3) {
+ /* Strip the leading zeroes from the address */
+ String address = elems[0].replaceFirst("^0+(?!$)", ""); //$NON-NLS-1$ //$NON-NLS-2$;
+ String name = elems[elems.length - 1];
+ map.put(address, name);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ return null;
+ } catch (IOException e) {
+ /* Stop reading the file at this point */
+ }
+
+ if (map.isEmpty()) {
+ return null;
+ }
+ return Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * Strip the leading zeroes from the address
+ * */
+ private static String stripLeadingZeros(String address) {
+ return address.replaceFirst("^0+(?!$)", ""); //$NON-NLS-1$ //$NON-NLS-2$;
+ }
+
+ public static @Nullable Map<String, String> mapFromBinaryFile(File file) {
+ Map<String, String> map = new HashMap<>();
+ IBinaryParser.IBinaryObject binaryObject = getBinaryObject(file);
+ if (binaryObject != null) {
+ ISymbol[] symbols = binaryObject.getSymbols();
+ for (ISymbol symbol : symbols) {
+ String address = symbol.getAddress().toHexAddressString();
+ /* Remove "0x" */
+ address = address.substring(2);
+ /* Strip the leading zeroes from the address */
+ address = stripLeadingZeros(address);
+ map.put(address, symbol.getName());
+ }
+ }
+
+ return map;
+ }
+
+ private static @Nullable IBinaryParser.IBinaryObject getBinaryObject(File file) {
+ IPath filePath = new Path(file.toString());
+
+ /* Get all the available binary parsers */
+ final List<IBinaryParser> binaryParsers = new ArrayList<>();
+ IConfigurationElement[] elements = Platform.getExtensionRegistry()
+ .getConfigurationElementsFor(CCorePlugin.BINARY_PARSER_UNIQ_ID);
+ for (IConfigurationElement element : elements) {
+ IConfigurationElement[] children = element.getChildren("run"); //$NON-NLS-1$
+ for (final IConfigurationElement run : children) {
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void run() throws Exception {
+ IBinaryParser binaryParser = (IBinaryParser) run.createExecutableExtension("class"); //$NON-NLS-1$
+ binaryParsers.add(binaryParser);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ Activator.getDefault().logError("Error creating binary parser", exception); //$NON-NLS-1$
+ }
+ });
+ }
+ }
+
+ /* Find the maximum "hint" buffer size we'll need from all the parsers */
+ int hintBufferSize = 0;
+ for (IBinaryParser parser : binaryParsers) {
+ if (parser.getHintBufferSize() > hintBufferSize) {
+ hintBufferSize = Math.max(hintBufferSize, parser.getHintBufferSize());
+ }
+ }
+
+ /* Read the initial "hint" bytes */
+ byte[] hintBuffer = new byte[hintBufferSize];
+ if (hintBufferSize > 0) {
+ try (InputStream is = new FileInputStream(file) ){
+
+ int count = 0;
+ // Make sure we read up to 'hints' bytes if we possibly can
+ while (count < hintBufferSize) {
+ int bytesRead = is.read(hintBuffer, count, hintBufferSize - count);
+ if (bytesRead < 0) {
+ break;
+ }
+ count += bytesRead;
+ }
+ if (count > 0 && count < hintBuffer.length) {
+ byte[] array = new byte[count];
+ System.arraycopy(hintBuffer, 0, array, 0, count);
+ hintBuffer = array;
+ }
+ } catch (IOException e) {
+ Activator.getDefault().logError("Error reading initial bytes of binary file", e); //$NON-NLS-1$
+ return null;
+ }
+ }
+
+ /* For all binary parsers, try to get a binary object */
+ for (IBinaryParser parser : binaryParsers) {
+ if (parser.isBinary(hintBuffer, filePath)) {
+ IBinaryFile binFile;
+ try {
+ binFile = parser.getBinary(hintBuffer, filePath);
+ if (binFile != null && binFile instanceof IBinaryParser.IBinaryObject) {
+ return (IBinaryParser.IBinaryObject)binFile;
+ }
+ } catch (IOException e) {
+ Activator.getDefault().logError("Error parsing binary file", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSetting.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSetting.java
new file mode 100644
index 0000000000..15c4d7dabc
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSetting.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated to use RGB for the tick color
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.colors;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.ui.themes.ColorUtil;
+
+/**
+ * Class for storing color settings of a TMF filter.
+ *
+ * Application code must explicitly invoke the ColorSetting.dispose() method to release the operating system
+ * resources managed by each instance when those instances are no longer required.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class ColorSetting {
+
+ private RGB fForegroundRGB;
+ private RGB fBackgroundRGB;
+ private RGB fTickColorRGB;
+ private Color fForegroundColor;
+ private Color fBackgroundColor;
+ private Color fDimmedForegroundColor;
+ private Color fDimmedBackgroundColor;
+ private Color fTickColor;
+ private ITmfFilterTreeNode fFilter;
+
+ /**
+ * Constructor
+ *
+ * You must dispose the color setting when it is no longer required.
+ *
+ * @param foreground
+ * The foreground color
+ * @param background
+ * The background color
+ * @param tickColorRGB
+ * The color for the checkbox ticks
+ * @param filter
+ * The filter tree node
+ */
+ public ColorSetting(RGB foreground, RGB background, RGB tickColorRGB, ITmfFilterTreeNode filter) {
+ fForegroundRGB = foreground;
+ fBackgroundRGB = background;
+ fTickColorRGB = tickColorRGB;
+ fFilter = filter;
+ Display display = Display.getDefault();
+ fForegroundColor = new Color(display, fForegroundRGB);
+ fBackgroundColor = new Color(display, fBackgroundRGB);
+ fDimmedForegroundColor = new Color(display, ColorUtil.blend(
+ fForegroundRGB, fBackgroundRGB));
+ fDimmedBackgroundColor = new Color(display, ColorUtil.blend(
+ fBackgroundRGB, display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB()));
+ fTickColor = new Color(display, fTickColorRGB);
+ }
+
+ /**
+ * Dispose the color setting resources
+ */
+ public void dispose() {
+ fForegroundColor.dispose();
+ fBackgroundColor.dispose();
+ fDimmedForegroundColor.dispose();
+ fDimmedBackgroundColor.dispose();
+ fTickColor.dispose();
+ }
+
+ /**
+ * Returns foreground RGB value.
+ *
+ * @return the foreground RGB
+ */
+ public RGB getForegroundRGB() {
+ return fForegroundRGB;
+ }
+
+ /**
+ * Sets the foreground RGB value
+ *
+ * @param foreground the foreground to set
+ */
+ public void setForegroundRGB(RGB foreground) {
+ fForegroundRGB = foreground;
+ fForegroundColor.dispose();
+ fDimmedForegroundColor.dispose();
+ Display display = Display.getDefault();
+ fForegroundColor = new Color(display, fForegroundRGB);
+ fDimmedForegroundColor = new Color(display, ColorUtil.blend(
+ fForegroundRGB, fBackgroundRGB));
+ }
+
+ /**
+ * Returns the background RGB value.
+ *
+ * @return the background RGB
+ */
+ public RGB getBackgroundRGB() {
+ return fBackgroundRGB;
+ }
+
+ /**
+ * Sets the background RGB value.
+ *
+ * @param background the background to set
+ */
+ public void setBackgroundRGB(RGB background) {
+ fBackgroundRGB = background;
+ fBackgroundColor.dispose();
+ fDimmedBackgroundColor.dispose();
+ Display display = Display.getDefault();
+ fBackgroundColor = new Color(display, fBackgroundRGB);
+ fDimmedBackgroundColor = new Color(display, ColorUtil.blend(
+ fBackgroundRGB, display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB()));
+ }
+
+ /**
+ * Returns the RGB of the tick color
+ *
+ * @return the RGB of the tick color
+ */
+ public RGB getTickColorRGB() {
+ return fTickColorRGB;
+ }
+
+ /**
+ * Sets the RGB of the tick color
+ *
+ * @param tickColorRGB the tick color TGB
+ */
+ public void setTickColorRGB(RGB tickColorRGB) {
+ fTickColorRGB = tickColorRGB;
+ fTickColor.dispose();
+ Display display = Display.getDefault();
+ fTickColor = new Color(display, fTickColorRGB);
+ }
+
+ /**
+ * Returns the filter implementation.
+ * @return the filter
+ */
+ public ITmfFilterTreeNode getFilter() {
+ return fFilter;
+ }
+
+ /**
+ * Sets the filter implementation.
+ *
+ * @param filter the filter to set
+ */
+ public void setFilter(ITmfFilterTreeNode filter) {
+ fFilter = filter;
+ }
+
+ /**
+ * Returns the foreground color.
+ *
+ * @return the foreground color
+ */
+ public Color getForegroundColor() {
+ return fForegroundColor;
+ }
+
+ /**
+ * Returns the background color.
+ *
+ * @return the background color
+ */
+ public Color getBackgroundColor() {
+ return fBackgroundColor;
+ }
+
+ /**
+ * Returns the dimmed foreground color.
+ *
+ * @return the dimmed foreground color
+ */
+ public Color getDimmedForegroundColor() {
+ return fDimmedForegroundColor;
+ }
+
+ /**
+ * Returns the dimmed background color.
+ *
+ * @return the dimmed background color
+ */
+ public Color getDimmedBackgroundColor() {
+ return fDimmedBackgroundColor;
+ }
+
+ /**
+ * Returns the tick color.
+ *
+ * @return the tick color
+ */
+ public Color getTickColor() {
+ return fTickColor;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsManager.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsManager.java
new file mode 100644
index 0000000000..7e6c7ce906
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsManager.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated to use RGB for the tick color
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.colors;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+
+/**
+ * Static class for managing color settings.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ *
+ */
+public class ColorSettingsManager {
+
+ // The color settings file name
+ private static final String COLOR_SETTINGS_FILE_NAME = "color_settings.xml"; //$NON-NLS-1$
+
+ // The path for the color settings file
+ private static final String COLOR_SETTINGS_PATH_NAME =
+ Activator.getDefault().getStateLocation().addTrailingSeparator().append(COLOR_SETTINGS_FILE_NAME).toString();
+
+ // The default color setting
+ private static final ColorSetting DEFAULT_COLOR_SETTING = new ColorSetting(
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND).getRGB(),
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(),
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND).getRGB(),
+ null);
+
+ /**
+ * Special value for priority if unknown.
+ */
+ public static final int PRIORITY_NONE = Integer.MAX_VALUE;
+
+ // The stored color settings
+ private static ColorSetting[] fColorSettings = ColorSettingsXML.load(COLOR_SETTINGS_PATH_NAME);
+
+ // The listener list
+ private static List<IColorSettingsListener> fListeners = new ArrayList<>();
+
+ /**
+ * Returns an array of color settings.
+ *
+ * @return an array of color settings.
+ */
+ public static ColorSetting[] getColorSettings() {
+ return (fColorSettings != null) ? Arrays.copyOf(fColorSettings, fColorSettings.length) : null;
+ }
+
+ /**
+ * Sets the array of color settings.
+ *
+ * @param colorSettings A array of color settings to set
+ */
+ public static void setColorSettings(ColorSetting[] colorSettings) {
+ fColorSettings = (colorSettings != null) ? Arrays.copyOf(colorSettings, colorSettings.length) : null;
+ ColorSettingsXML.save(COLOR_SETTINGS_PATH_NAME, fColorSettings);
+ fireColorSettingsChanged();
+ }
+
+ /**
+ * Gets the color settings that matches the filter for given event.
+ *
+ * @param event
+ * The event to check
+ *
+ * @return color settings defined for filter if found else default color
+ * settings
+ */
+ public static ColorSetting getColorSetting(ITmfEvent event) {
+ for (int i = 0; i < fColorSettings.length; i++) {
+ ColorSetting colorSetting = fColorSettings[i];
+ if (colorSetting.getFilter() != null && colorSetting.getFilter().matches(event)) {
+ return colorSetting;
+ }
+ }
+ return DEFAULT_COLOR_SETTING;
+ }
+
+ /**
+ * Gets the color settings priority for the given event.
+ *
+ * @param event A event the event to check
+ * @return the priority defined for the filter else PRIORITY_NONE
+ */
+ public static int getColorSettingPriority(ITmfEvent event) {
+ for (int i = 0; i < fColorSettings.length; i++) {
+ ColorSetting colorSetting = fColorSettings[i];
+ if (colorSetting.getFilter() != null && colorSetting.getFilter().matches(event)) {
+ return i;
+ }
+ }
+ return PRIORITY_NONE;
+ }
+
+ /**
+ * Returns the color settings based the priority.
+ *
+ * @param priority A priority (index) of color settings
+ * @return the color settings defined for the priority else default color settings
+ */
+ public static ColorSetting getColorSetting(int priority) {
+ if (priority < fColorSettings.length) {
+ return fColorSettings[priority];
+ }
+ return DEFAULT_COLOR_SETTING;
+ }
+
+ /**
+ * Adds a color settings listener.
+ *
+ * @param listener A listener to add.
+ */
+ public static void addColorSettingsListener(IColorSettingsListener listener) {
+ if (! fListeners.contains(listener)) {
+ fListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes a color settings listener.
+ *
+ * @param listener A listener to remove.
+ */
+ public static void removeColorSettingsListener(IColorSettingsListener listener) {
+ fListeners.remove(listener);
+ }
+
+ // Notify listeners
+ private static void fireColorSettingsChanged() {
+ for (IColorSettingsListener listener : fListeners) {
+ listener.colorSettingsChanged(fColorSettings);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsXML.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsXML.java
new file mode 100644
index 0000000000..a123b25c6c
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorSettingsXML.java
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated to use RGB for the tick color
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.colors;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterContentHandler;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterXMLWriter;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * Class for saving and loading of color settings to/from file.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ *
+ */
+public class ColorSettingsXML {
+
+ // XML Tags and attributes
+ private static final String COLOR_SETTINGS_TAG = "COLOR_SETTINGS"; //$NON-NLS-1$
+ private static final String COLOR_SETTING_TAG = "COLOR_SETTING"; //$NON-NLS-1$
+ private static final String FG_TAG = "FG"; //$NON-NLS-1$
+ private static final String BG_TAG = "BG"; //$NON-NLS-1$
+ private static final String R_ATTR = "R"; //$NON-NLS-1$
+ private static final String G_ATTR = "G"; //$NON-NLS-1$
+ private static final String B_ATTR = "B"; //$NON-NLS-1$
+ private static final String TICK_TAG = "TICK"; //$NON-NLS-1$
+ private static final String FILTER_TAG = "FILTER"; //$NON-NLS-1$
+
+ /**
+ * Saves the given color settings to file.
+ *
+ * @param pathName
+ * A file name with path
+ * @param colorSettings
+ * -An array of color settings to save.
+ */
+ public static void save(String pathName, ColorSetting[] colorSettings) {
+ try {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document document = documentBuilder.newDocument();
+
+ Element rootElement = document.createElement(COLOR_SETTINGS_TAG);
+ document.appendChild(rootElement);
+
+ for (ColorSetting colorSetting : colorSettings) {
+ Element colorSettingElement = document.createElement(COLOR_SETTING_TAG);
+ rootElement.appendChild(colorSettingElement);
+
+ Element fgElement = document.createElement(FG_TAG);
+ colorSettingElement.appendChild(fgElement);
+ RGB foreground = colorSetting.getForegroundRGB();
+ fgElement.setAttribute(R_ATTR, Integer.toString(foreground.red));
+ fgElement.setAttribute(G_ATTR, Integer.toString(foreground.green));
+ fgElement.setAttribute(B_ATTR, Integer.toString(foreground.blue));
+
+ Element bgElement = document.createElement(BG_TAG);
+ colorSettingElement.appendChild(bgElement);
+ RGB background = colorSetting.getBackgroundRGB();
+ bgElement.setAttribute(R_ATTR, Integer.toString(background.red));
+ bgElement.setAttribute(G_ATTR, Integer.toString(background.green));
+ bgElement.setAttribute(B_ATTR, Integer.toString(background.blue));
+
+ Element tickColorElement = document.createElement(TICK_TAG);
+ colorSettingElement.appendChild(tickColorElement);
+ RGB tickColor = colorSetting.getTickColorRGB();
+ tickColorElement.setAttribute(R_ATTR, Integer.toString(tickColor.red));
+ tickColorElement.setAttribute(G_ATTR, Integer.toString(tickColor.green));
+ tickColorElement.setAttribute(B_ATTR, Integer.toString(tickColor.blue));
+
+ if (colorSetting.getFilter() != null) {
+ Element filterElement = document.createElement(FILTER_TAG);
+ colorSettingElement.appendChild(filterElement);
+ TmfFilterXMLWriter.buildXMLTree(document, colorSetting.getFilter(), filterElement);
+ }
+ }
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(document);
+ StreamResult result = new StreamResult(new File(pathName));
+ transformer.transform(source, result);
+ } catch (ParserConfigurationException e) {
+ Activator.getDefault().logError("Error saving color xml file: " + pathName, e); //$NON-NLS-1$
+ } catch (TransformerConfigurationException e) {
+ Activator.getDefault().logError("Error saving color xml file: " + pathName, e); //$NON-NLS-1$
+ } catch (TransformerException e) {
+ Activator.getDefault().logError("Error saving color xml file: " + pathName, e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Loads color settings from file and returns it in an array.
+ *
+ * @param pathName
+ * A file name with path
+ *
+ * @return the color settings array loaded from file
+ */
+ public static ColorSetting[] load(String pathName) {
+ if (!new File(pathName).canRead()) {
+ return new ColorSetting[0];
+ }
+ SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+ parserFactory.setNamespaceAware(true);
+
+ ColorSettingsContentHandler handler = new ColorSettingsContentHandler();
+ try {
+ XMLReader saxReader = parserFactory.newSAXParser().getXMLReader();
+ saxReader.setContentHandler(handler);
+ saxReader.parse(pathName);
+ return handler.colorSettings.toArray(new ColorSetting[0]);
+ } catch (ParserConfigurationException e) {
+ Activator.getDefault().logError("Error loading color xml file: " + pathName, e); //$NON-NLS-1$
+ } catch (SAXException e) {
+ Activator.getDefault().logError("Error loading color xml file: " + pathName, e); //$NON-NLS-1$
+ } catch (IOException e) {
+ Activator.getDefault().logError("Error loading color xml file: " + pathName, e); //$NON-NLS-1$
+ }
+ // In case of error, dispose the partial list of color settings
+ for (ColorSetting colorSetting : handler.colorSettings) {
+ colorSetting.dispose();
+ }
+ return new ColorSetting[0];
+ }
+
+ // Helper class
+ private static class ColorSettingsContentHandler extends DefaultHandler {
+
+ private List<ColorSetting> colorSettings = new ArrayList<>(0);
+ private RGB fg = new RGB(0, 0, 0);
+ private RGB bg = new RGB(255, 255, 255);
+ private RGB tickColor = new RGB(0, 0, 0);
+ private ITmfFilterTreeNode filter;
+ private TmfFilterContentHandler filterContentHandler;
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ if (localName.equals(COLOR_SETTINGS_TAG)) {
+ colorSettings = new ArrayList<>();
+ } else if (localName.equals(COLOR_SETTING_TAG)) {
+ fg = null;
+ bg = null;
+ filter = null;
+ } else if (localName.equals(FG_TAG)) {
+ int r = Integer.parseInt(attributes.getValue(R_ATTR));
+ int g = Integer.parseInt(attributes.getValue(G_ATTR));
+ int b = Integer.parseInt(attributes.getValue(B_ATTR));
+ fg = new RGB(r, g, b);
+ } else if (localName.equals(BG_TAG)) {
+ int r = Integer.parseInt(attributes.getValue(R_ATTR));
+ int g = Integer.parseInt(attributes.getValue(G_ATTR));
+ int b = Integer.parseInt(attributes.getValue(B_ATTR));
+ bg = new RGB(r, g, b);
+ } else if (localName.equals(TICK_TAG)) {
+ int r = Integer.parseInt(attributes.getValue(R_ATTR));
+ int g = Integer.parseInt(attributes.getValue(G_ATTR));
+ int b = Integer.parseInt(attributes.getValue(B_ATTR));
+ tickColor = new RGB(r, g, b);
+ } else if (localName.equals(FILTER_TAG)) {
+ filterContentHandler = new TmfFilterContentHandler();
+ } else if (filterContentHandler != null) {
+ filterContentHandler.startElement(uri, localName, qName, attributes);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+ if (localName.equals(COLOR_SETTINGS_TAG)) {
+ // Nothing to do
+ } else if (localName.equals(COLOR_SETTING_TAG)) {
+ ColorSetting colorSetting = new ColorSetting(fg, bg, tickColor, filter);
+ colorSettings.add(colorSetting);
+ } else if (localName.equals(FILTER_TAG)) {
+ filter = filterContentHandler.getTree();
+ filterContentHandler = null;
+ } else if (filterContentHandler != null) {
+ filterContentHandler.endElement(uri, localName, qName);
+ }
+ }
+
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorsView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorsView.java
new file mode 100644
index 0000000000..a5081a0566
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/ColorsView.java
@@ -0,0 +1,588 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated to use RGB for the tick color
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.colors;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.ColorDialog;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.views.filter.FilterDialog;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.TimeGraphColorScheme;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * Color view implementation. This view provides support for managing color settings for filters.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ *
+ */
+public class ColorsView extends TmfView {
+
+ /** ID for the color view */
+ public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.colors"; //$NON-NLS-1$
+
+ private static final Image ADD_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/add_button.gif"); //$NON-NLS-1$
+ private static final Image DELETE_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/delete_button.gif"); //$NON-NLS-1$
+ private static final Image MOVE_UP_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/moveup_button.gif"); //$NON-NLS-1$
+ private static final Image MOVE_DOWN_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/movedown_button.gif"); //$NON-NLS-1$
+ private static final Image IMPORT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/import_button.gif"); //$NON-NLS-1$
+ private static final Image EXPORT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/export_button.gif"); //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Main data structures
+ // ------------------------------------------------------------------------
+
+ /**
+ * The composite shell.
+ */
+ protected Shell fShell;
+ /**
+ * The main composite (scrolled composite)
+ */
+ protected ScrolledComposite fScrolledComposite;
+ /**
+ * The list composite.
+ */
+ protected Composite fListComposite;
+ /**
+ * The filler composite.
+ */
+ protected Composite fFillerComposite;
+ /**
+ * The selected color settings row
+ */
+ protected ColorSettingRow fSelectedRow = null;
+ /**
+ * The color scheme instance for managing colors
+ */
+ protected TimeGraphColorScheme traceColorScheme = new TimeGraphColorScheme();
+ /**
+ * An action to add a color settings row
+ */
+ protected Action fAddAction;
+ /**
+ * An action to delete a color settings row
+ */
+ protected Action fDeleteAction;
+ /**
+ * An action to move up a color settings row in the list.
+ */
+ protected Action fMoveUpAction;
+ /**
+ * An action to move down a color settings row in the list.
+ */
+ protected Action fMoveDownAction;
+ /**
+ * An action to import color settings from file.
+ */
+ protected Action fImportAction;
+ /**
+ * An action to export color settings from file.
+ */
+ protected Action fExportAction;
+ /**
+ * The list of existing color settings
+ */
+ protected List<ColorSetting> fColorSettings;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default Constructor
+ */
+ public ColorsView() {
+ super("Colors"); //$NON-NLS-1$
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ fShell = parent.getShell();
+
+ fScrolledComposite = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL);
+ fScrolledComposite.setExpandHorizontal(true);
+ fScrolledComposite.setExpandVertical(true);
+ fListComposite = new Composite(fScrolledComposite, SWT.NONE);
+ fScrolledComposite.setContent(fListComposite);
+
+ GridLayout gl = new GridLayout();
+ gl.marginHeight = 0;
+ gl.marginWidth = 0;
+ gl.verticalSpacing = 1;
+ fListComposite.setLayout(gl);
+
+ fColorSettings = new ArrayList<>(Arrays.asList(ColorSettingsManager.getColorSettings()));
+ for (ColorSetting colorSetting : fColorSettings) {
+ new ColorSettingRow(fListComposite, colorSetting);
+ }
+
+ fFillerComposite = new Composite(fListComposite, SWT.NONE);
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gd.heightHint = 0;
+ fFillerComposite.setLayoutData(gd);
+ gl = new GridLayout();
+ gl.marginHeight = 1;
+ gl.marginWidth = 1;
+ fFillerComposite.setLayout(gl);
+ Label fillerLabel = new Label(fFillerComposite, SWT.NONE);
+ fillerLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ fillerLabel.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ fFillerComposite.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ if (fSelectedRow == null) {
+ Color lineColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ Point p = fFillerComposite.getSize();
+ GC gc = e.gc;
+ gc.setForeground(lineColor);
+ gc.drawLine(0, 0, p.x - 1, 0);
+ }
+ }
+ });
+
+ MouseListener mouseListener = new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ fSelectedRow = null;
+ refresh();
+ }
+ };
+ fillerLabel.addMouseListener(mouseListener);
+
+ fScrolledComposite.setMinSize(fListComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ fillToolBar();
+ }
+
+ @Override
+ public void setFocus() {
+ fScrolledComposite.setFocus();
+ }
+
+ /**
+ * Refreshes the view display and updates the view actions enablements.
+ */
+ public void refresh() {
+ fListComposite.layout();
+ fScrolledComposite.setMinSize(fListComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+ fListComposite.redraw(0, 0, fListComposite.getBounds().width, fListComposite.getBounds().height, true);
+ if (fSelectedRow == null) {
+ fDeleteAction.setEnabled(false);
+ fMoveUpAction.setEnabled(false);
+ fMoveDownAction.setEnabled(false);
+ } else {
+ fDeleteAction.setEnabled(true);
+ fMoveUpAction.setEnabled(true);
+ fMoveDownAction.setEnabled(true);
+ }
+ }
+
+ private void fillToolBar() {
+
+ fAddAction = new AddAction();
+ fAddAction.setImageDescriptor(ImageDescriptor.createFromImage(ADD_IMAGE));
+ fAddAction.setToolTipText(Messages.ColorsView_AddActionToolTipText);
+
+ fDeleteAction = new DeleteAction();
+ fDeleteAction.setImageDescriptor(ImageDescriptor.createFromImage(DELETE_IMAGE));
+ fDeleteAction.setToolTipText(Messages.ColorsView_DeleteActionToolTipText);
+ fDeleteAction.setEnabled(false);
+
+ fMoveUpAction = new MoveUpAction();
+ fMoveUpAction.setImageDescriptor(ImageDescriptor.createFromImage(MOVE_UP_IMAGE));
+ fMoveUpAction.setToolTipText(Messages.ColorsView_MoveUpActionToolTipText);
+ fMoveUpAction.setEnabled(false);
+
+ fMoveDownAction = new MoveDownAction();
+ fMoveDownAction.setImageDescriptor(ImageDescriptor.createFromImage(MOVE_DOWN_IMAGE));
+ fMoveDownAction.setToolTipText(Messages.ColorsView_MoveDownActionToolTipText);
+ fMoveDownAction.setEnabled(false);
+
+ fExportAction = new ExportAction();
+ fExportAction.setImageDescriptor(ImageDescriptor.createFromImage(EXPORT_IMAGE));
+ fExportAction.setToolTipText(Messages.ColorsView_ExportActionToolTipText);
+
+ fImportAction = new ImportAction();
+ fImportAction.setImageDescriptor(ImageDescriptor.createFromImage(IMPORT_IMAGE));
+ fImportAction.setToolTipText(Messages.ColorsView_ImportActionToolTipText);
+
+ IActionBars bars = getViewSite().getActionBars();
+ IToolBarManager manager = bars.getToolBarManager();
+ manager.add(fAddAction);
+ manager.add(fDeleteAction);
+ manager.add(fMoveUpAction);
+ manager.add(fMoveDownAction);
+ manager.add(new Separator());
+ manager.add(fExportAction);
+ manager.add(fImportAction);
+ }
+
+ private class AddAction extends Action {
+ @Override
+ public void run() {
+ ColorSetting colorSetting = new ColorSetting(
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND).getRGB(),
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB(),
+ Display.getDefault().getSystemColor(SWT.COLOR_LIST_FOREGROUND).getRGB(),
+ null);
+ ColorSettingRow row = new ColorSettingRow(fListComposite, colorSetting);
+ if (fSelectedRow == null) {
+ fColorSettings.add(colorSetting);
+ row.moveAbove(fFillerComposite);
+ } else {
+ fColorSettings.add(fColorSettings.indexOf(fSelectedRow.getColorSetting()), colorSetting);
+ row.moveAbove(fSelectedRow);
+ }
+ fSelectedRow = row;
+ refresh();
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+
+ private class DeleteAction extends Action {
+
+ @Override
+ public void run() {
+ if (fSelectedRow != null) {
+ int index = fColorSettings.indexOf(fSelectedRow.getColorSetting());
+ fColorSettings.remove(index);
+ fSelectedRow.fColorSetting.dispose();
+ fSelectedRow.dispose();
+ if (index < fColorSettings.size()) {
+ fSelectedRow = (ColorSettingRow) fListComposite.getChildren()[index];
+ } else {
+ fSelectedRow = null;
+ }
+ refresh();
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+ }
+
+ private class MoveUpAction extends Action {
+ @Override
+ public void run() {
+ if (fSelectedRow != null) {
+ int index = fColorSettings.indexOf(fSelectedRow.getColorSetting());
+ if (index > 0) {
+ fColorSettings.add(index - 1, fColorSettings.remove(index));
+ fSelectedRow.moveAbove(fListComposite.getChildren()[index - 1]);
+ refresh();
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+ }
+ }
+
+ private class MoveDownAction extends Action {
+ @Override
+ public void run() {
+ if (fSelectedRow != null) {
+ int index = fColorSettings.indexOf(fSelectedRow.getColorSetting());
+ if (index < fColorSettings.size() - 1) {
+ fColorSettings.add(index + 1, fColorSettings.remove(index));
+
+ fSelectedRow.moveBelow(fListComposite.getChildren()[index + 1]);
+ refresh();
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+ }
+ }
+
+ private class ExportAction extends Action {
+ @Override
+ public void run() {
+ FileDialog fileDialog = new FileDialog(fShell, SWT.SAVE);
+ fileDialog.setFilterExtensions(new String[] {"*.xml"}); //$NON-NLS-1$
+ fileDialog.setOverwrite(true);
+ String pathName = fileDialog.open();
+ if (pathName != null) {
+ ColorSettingsXML.save(pathName, fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+ }
+
+ private class ImportAction extends Action {
+ @Override
+ public void run() {
+ FileDialog fileDialog = new FileDialog(fShell, SWT.OPEN);
+ fileDialog.setFilterExtensions(new String[] {"*.xml"}); //$NON-NLS-1$
+ String pathName = fileDialog.open();
+ if (pathName != null) {
+ ColorSetting[] colorSettings = ColorSettingsXML.load(pathName);
+ if (colorSettings.length > 0) {
+ if (fColorSettings.size() > 0) {
+ boolean overwrite = MessageDialog.openQuestion(fShell,
+ Messages.ColorsView_ImportOverwriteDialogTitle,
+ Messages.ColorsView_ImportOverwriteDialogMessage1 +
+ Messages.ColorsView_ImportOverwriteDialogMessage2);
+ if (overwrite) {
+ for (Control control : fListComposite.getChildren()) {
+ if (control instanceof ColorSettingRow) {
+ ((ColorSettingRow) control).fColorSetting.dispose();
+ control.dispose();
+ }
+ }
+ fColorSettings = new ArrayList<>();
+ fSelectedRow = null;
+ }
+ }
+ for (ColorSetting colorSetting : colorSettings) {
+ ColorSettingRow row = new ColorSettingRow(fListComposite, colorSetting);
+ if (fSelectedRow == null) {
+ fColorSettings.add(colorSetting);
+ row.moveAbove(fFillerComposite);
+ } else {
+ fColorSettings.add(fColorSettings.indexOf(fSelectedRow.getColorSetting()), colorSetting);
+ row.moveAbove(fSelectedRow);
+ }
+ }
+ refresh();
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ }
+ }
+ }
+ }
+
+ private class ColorSettingRow extends Composite {
+
+ ColorSetting fColorSetting;
+
+ public ColorSettingRow(final Composite parent, final ColorSetting colorSetting) {
+ super(parent, SWT.NONE);
+ fColorSetting = colorSetting;
+
+ setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ GridLayout gl = new GridLayout(7, false);
+ gl.marginHeight = 1;
+ gl.marginWidth = 1;
+ gl.horizontalSpacing = 1;
+ gl.verticalSpacing = 0;
+ setLayout(gl);
+
+ final Button fgButton = new Button(this, SWT.PUSH);
+ fgButton.setText(Messages.ColorsView_ForegroundButtonText);
+ fgButton.setSize(fgButton.computeSize(SWT.DEFAULT, 19));
+ fgButton.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ final Button bgButton = new Button(this, SWT.PUSH);
+ bgButton.setText(Messages.ColorsView_BackgroundButtonText);
+ bgButton.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ final Composite labelComposite = new Composite(this, SWT.NONE);
+ labelComposite.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false));
+ gl = new GridLayout();
+ gl.marginHeight = 0;
+ gl.marginWidth = 0;
+ labelComposite.setLayout(gl);
+ labelComposite.setBackground(colorSetting.getBackgroundColor());
+
+ final Label label = new Label(labelComposite, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, true));
+ label.setText(" Text "); //$NON-NLS-1$
+ label.setForeground(colorSetting.getForegroundColor());
+ label.setBackground(colorSetting.getBackgroundColor());
+
+ fgButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fSelectedRow = ColorSettingRow.this;
+ refresh();
+ ColorDialog dialog = new ColorDialog(fShell);
+ dialog.setRGB(colorSetting.getForegroundRGB());
+ dialog.setText(Messages.ColorsView_ForegroundDialogText);
+ dialog.open();
+ RGB rgb = dialog.getRGB();
+ if (rgb != null) {
+ colorSetting.setForegroundRGB(rgb);
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ label.setForeground(colorSetting.getForegroundColor());
+ }
+ }});
+
+ bgButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fSelectedRow = ColorSettingRow.this;
+ refresh();
+ ColorDialog dialog = new ColorDialog(fShell);
+ dialog.setRGB(colorSetting.getBackgroundRGB());
+ dialog.setText(Messages.ColorsView_BackgroundDialogText);
+ dialog.open();
+ RGB rgb = dialog.getRGB();
+ if (rgb != null) {
+ colorSetting.setBackgroundRGB(rgb);
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ labelComposite.setBackground(colorSetting.getBackgroundColor());
+ label.setBackground(colorSetting.getBackgroundColor());
+ }
+ }});
+
+ final Button tickButton = new Button(this, SWT.PUSH);
+ tickButton.setText(Messages.ColorsView_TickButtonText);
+ tickButton.setSize(tickButton.computeSize(SWT.DEFAULT, 19));
+ tickButton.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ final Canvas tickCanvas = new Canvas(this, SWT.NONE);
+ GridData gd = new GridData(SWT.CENTER, SWT.FILL, false, false);
+ gd.widthHint = 12;
+ gd.heightHint = bgButton.getSize().y;
+ tickCanvas.setLayoutData(gd);
+ tickCanvas.setBackground(traceColorScheme.getBkColor(false, false, false));
+ tickCanvas.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ Rectangle bounds = tickCanvas.getBounds();
+ e.gc.setForeground(traceColorScheme.getColor(TimeGraphColorScheme.MID_LINE));
+ int midy = bounds.y + bounds.height / 2 - 1;
+ //int midy = e.y + e.height / 2;
+ e.gc.drawLine(e.x, midy, e.x + e.width, midy);
+ Rectangle rect = new Rectangle(e.x + 1, bounds.y + 2, 0, bounds.height - 6);
+ for (int i = 1; i <= 3; i++) {
+ rect.x += i;
+ rect.width = i;
+ e.gc.setBackground(fColorSetting.getTickColor());
+ e.gc.fillRectangle(rect);
+ }
+ }});
+
+ tickButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fSelectedRow = ColorSettingRow.this;
+ ColorDialog dialog = new ColorDialog(fShell);
+ dialog.setRGB(colorSetting.getTickColorRGB());
+ dialog.setText(Messages.TickColorDialog_TickColorDialogTitle);
+ dialog.open();
+ RGB rgb = dialog.getRGB();
+ if (rgb != null) {
+ colorSetting.setTickColorRGB(rgb);
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ refresh();
+ }
+ }});
+
+ final Button filterButton = new Button(this, SWT.PUSH);
+ filterButton.setText(Messages.ColorsView_FilterButtonText);
+ filterButton.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+
+ final Label filterText = new Label(this, SWT.NONE);
+ if (colorSetting.getFilter() != null) {
+ filterText.setText(colorSetting.getFilter().toString());
+ filterText.setToolTipText(colorSetting.getFilter().toString());
+ }
+ filterText.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
+ filterText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ filterButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fSelectedRow = ColorSettingRow.this;
+ refresh();
+ FilterDialog dialog = new FilterDialog(fShell);
+ dialog.setFilter(colorSetting.getFilter());
+ dialog.open();
+ if (dialog.getReturnCode() == Window.OK) {
+ if (dialog.getFilter() != null) {
+ colorSetting.setFilter(dialog.getFilter());
+ filterText.setText(dialog.getFilter().toString());
+ filterText.setToolTipText(dialog.getFilter().toString());
+ } else {
+ colorSetting.setFilter(null);
+ filterText.setText(""); //$NON-NLS-1$
+ filterText.setToolTipText(""); //$NON-NLS-1$
+ }
+ ColorSettingsManager.setColorSettings(fColorSettings.toArray(new ColorSetting[0]));
+ refresh();
+ }
+ }});
+
+ addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ if (fSelectedRow == ColorSettingRow.this) {
+ Color borderColor = Display.getDefault().getSystemColor(SWT.COLOR_BLACK);
+ Point p = ColorSettingRow.this.getSize();
+ Rectangle rect = new Rectangle(0, 0, p.x - 1, p.y - 1);
+ GC gc = e.gc;
+ gc.setForeground(borderColor);
+ gc.drawRectangle(rect);
+ }
+ }
+ });
+
+ MouseListener mouseListener = new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ fSelectedRow = ColorSettingRow.this;
+ refresh();
+ }
+ };
+ addMouseListener(mouseListener);
+ label.addMouseListener(mouseListener);
+ tickCanvas.addMouseListener(mouseListener);
+ filterText.addMouseListener(mouseListener);
+ }
+
+ /**
+ * @return the ColorSetting
+ */
+ public ColorSetting getColorSetting() {
+ return fColorSetting;
+ }
+
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/IColorSettingsListener.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/IColorSettingsListener.java
new file mode 100644
index 0000000000..629dbf1c79
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/colors/IColorSettingsListener.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.colors;
+
+/**
+ * A color change listener
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public interface IColorSettingsListener {
+
+ /**
+ * Notify the listener that the color settings have changed.
+ *
+ * @param colorSettings
+ * The new color settings
+ */
+ void colorSettingsChanged(ColorSetting[] colorSettings);
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/BaseDistributionData.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/BaseDistributionData.java
new file mode 100644
index 0000000000..3d9201ae60
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/BaseDistributionData.java
@@ -0,0 +1,243 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ ******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.distribution.model;
+
+/**
+ * Class with basic distribution data used for distribution models.
+ *
+ * It stores number of events (with timestamp) in buckets with a start time and a
+ * certain duration. The duration is the same across all buckets.
+ * Note that Timestamps are stored as long values.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class BaseDistributionData {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Constant indication that bucket is not filled.
+ */
+ public final static int OUT_OF_RANGE_BUCKET = -1;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Number of buckets
+ */
+ protected final int fNbBuckets;
+ /**
+ * Duration of each bucket
+ */
+ protected long fBucketDuration;
+ /**
+ * Bucket index of last event time
+ */
+ protected int fLastBucket;
+ /**
+ * Timestamp of the first bucket. (could be negative when analyzing events with descending time!!!)
+ */
+ protected long fFirstBucketTime;
+ /**
+ * Timestamp of the first event
+ */
+ protected long fFirstEventTime;
+ /**
+ * Timestamp of the last event
+ */
+ protected long fLastEventTime;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a base distribution data object.
+ * @param nbBuckets A total number of buckets
+ */
+ public BaseDistributionData(int nbBuckets) {
+ fNbBuckets = nbBuckets;
+ clear();
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+ /**
+ * Returns the total number of buckets.
+ *
+ * @return the number of buckets.
+ */
+ public int getNbBuckets() {
+ return fNbBuckets;
+ }
+
+ /**
+ * Returns the duration of buckets.
+ *
+ * @return bucket duration
+ */
+ public long getBucketDuration() {
+ return fBucketDuration;
+ }
+
+ /**
+ * Set the bucket duration.
+ *
+ * @param bucketDuration The duration to set.
+ */
+ public void setBucketDuration(long bucketDuration) {
+ fBucketDuration = bucketDuration;
+ }
+
+ /**
+ * Returns the index of the last used bucket.
+ *
+ * @return last bucket index.
+ */
+ public int getLastBucket() {
+ return fLastBucket;
+ }
+
+ /**
+ * Sets the index of the last bucket used.
+ *
+ * @param lastBucket The last bucket index to set.
+ */
+ public void setLastBucket(int lastBucket) {
+ fLastBucket = lastBucket;
+ }
+
+ /**
+ * Returns the start time of the first bucket.
+ *
+ * @return first bucket time.
+ */
+ public long getFirstBucketTime() {
+ return fFirstBucketTime;
+ }
+
+ /**
+ * Sets the start time of the first bucket.
+ *
+ * @param firstBucketTime The bucket time to ser.
+ */
+ public void setFirstBucketTime(long firstBucketTime) {
+ fFirstBucketTime = firstBucketTime;
+ }
+
+ /**
+ * Returns the start time of the last bucket used.
+ *
+ * @return the start time of the last bucket.
+ */
+ public long getLastBucketTime() {
+ return getBucketStartTime(fLastBucket);
+ }
+
+ /**
+ * Returns the time of the event with the lowest timestamp.
+ *
+ * @return first event time.
+ */
+ public long getFirstEventTime() {
+ return fFirstEventTime;
+ }
+
+ /**
+ * Sets the time of the event with the lowest timestamp.
+ *
+ * @param firstEventTime The first event time to set.
+ */
+ public void setFirstEventTime(long firstEventTime) {
+ fFirstEventTime = firstEventTime;
+ }
+
+ /**
+ * Returns the time of the event with the biggest timestamp.
+ *
+ * @return the last event time.
+ */
+ public long getLastEventTime() {
+ return fLastEventTime;
+ }
+
+ /**
+ * Sets the time of the event with the biggest timestamp.
+ *
+ * @param lastEventTime The last event time to set.
+ */
+ public void setLastEventTime(long lastEventTime) {
+ fLastEventTime = lastEventTime;
+ }
+
+ /**
+ * Returns the bucket start time of a given bucket index.
+ *
+ * @param index The bucket index.
+ * @return the bucket start time of a given bucket index.
+ */
+ public long getBucketStartTime(int index) {
+ return fFirstBucketTime + index * fBucketDuration;
+ }
+
+ /**
+ * Returns the bucket end time of a given bucket index.
+ *
+ * @param index The bucket index.
+ * @return the bucket start time of a given bucket index.
+ */
+ public long getBucketEndTime(int index) {
+ return getBucketStartTime(index) + fBucketDuration;
+ }
+
+ /**
+ * Returns the bucket index of the bucket containing a given time.
+ *
+ * @param time The timestamp to check.
+ * @return the bucket index of the bucket containing the given time.
+ */
+ public int getIndex(long time) {
+ return (int)((time - fFirstBucketTime) / fBucketDuration);
+ }
+
+ /**
+ * Check if an index is valid.
+ *
+ * @param index
+ * The index to check
+ * @return If it's valid, true or false.
+ */
+ public boolean isIndexValid(int index) {
+ return ((index >= 0) && (index <= fNbBuckets - 1));
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Clears the data model to default values.
+ */
+ public void clear() {
+ fFirstBucketTime = 0;
+ fFirstEventTime = 0;
+ fLastEventTime = 0;
+ fLastBucket = 0;
+ fBucketDuration = 1;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/IBaseDistributionModel.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/IBaseDistributionModel.java
new file mode 100644
index 0000000000..34ba642ec6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/distribution/model/IBaseDistributionModel.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.distribution.model;
+
+/**
+ * Base distribution model interface.
+ *
+ * Distribution models such histograms need to implement this interface.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ *
+ */
+public interface IBaseDistributionModel {
+ /**
+ * Complete the model (all data received)
+ */
+ void complete();
+
+ /**
+ * Clear the model (delete all data).
+ */
+ void clear();
+} \ No newline at end of file
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CopyHandler.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CopyHandler.java
new file mode 100644
index 0000000000..9acb2ced8f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CopyHandler.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Handler for copy command in filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ * @since 3.0
+ */
+public class CopyHandler extends AbstractHandler {
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return null;
+ }
+ IWorkbenchPage page = window.getActivePage();
+ FilterView part = (FilterView) page.getActivePart();
+ ISelection selection = getSelection(part);
+
+ LocalSelectionTransfer.getTransfer().setSelection(selection);
+ LocalSelectionTransfer.getTransfer().setSelectionSetTime(System.currentTimeMillis());
+ return null;
+ }
+
+ /**
+ * Retrieve the current selection
+ *
+ * @param tcv
+ * the FilterView
+ * @return the current selection in the FilterView
+ */
+ protected ISelection getSelection(FilterView tcv) {
+ return tcv.getViewSite().getSelectionProvider().getSelection();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return false;
+ }
+
+ // Get the selection
+ IWorkbenchPage page = window.getActivePage();
+ IWorkbenchPart part = page.getActivePart();
+ if (part instanceof FilterView) {
+ FilterView tcv = (FilterView) part;
+ ISelection selection = tcv.getSite().getSelectionProvider().getSelection();
+ if (!selection.isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CutHandler.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CutHandler.java
new file mode 100644
index 0000000000..f76396d0cc
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/CutHandler.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+
+/**
+ * Handler for cut command in filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ * @since 3.0
+ */
+public class CutHandler extends CopyHandler {
+
+ @Override
+ protected ISelection getSelection(FilterView tcv) {
+ ISelection sel = super.getSelection(tcv);
+ if (sel instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) sel;
+ Object o = selection.getFirstElement();
+ if (o instanceof ITmfFilterTreeNode) {
+ ITmfFilterTreeNode node = (ITmfFilterTreeNode) o;
+ node = node.remove();
+ tcv.refresh();
+ return new StructuredSelection(node);
+ }
+ }
+ return sel;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/DeleteHandler.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/DeleteHandler.java
new file mode 100644
index 0000000000..bb01f0eb34
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/DeleteHandler.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Handler for delete command in filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ * @since 3.0
+ */
+public class DeleteHandler extends AbstractHandler {
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return null;
+ }
+ IWorkbenchPage page = window.getActivePage();
+ FilterView part = (FilterView) page.getActivePart();
+ ISelection sel = part.getViewSite().getSelectionProvider().getSelection();
+ if (sel instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) sel;
+ Object o = selection.getFirstElement();
+ if (o instanceof ITmfFilterTreeNode) {
+ ITmfFilterTreeNode node = (ITmfFilterTreeNode) o;
+ node = node.remove();
+ part.refresh();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return false;
+ }
+
+ // Get the selection
+ IWorkbenchPage page = window.getActivePage();
+ IWorkbenchPart part = page.getActivePart();
+ if (part instanceof FilterView) {
+ FilterView tcv = (FilterView) part;
+ ISelection selection = tcv.getSite().getSelectionProvider().getSelection();
+ if (!selection.isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDialog.java
new file mode 100644
index 0000000000..43707c8d98
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDialog.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+
+/**
+ * The dialog for user-defined filters.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class FilterDialog extends Dialog {
+
+ TmfFilterNode fRoot;
+ FilterViewer fViewer;
+
+ /**
+ * Constructor.
+ *
+ * @param shell
+ * The shell to which this dialog is attached
+ */
+ public FilterDialog(Shell shell) {
+ super(shell);
+ setShellStyle(getShellStyle() | SWT.RESIZE | SWT.MAX);
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ getShell().setText(Messages.FilterDialog_FilterDialogTitle);
+ getShell().setMinimumSize(getShell().computeSize(500, 200));
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ fViewer = new FilterViewer(composite, SWT.BORDER);
+ fViewer.setInput(fRoot);
+ return composite;
+ }
+
+ /**
+ * @param filter
+ * the filter to set
+ */
+ public void setFilter(ITmfFilterTreeNode filter) {
+ fRoot = new TmfFilterNode(null);
+ if (filter != null) {
+ fRoot.addChild(filter.clone());
+ }
+ if (fViewer != null) {
+ fViewer.setInput(fRoot);
+ }
+ }
+
+ /**
+ * @return the filter
+ */
+ public ITmfFilterTreeNode getFilter() {
+ if (fRoot != null && fRoot.hasChildren()) {
+ return fRoot.getChild(0).clone();
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDragSourceAdapter.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDragSourceAdapter.java
new file mode 100644
index 0000000000..ef05bd431f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDragSourceAdapter.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSourceAdapter;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+
+/**
+ * DragSourceListener for filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ */
+class FilterDragSourceAdapter extends DragSourceAdapter {
+
+ private FilterViewer fViewer;
+
+ /**
+ * Constructor
+ *
+ * @param viewer
+ * the content of the FilterView
+ */
+ public FilterDragSourceAdapter(FilterViewer viewer) {
+ super();
+ this.fViewer = viewer;
+ }
+
+ @Override
+ public void dragStart(DragSourceEvent event) {
+ ISelection s = fViewer.getTreeViewer().getSelection();
+ LocalSelectionTransfer.getTransfer().setSelection(s);
+ LocalSelectionTransfer.getTransfer().setSelectionSetTime(event.time & 0xFFFFFFFFL);
+ }
+
+ @Override
+ public void dragSetData(DragSourceEvent event) {
+ event.data = LocalSelectionTransfer.getTransfer().getSelection();
+ }
+
+ @Override
+ public void dragFinished(DragSourceEvent event) {
+ if (event.detail == DND.DROP_MOVE) {
+ IStructuredSelection selection = (IStructuredSelection) LocalSelectionTransfer.getTransfer().getSelection();
+ for (Object data : selection.toList()) {
+ if (data instanceof ITmfFilterTreeNode) {
+ ITmfFilterTreeNode e = (ITmfFilterTreeNode) data;
+ e.remove();
+ fViewer.refresh();
+ }
+ }
+ }
+ LocalSelectionTransfer.getTransfer().setSelection(null);
+ LocalSelectionTransfer.getTransfer().setSelectionSetTime(0);
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDropTargetAdapter.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDropTargetAdapter.java
new file mode 100644
index 0000000000..557f77e670
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterDropTargetAdapter.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+
+/**
+ * DropTargetListener for filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ */
+class FilterDropTargetAdapter extends DropTargetAdapter {
+
+ private FilterViewer fViewer;
+
+ /**
+ * Constructor
+ * @param viewer the content of the FilterView
+ */
+ public FilterDropTargetAdapter(FilterViewer viewer) {
+ super();
+ this.fViewer = viewer;
+ }
+
+ /**
+ * Returns <code>true</code> if droppedNode is an ancestor of node.
+ *
+ * @param droppedNode
+ * the ITmfFilterTreeNode to drop or paste
+ * @param node
+ * the ITmfFilterTreeNode receiving a new child
+ * @return <code>true</code> if droppedNode is and ancestor of node,
+ * <code>false</code> otherwise.
+ */
+ private static boolean isAncestor(ITmfFilterTreeNode droppedNode, ITmfFilterTreeNode node) {
+ ITmfFilterTreeNode tmp = node;
+
+ while (tmp != null) {
+ ITmfFilterTreeNode n = tmp.getParent();
+ if (n == droppedNode) {
+ return true;
+ }
+ tmp = n;
+ }
+ return false;
+ }
+
+ @Override
+ public void dropAccept(DropTargetEvent event) {
+ ITmfFilterTreeNode treeNodeToDrop = null;
+ if (LocalSelectionTransfer.getTransfer().isSupportedType(event.currentDataType)) {
+ treeNodeToDrop = FilterEditUtils.getTransferredTreeNode();
+ }
+ if (treeNodeToDrop == null) {
+ // should never occur
+ event.detail = DND.DROP_NONE;
+ return;
+ }
+ if (event.item instanceof TreeItem) {
+ Object data = event.item.getData();
+ if (data instanceof ITmfFilterTreeNode) {
+ ITmfFilterTreeNode node = (ITmfFilterTreeNode) data;
+ if (node.getValidChildren().contains(treeNodeToDrop.getNodeName())) {
+ if (isAncestor(treeNodeToDrop, node) && event.detail != DND.DROP_COPY) {
+ // do nothing in this case
+ event.detail = DND.DROP_NONE;
+ }
+ return;
+ }
+ }
+ } else { // accept only TmfFilterNode
+ if (!TmfFilterNode.NODE_NAME.equals(treeNodeToDrop.getNodeName())) {
+ event.detail = DND.DROP_NONE;
+ }
+ return;
+ }
+ event.detail = DND.DROP_NONE;
+ return;
+ }
+
+ @Override
+ public void drop(DropTargetEvent event) {
+ ITmfFilterTreeNode treeNodeToDrop = FilterEditUtils.getTransferredTreeNode();
+ if (event.item instanceof TreeItem) {
+ Object data = event.item.getData();
+ if (data instanceof ITmfFilterTreeNode) {
+ ITmfFilterTreeNode node = (ITmfFilterTreeNode) data;
+ if (node.getValidChildren().contains(treeNodeToDrop.getNodeName())) {
+ treeNodeToDrop = treeNodeToDrop.clone();
+ node.addChild(treeNodeToDrop);
+ fViewer.refresh();
+ fViewer.setSelection(treeNodeToDrop, true);
+ return;
+ }
+ }
+ } else { // accept only TmfFilterNode
+ if (TmfFilterNode.NODE_NAME.equals(treeNodeToDrop.getNodeName())) {
+ ITmfFilterTreeNode root = fViewer.getInput();
+ treeNodeToDrop = treeNodeToDrop.clone();
+ root.addChild(treeNodeToDrop);
+ fViewer.refresh();
+ fViewer.setSelection(treeNodeToDrop, true);
+ return;
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterEditUtils.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterEditUtils.java
new file mode 100644
index 0000000000..7766d8f63c
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterEditUtils.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+
+/**
+ * Utilities for cut/copy/paste/dnd in filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ */
+class FilterEditUtils {
+
+ /**
+ * Gets the ITmfFilterTreeNode in LocalSelectionTransfer, if any
+ * @return a ITmfFilterTreeNode or <code>null</code>
+ */
+ public static ITmfFilterTreeNode getTransferredTreeNode() {
+ ITmfFilterTreeNode treeNodeToDrop = null;
+ ISelection sel = LocalSelectionTransfer.getTransfer().getSelection();
+ if (sel instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) sel;
+ for (Object data : selection.toList()) {
+ if (!(data instanceof ITmfFilterTreeNode)) {
+ return null;
+ } else if (treeNodeToDrop != null) {
+ // should never occur, since tree has SWT.SINGLE style
+ return null;
+ } else {
+ treeNodeToDrop = (ITmfFilterTreeNode) data;
+ }
+ }
+ }
+ return treeNodeToDrop;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterManager.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterManager.java
new file mode 100644
index 0000000000..fecd173708
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterManager.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterRootNode;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterXMLParser;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterXMLWriter;
+import org.xml.sax.SAXException;
+
+/**
+ * Central filter manager
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class FilterManager {
+
+ private static final String SAVED_FILTERS_FILE_NAME = "saved_filters.xml"; //$NON-NLS-1$
+ private static final String SAVED_FILTERS_PATH_NAME =
+ Activator.getDefault().getStateLocation().addTrailingSeparator().append(SAVED_FILTERS_FILE_NAME).toString();
+
+ private static ITmfFilterTreeNode fRoot = new TmfFilterRootNode();
+ static {
+ try {
+ fRoot = new TmfFilterXMLParser(SAVED_FILTERS_PATH_NAME).getTree();
+ } catch (FileNotFoundException e) {
+ } catch (SAXException e) {
+ Activator.getDefault().logError("Error parsing saved filter xml file: " + SAVED_FILTERS_PATH_NAME, e); //$NON-NLS-1$
+ } catch (IOException e) {
+ Activator.getDefault().logError("Error parsing saved filter xml file: " + SAVED_FILTERS_PATH_NAME, e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Retrieve the currently saved filters
+ *
+ * @return The array of filters
+ */
+ public static ITmfFilterTreeNode[] getSavedFilters() {
+ return fRoot.clone().getChildren();
+ }
+
+ /**
+ * Set the passed filters as the currently saved ones.
+ *
+ * @param filters
+ * The filters to save
+ */
+ public static void setSavedFilters(ITmfFilterTreeNode[] filters) {
+ fRoot = new TmfFilterRootNode();
+ for (ITmfFilterTreeNode filter : filters) {
+ fRoot.addChild(filter.clone());
+ }
+ try {
+ TmfFilterXMLWriter writerXML = new TmfFilterXMLWriter(fRoot);
+ writerXML.saveTree(SAVED_FILTERS_PATH_NAME);
+ } catch (ParserConfigurationException e) {
+ Activator.getDefault().logError("Error saving filter xml file: " + SAVED_FILTERS_PATH_NAME, e); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeContentProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeContentProvider.java
new file mode 100644
index 0000000000..ec9ec29cb9
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeContentProvider.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Yuriy Vashchuk - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import java.util.ArrayList;
+
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+
+/**
+ * This is the Content Provider of our tree
+ *
+ * @version 1.0
+ * @author Yuriy Vashchuk
+ */
+public class FilterTreeContentProvider implements ITreeContentProvider {
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof ITmfFilterTreeNode) {
+ ArrayList<ITmfFilterTreeNode> result = new ArrayList<>();
+ for (int i = 0; i < ((ITmfFilterTreeNode) inputElement).getChildrenCount(); i++) {
+ result.add(((ITmfFilterTreeNode) inputElement).getChild(i));
+ }
+
+ return result.toArray();
+ }
+ return null;
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ ArrayList<ITmfFilterTreeNode> result = new ArrayList<>();
+ for (int i = 0; i < ((ITmfFilterTreeNode) parentElement).getChildrenCount(); i++) {
+ result.add(((ITmfFilterTreeNode) parentElement).getChild(i));
+ }
+ return result.toArray();
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ return ((ITmfFilterTreeNode) element).getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ return ((ITmfFilterTreeNode) element).hasChildren();
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeLabelProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeLabelProvider.java
new file mode 100644
index 0000000000..53bb2caef1
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterTreeLabelProvider.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Yuriy Vashchuk - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterCompareNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterContainsNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterEqualsNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterEventTypeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterMatchesNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterOrNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterCompareNode.Type;
+
+/**
+ * This is the Label Provider for our Filter Tree
+ *
+ * @version 1.0
+ * @author Yuriy Vashchuk
+ */
+public class FilterTreeLabelProvider implements ILabelProvider {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void dispose() {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getText(Object element) {
+ String label = null;
+
+ if (element instanceof TmfFilterNode) {
+
+ TmfFilterNode node = (TmfFilterNode) element;
+ label = node.getNodeName() + " " + node.getFilterName(); //$NON-NLS-1$
+
+ } else if (element instanceof TmfFilterEventTypeNode) {
+
+ TmfFilterEventTypeNode node = (TmfFilterEventTypeNode) element;
+ label = "WITH " + node.getNodeName() + (node.getName() != null ? " " + node.getName() : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ } else if (element instanceof TmfFilterAndNode) {
+
+ TmfFilterAndNode node = (TmfFilterAndNode) element;
+ label = (node.isNot() ? "NOT " : "") + node.getNodeName(); //$NON-NLS-1$ //$NON-NLS-2$
+
+ } else if (element instanceof TmfFilterOrNode) {
+
+ TmfFilterOrNode node = (TmfFilterOrNode) element;
+ label = (node.isNot() ? "NOT " : "") + node.getNodeName(); //$NON-NLS-1$ //$NON-NLS-2$
+
+ } else if (element instanceof TmfFilterContainsNode) {
+
+ TmfFilterContainsNode node = (TmfFilterContainsNode) element;
+ label = (node.isNot() ? "NOT " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getField() != null ? node.getField() + " " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ node.getNodeName() +
+ (node.getValue() != null && node.getValue().length() > 0 ? " \"" + node.getValue() + "\"" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ } else if (element instanceof TmfFilterEqualsNode) {
+
+ TmfFilterEqualsNode node = (TmfFilterEqualsNode) element;
+ label = (node.isNot() ? "NOT " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getField() != null ? node.getField() + " " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ node.getNodeName() +
+ (node.getValue() != null && node.getValue().length() > 0 ? " \"" + node.getValue() + "\"" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ } else if (element instanceof TmfFilterMatchesNode) {
+
+ TmfFilterMatchesNode node = (TmfFilterMatchesNode) element;
+ label = (node.isNot() ? "NOT " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getField() != null ? node.getField() + " " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ node.getNodeName() +
+ (node.getRegex() != null && node.getRegex().length() > 0 ? " \"" + node.getRegex() + "\"" : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ } else if (element instanceof TmfFilterCompareNode) {
+
+ TmfFilterCompareNode node = (TmfFilterCompareNode) element;
+ label = (node.isNot() ? "NOT " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getField() != null ? node.getField() + " " : "") + //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getResult() < 0 ? "<" : (node.getResult() > 0 ? ">" : "=")) + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ (node.getValue() != null && node.getValue().length() > 0 ?
+ (node.getType() == Type.ALPHA ? " \"" + node.getValue() + "\"" : //$NON-NLS-1$ //$NON-NLS-2$
+ (node.getType() == Type.TIMESTAMP ? " [" + node.getValue() + "]" : //$NON-NLS-1$ //$NON-NLS-2$
+ " " + node.getValue())) : ""); //$NON-NLS-1$//$NON-NLS-2$
+
+ }
+ return label;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterView.java
new file mode 100644
index 0000000000..d3ee36c7eb
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterView.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Yuriy Vashchuk - Initial API and implementation
+ * Xavier Raynaud - add cut/copy/paste/dnd support
+ * based on Francois Chouinard ProjectView code.
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import java.io.IOException;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.resource.ImageDescriptor;
+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.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterRootNode;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterXMLParser;
+import org.eclipse.tracecompass.tmf.core.filter.xml.TmfFilterXMLWriter;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.ui.IActionBars;
+import org.xml.sax.SAXException;
+
+/**
+ * View that contain UI to the TMF filter.
+ *
+ * @version 1.0
+ * @author Yuriy Vashchuk
+ */
+public class FilterView extends TmfView {
+
+ /** ID for the Filter view */
+ public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.filter"; //$NON-NLS-1$
+
+ private static final Image SAVE_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/save_button.gif"); //$NON-NLS-1$
+ private static final Image ADD_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/add_button.gif"); //$NON-NLS-1$
+ private static final Image IMPORT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/import_button.gif"); //$NON-NLS-1$
+ private static final Image EXPORT_IMAGE = Activator.getDefault().getImageFromPath("/icons/elcl16/export_button.gif"); //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Main data structures
+ // ------------------------------------------------------------------------
+
+ private FilterViewer fViewer;
+ private final ITmfFilterTreeNode fRoot;
+
+ private final IWorkspace fWorkspace;
+
+ private SaveAction fSaveAction;
+ private AddAction fAddAction;
+ private ExportAction fExportAction;
+ private ImportAction fImportAction;
+
+ /**
+ * Getter for the Filter Tree Root
+ *
+ * @return The root of builded tree
+ */
+ public ITmfFilterTreeNode getFilterRoot() {
+ return fRoot;
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default Constructor
+ */
+ public FilterView() {
+ super("Filter"); //$NON-NLS-1$
+
+ fWorkspace = ResourcesPlugin.getWorkspace();
+ try {
+ fWorkspace.getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
+ } catch (CoreException e) {
+ Activator.getDefault().logError("Error refreshing workspace", e); //$NON-NLS-1$
+ }
+
+ fRoot = new TmfFilterRootNode();
+ for (ITmfFilterTreeNode node : FilterManager.getSavedFilters()) {
+ fRoot.addChild(node);
+ }
+ }
+
+ /**
+ * Add a filter to the FilterView. This does not modify the XML, which must
+ * be done manually. If the filter is already in the FilterView, this is a
+ * no-op.
+ *
+ * @param filter
+ * The filter to add.
+ * @since 3.1
+ */
+ public void addFilter(ITmfFilterTreeNode filter) {
+ ITmfFilterTreeNode root = fViewer.getInput();
+ for (ITmfFilterTreeNode node : root.getChildren()) {
+ if (node.equals(filter)) {
+ return;
+ }
+ }
+ root.addChild(filter);
+ fViewer.setInput(root);
+ }
+
+ /**
+ * Refresh the tree widget
+ */
+ public void refresh() {
+ fViewer.refresh();
+ }
+
+ /**
+ * Setter for selection
+ *
+ * @param node
+ * The node to select
+ */
+ public void setSelection(ITmfFilterTreeNode node) {
+ fViewer.setSelection(node, true);
+ }
+
+ // ------------------------------------------------------------------------
+ // ViewPart
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ fViewer = new FilterViewer(parent, SWT.NONE);
+ fViewer.setInput(fRoot);
+
+ contributeToActionBars();
+
+ fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (!(event.getSelection().isEmpty()) && event.getSelection() instanceof IStructuredSelection) {
+ fExportAction.setEnabled(true);
+ } else {
+ fExportAction.setEnabled(false);
+ }
+ }
+ });
+ this.getSite().setSelectionProvider(fViewer.getTreeViewer());
+
+ MenuManager menuManager = fViewer.getMenuManager();
+ this.getSite().registerContextMenu(menuManager, fViewer.getTreeViewer());
+ }
+
+ /**
+ * @return the ITmfFilterTreeNode currently selected
+ */
+ ITmfFilterTreeNode getSelection() {
+ return fViewer.getSelection();
+ }
+
+ @Override
+ public void setFocus() {
+ fViewer.setFocus();
+ }
+
+ @Override
+ public String toString() {
+ return "[FilterView]"; //$NON-NLS-1$
+ }
+
+ /**
+ * Builds the menu toolbar
+ */
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ // fillLocalPullDown(bars.getMenuManager());
+ fillLocalToolBar(bars.getToolBarManager());
+ }
+
+ /**
+ * Build the popup menu
+ *
+ * @param manager
+ * The manager to build
+ */
+ private void fillLocalToolBar(IToolBarManager manager) {
+
+ fSaveAction = new SaveAction();
+ fSaveAction.setImageDescriptor(ImageDescriptor.createFromImage(SAVE_IMAGE));
+ fSaveAction.setToolTipText(Messages.FilterView_SaveActionToolTipText);
+
+ fAddAction = new AddAction();
+ fAddAction.setImageDescriptor(ImageDescriptor.createFromImage(ADD_IMAGE));
+ fAddAction.setToolTipText(Messages.FilterView_AddActionToolTipText);
+
+ fExportAction = new ExportAction();
+ fExportAction.setImageDescriptor(ImageDescriptor.createFromImage(EXPORT_IMAGE));
+ fExportAction.setToolTipText(Messages.FilterView_ExportActionToolTipText);
+
+ fImportAction = new ImportAction();
+ fImportAction.setImageDescriptor(ImageDescriptor.createFromImage(IMPORT_IMAGE));
+ fImportAction.setToolTipText(Messages.FilterView_ImportActionToolTipText);
+
+ manager.add(fSaveAction);
+ manager.add(new Separator("add_delete")); //$NON-NLS-1$
+ manager.add(fAddAction);
+ manager.add(new Separator("edit")); //$NON-NLS-1$
+ manager.add(new Separator());
+ manager.add(fExportAction);
+ manager.add(fImportAction);
+ }
+
+ private class SaveAction extends Action {
+ @Override
+ public void run() {
+ FilterManager.setSavedFilters(fRoot.getChildren());
+ }
+ }
+
+ private class AddAction extends Action {
+ @Override
+ public void run() {
+
+ TmfFilterNode newNode = new TmfFilterNode(fRoot, ""); //$NON-NLS-1$
+ refresh();
+ setSelection(newNode);
+ }
+ }
+
+ private class ExportAction extends Action {
+ @Override
+ public void run() {
+ try {
+ FileDialog dlg = new FileDialog(new Shell(), SWT.SAVE);
+ dlg.setFilterNames(new String[] { Messages.FilterView_FileDialogFilterName + " (*.xml)" }); //$NON-NLS-1$
+ dlg.setFilterExtensions(new String[] { "*.xml" }); //$NON-NLS-1$
+
+ String fn = dlg.open();
+ if (fn != null) {
+ TmfFilterXMLWriter writerXML = new TmfFilterXMLWriter(fRoot);
+ writerXML.saveTree(fn);
+ }
+
+ } catch (ParserConfigurationException e) {
+ Activator.getDefault().logError("Error parsing filter xml file", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private class ImportAction extends Action {
+ @Override
+ public void run() {
+ if (fViewer != null) {
+ ITmfFilterTreeNode root = null;
+ try {
+ FileDialog dlg = new FileDialog(new Shell(), SWT.OPEN);
+ dlg.setFilterNames(new String[] { Messages.FilterView_FileDialogFilterName + " (*.xml)" }); //$NON-NLS-1$
+ dlg.setFilterExtensions(new String[] { "*.xml" }); //$NON-NLS-1$
+
+ TmfFilterXMLParser parserXML = null;
+ String fn = dlg.open();
+ if (fn != null) {
+ parserXML = new TmfFilterXMLParser(fn);
+ root = parserXML.getTree();
+ }
+
+ } catch (SAXException e) {
+ Activator.getDefault().logError("Error importing filter xml file", e); //$NON-NLS-1$
+ } catch (IOException e) {
+ Activator.getDefault().logError("Error importing filter xml file", e); //$NON-NLS-1$
+ }
+
+ if (root != null) {
+ for (ITmfFilterTreeNode node : root.getChildren()) {
+ if (node instanceof TmfFilterNode) {
+ fRoot.addChild(node);
+ refresh();
+ fViewer.setSelection(node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+} \ No newline at end of file
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterViewer.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterViewer.java
new file mode 100644
index 0000000000..af432330ae
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/FilterViewer.java
@@ -0,0 +1,1124 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Xavier Raynaud - add cut/copy/paste/dnd support
+ * Vincent Perot - Add subfield filtering
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.jface.action.Action;
+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.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSource;
+import org.eclipse.swt.dnd.DropTarget;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.FillLayout;
+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.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tracecompass.internal.tmf.ui.Messages;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventType;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterAndNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterCompareNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterContainsNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterEqualsNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterEventTypeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterMatchesNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterOrNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterRootNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterCompareNode.Type;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTxtEvent;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTxtTraceDefinition;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlEvent;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomXmlTraceDefinition;
+import org.eclipse.tracecompass.tmf.core.parsers.custom.CustomTraceDefinition.OutputColumn;
+import org.eclipse.tracecompass.tmf.core.project.model.TmfTraceType;
+
+class FilterViewer extends Composite {
+
+ private static final String SEP = " : "; //$NON-NLS-1$
+
+ private TreeViewer fViewer;
+
+ private Composite fComposite;
+ private MenuManager fMenuManager;
+
+ public FilterViewer(Composite parent, int style) {
+ super(parent, style);
+
+ setLayout(new FillLayout());
+ GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
+ setLayoutData(gd);
+
+ final SashForm sash = new SashForm(this, SWT.HORIZONTAL);
+
+ // Create the tree viewer to display the filter tree
+ fViewer = new TreeViewer(sash, SWT.NONE);
+ fViewer.setContentProvider(new FilterTreeContentProvider());
+ fViewer.setLabelProvider(new FilterTreeLabelProvider());
+ fViewer.setInput(new TmfFilterRootNode());
+
+ // Create the empty filter node properties panel
+ fComposite = new Composite(sash, SWT.NONE);
+ GridLayout gl = new GridLayout();
+ gl.marginHeight = 0;
+ gl.marginWidth = 0;
+ fComposite.setLayout(gl);
+
+ createContextMenu();
+
+ fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ if (!(event.getSelection().isEmpty()) && event.getSelection() instanceof IStructuredSelection) {
+ // Update the filter node properties panel to the selection
+ IStructuredSelection selection = (IStructuredSelection) event.getSelection();
+ ITmfFilterTreeNode node = (ITmfFilterTreeNode) selection.getFirstElement();
+ updateFilterNodeComposite(node);
+ // Highlight the selection's children
+ highlightTreeItems(fViewer.getTree().getSelection()[0].getItems());
+ } else {
+ updateFilterNodeComposite(null);
+ }
+ }
+ });
+
+ fViewer.getTree().addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ TmfFilterTreeNode root = (TmfFilterTreeNode) fViewer.getInput();
+ if (root == null || root.getChildrenCount() == 0) {
+ e.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+ e.gc.drawText(Messages.FilterViewer_EmptyTreeHintText, 5, 0);
+ }
+ }
+ });
+
+ int operations = DND.DROP_MOVE | DND.DROP_COPY;
+ DragSource dragSource = new org.eclipse.swt.dnd.DragSource(fViewer.getTree(), operations);
+ dragSource.setTransfer(new Transfer[] { LocalSelectionTransfer.getTransfer() });
+ dragSource.addDragListener(new FilterDragSourceAdapter(this));
+ DropTarget dropTarget = new DropTarget(fViewer.getTree(), operations);
+ dropTarget.setTransfer(new Transfer[] { LocalSelectionTransfer.getTransfer() });
+ dropTarget.addDropListener(new FilterDropTargetAdapter(this));
+ }
+
+ /**
+ * Create the context menu for the tree viewer
+ */
+ private void createContextMenu() {
+ // Adds root context menu
+ fMenuManager = new MenuManager();
+ fMenuManager.setRemoveAllWhenShown(true);
+ fMenuManager.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager) {
+ fillContextMenu(manager);
+ }
+ });
+
+ // Context
+ Menu contextMenu = fMenuManager.createContextMenu(fViewer.getTree());
+
+ // Publish it
+ fViewer.getTree().setMenu(contextMenu);
+ }
+
+ public MenuManager getMenuManager() {
+ return fMenuManager;
+ }
+
+ /**
+ * Fill the context menu for the tree viewer.
+ *
+ * @param manager
+ * The menu manager
+ */
+ protected void fillContextMenu(IMenuManager manager) {
+ final ISelection selection = fViewer.getSelection();
+ ITmfFilterTreeNode filterTreeNode = null;
+ if (selection instanceof StructuredSelection) {
+ Object element = ((StructuredSelection) selection).getFirstElement();
+ if (element instanceof ITmfFilterTreeNode) {
+ filterTreeNode = (ITmfFilterTreeNode) element;
+ }
+ }
+
+ if (filterTreeNode != null) {
+ fillContextMenuForNode(filterTreeNode, manager);
+ }
+ manager.add(new Separator("delete")); //$NON-NLS-1$
+ manager.add(new Separator("edit")); //$NON-NLS-1$
+
+ if (fViewer.getInput() instanceof TmfFilterRootNode || filterTreeNode == null) {
+ manager.add(new Separator());
+ ITmfFilterTreeNode root = (ITmfFilterTreeNode) fViewer.getInput();
+ fillContextMenuForNode(root, manager);
+ }
+ }
+
+ /**
+ * Fill the context menu with the valid children of the provided node
+ *
+ * @param node
+ * The target node
+ * @param manager
+ * The menu manager
+ */
+ protected void fillContextMenuForNode(final ITmfFilterTreeNode node, IMenuManager manager) {
+ for (final String child : node.getValidChildren()) {
+ final Action action = new Action() {
+ @Override
+ public void run() {
+ ITmfFilterTreeNode newNode = null;
+ if (TmfFilterNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterNode(node, ""); //$NON-NLS-1$
+ } else if (TmfFilterEventTypeNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterEventTypeNode(node);
+ } else if (TmfFilterAndNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterAndNode(node);
+ } else if (TmfFilterOrNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterOrNode(node);
+ } else if (TmfFilterContainsNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterContainsNode(node);
+ } else if (TmfFilterEqualsNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterEqualsNode(node);
+ } else if (TmfFilterMatchesNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterMatchesNode(node);
+ } else if (TmfFilterCompareNode.NODE_NAME.equals(child)) {
+ newNode = new TmfFilterCompareNode(node);
+ }
+ if (newNode != null) {
+ fViewer.refresh();
+ fViewer.setSelection(new StructuredSelection(newNode), true);
+ }
+ }
+ };
+ if (TmfFilterNode.NODE_NAME.equals(child)) {
+ action.setText(Messages.FilterViewer_NewPrefix + " " + child); //$NON-NLS-1$
+ } else {
+ action.setText(child);
+ }
+ manager.add(action);
+ }
+ }
+
+ /**
+ * Create the appropriate filter node properties composite
+ */
+ private void updateFilterNodeComposite(ITmfFilterTreeNode node) {
+ for (Control control : fComposite.getChildren()) {
+ control.dispose();
+ }
+
+ if (node instanceof TmfFilterNode) {
+ new FilterNodeComposite(fComposite, (TmfFilterNode) node);
+ } else if (node instanceof TmfFilterEventTypeNode) {
+ new FilterEventTypeNodeComposite(fComposite, (TmfFilterEventTypeNode) node);
+ } else if (node instanceof TmfFilterAndNode) {
+ new FilterAndNodeComposite(fComposite, (TmfFilterAndNode) node);
+ } else if (node instanceof TmfFilterOrNode) {
+ new FilterOrNodeComposite(fComposite, (TmfFilterOrNode) node);
+ } else if (node instanceof TmfFilterContainsNode) {
+ new FilterContainsNodeComposite(fComposite, (TmfFilterContainsNode) node);
+ } else if (node instanceof TmfFilterEqualsNode) {
+ new FilterEqualsNodeComposite(fComposite, (TmfFilterEqualsNode) node);
+ } else if (node instanceof TmfFilterMatchesNode) {
+ new FilterMatchesNodeComposite(fComposite, (TmfFilterMatchesNode) node);
+ } else if (node instanceof TmfFilterCompareNode) {
+ new FilterCompareNodeComposite(fComposite, (TmfFilterCompareNode) node);
+ } else {
+ new FilterBaseNodeComposite(fComposite);
+ }
+ fComposite.layout();
+ }
+
+ /**
+ * Highlight the provided tree items
+ */
+ private void highlightTreeItems(TreeItem[] items) {
+ resetTreeItems(fViewer.getTree().getItems());
+ for (TreeItem item : items) {
+ item.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
+ }
+
+ }
+
+ /**
+ * Reset the provided tree items (remove highlight)
+ */
+ private void resetTreeItems(TreeItem[] items) {
+ for (TreeItem item : items) {
+ item.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ resetTreeItems(item.getItems());
+ }
+ }
+
+ public void setInput(ITmfFilterTreeNode root) {
+ fViewer.setInput(root);
+ fViewer.expandAll();
+
+ updateFilterNodeComposite(null);
+ }
+
+ public ITmfFilterTreeNode getInput() {
+ return (ITmfFilterTreeNode) fViewer.getInput();
+ }
+
+ public void refresh() {
+ fViewer.refresh();
+ }
+
+ public void setSelection(ITmfFilterTreeNode node, boolean reveal) {
+ fViewer.setSelection(new StructuredSelection(node), reveal);
+ }
+
+ public void setSelection(ITmfFilterTreeNode node) {
+ fViewer.setSelection(new StructuredSelection(node));
+ }
+
+ public ITmfFilterTreeNode getSelection() {
+ final ISelection selection = fViewer.getSelection();
+ ITmfFilterTreeNode filterTreeNode = null;
+ if (selection instanceof StructuredSelection) {
+ Object element = ((StructuredSelection) selection).getFirstElement();
+ if (element instanceof ITmfFilterTreeNode) {
+ filterTreeNode = (ITmfFilterTreeNode) element;
+ }
+ }
+
+ final ITmfFilterTreeNode selectedNode = filterTreeNode;
+ return selectedNode;
+ }
+
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ fViewer.addSelectionChangedListener(listener);
+ }
+
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ fViewer.removeSelectionChangedListener(listener);
+ }
+
+ /**
+ * Gets the TreeViewer displaying filters
+ *
+ * @return a {@link TreeViewer}
+ */
+ TreeViewer getTreeViewer() {
+ return fViewer;
+ }
+
+ private class FilterBaseNodeComposite extends Composite {
+
+ FilterBaseNodeComposite(Composite parent) {
+ super(parent, SWT.NONE);
+ setLayout(new GridLayout(2, false));
+ setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ }
+
+ protected Map<String, Object> getEventsTypeMap() {
+ Map<String, Object> eventsTypeMap = new TreeMap<>();
+ for (IConfigurationElement ce : TmfTraceType.getTypeElements()) {
+ String categoryPrefix = ""; //$NON-NLS-1$
+ String categoryId = ce.getAttribute(TmfTraceType.CATEGORY_ATTR);
+ if (categoryId != null) {
+ categoryPrefix = TmfTraceType.getCategoryName(categoryId) + SEP;
+ }
+ String text = categoryPrefix + ce.getAttribute(TmfTraceType.NAME_ATTR);
+ eventsTypeMap.put(text, ce);
+ }
+ for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) {
+ String text = def.categoryName + SEP + def.definitionName;
+ eventsTypeMap.put(text, def);
+ }
+ for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) {
+ String text = def.categoryName + SEP + def.definitionName;
+ eventsTypeMap.put(text, def);
+ }
+ return eventsTypeMap;
+ }
+
+ protected String[] getFieldsList(ITmfFilterTreeNode node) {
+ ArrayList<String> fieldsList = new ArrayList<>();
+ ITmfFilterTreeNode curNode = node;
+ while (curNode != null) {
+ if (curNode instanceof TmfFilterEventTypeNode) {
+ TmfFilterEventTypeNode eventTypeNode = (TmfFilterEventTypeNode) curNode;
+ for (IConfigurationElement ce : TmfTraceType.getTypeElements()) {
+ if (ce.getAttribute(TmfTraceType.EVENT_TYPE_ATTR).equals(eventTypeNode.getEventType())) {
+ try {
+ ITmfEvent event = (ITmfEvent) ce.createExecutableExtension(TmfTraceType.EVENT_TYPE_ATTR);
+ ITmfEventType eventType = event.getType();
+ if (eventType != null) {
+ for (String field : eventType.getRootField().getFieldNames()) {
+ fieldsList.add(field);
+ }
+ }
+ } catch (CoreException e) {
+ }
+ if (fieldsList.size() == 0) {
+ fieldsList.add(ITmfEvent.EVENT_FIELD_TIMESTAMP);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_SOURCE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_TYPE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_REFERENCE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_CONTENT);
+ }
+ return fieldsList.toArray(new String[0]);
+ }
+ }
+ if (eventTypeNode.getEventType() != null && eventTypeNode.getEventType().startsWith(CustomTxtEvent.class.getCanonicalName())) {
+ for (CustomTxtTraceDefinition def : CustomTxtTraceDefinition.loadAll()) {
+ if (eventTypeNode.getEventType().equals(CustomTxtEvent.class.getCanonicalName() + ':' + def.categoryName + ':' + def.definitionName)) {
+ for (OutputColumn output : def.outputs) {
+ fieldsList.add(output.name);
+ }
+ return fieldsList.toArray(new String[0]);
+ }
+ }
+ }
+ if (eventTypeNode.getEventType() != null && eventTypeNode.getEventType().startsWith(CustomXmlEvent.class.getCanonicalName())) {
+ for (CustomXmlTraceDefinition def : CustomXmlTraceDefinition.loadAll()) {
+ if (eventTypeNode.getEventType().equals(CustomXmlEvent.class.getCanonicalName() + ':' + def.categoryName + ':' + def.definitionName)) {
+ for (OutputColumn output : def.outputs) {
+ fieldsList.add(output.name);
+ }
+ return fieldsList.toArray(new String[0]);
+ }
+ }
+ }
+ }
+ curNode = curNode.getParent();
+ }
+
+ fieldsList.add(Messages.FilterViewer_CommonCategory);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_TIMESTAMP);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_SOURCE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_TYPE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_REFERENCE);
+ fieldsList.add(ITmfEvent.EVENT_FIELD_CONTENT);
+ fieldsList.add(""); //$NON-NLS-1$
+
+ for (Entry<String, Object> eventTypeEntry : getEventsTypeMap().entrySet()) {
+ Object value = eventTypeEntry.getValue();
+ if (value instanceof IConfigurationElement) {
+ IConfigurationElement ce = (IConfigurationElement) value;
+ try {
+ ITmfEvent event = (ITmfEvent) ce.createExecutableExtension(TmfTraceType.EVENT_TYPE_ATTR);
+ ITmfEventType eventType = event.getType();
+ if (eventType != null && eventType.getFieldNames().size() > 0) {
+ String categoryId = ce.getAttribute(TmfTraceType.CATEGORY_ATTR);
+ if (categoryId != null) {
+ fieldsList.add('[' + TmfTraceType.getCategoryName(categoryId) + SEP
+ + ce.getAttribute(TmfTraceType.NAME_ATTR) + ']');
+ } else {
+ fieldsList.add('[' + ce.getAttribute(TmfTraceType.NAME_ATTR) + ']');
+ }
+ for (String field : eventType.getFieldNames()) {
+ fieldsList.add(field);
+ }
+ fieldsList.add(""); //$NON-NLS-1$
+ }
+ } catch (CoreException e) {
+ }
+ } else if (value instanceof CustomTraceDefinition) {
+ CustomTraceDefinition def = (CustomTraceDefinition) value;
+ if (def.outputs.size() > 0) {
+ fieldsList.add('[' + def.categoryName + SEP + def.definitionName + ']');
+ for (OutputColumn output : def.outputs) {
+ fieldsList.add(output.name);
+ }
+ fieldsList.add(""); //$NON-NLS-1$
+ }
+ }
+ }
+ return fieldsList.toArray(new String[0]);
+ }
+ }
+
+ private class FilterNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterNode fNode;
+ Text fNameText;
+
+ FilterNodeComposite(Composite parent, TmfFilterNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NameLabel);
+
+ fNameText = new Text(this, SWT.BORDER);
+ fNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (node.getFilterName() != null && node.getFilterName().length() > 0) {
+ fNameText.setText(node.getFilterName());
+ } else {
+ fNameText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fNameText.setText(Messages.FilterViewer_FilterNameHint);
+ }
+ fNameText.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (fNode.getFilterName() == null || fNode.getFilterName().length() == 0) {
+ fNameText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fNameText.setText(Messages.FilterViewer_FilterNameHint);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (fNameText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNameText.setText(""); //$NON-NLS-1$
+ }
+ fNameText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ }
+ });
+ fNameText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (!fNameText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNode.setFilterName(fNameText.getText());
+ fViewer.refresh(fNode);
+ }
+ }
+ });
+ }
+ }
+
+ private class FilterEventTypeNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterEventTypeNode fNode;
+ Combo fTypeCombo;
+ Map<String, Object> fEventsTypeMap;
+
+ FilterEventTypeNodeComposite(Composite parent, TmfFilterEventTypeNode node) {
+ super(parent);
+ fNode = node;
+ fEventsTypeMap = getEventsTypeMap();
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_TypeLabel);
+
+ fTypeCombo = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY);
+ fTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fTypeCombo.setItems(fEventsTypeMap.keySet().toArray(new String[0]));
+ if (fNode.getEventType() != null) {
+ fTypeCombo.setText(fNode.getName());
+ }
+ fTypeCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ for (Entry<String, Object> eventTypeEntry : fEventsTypeMap.entrySet()) {
+ if (eventTypeEntry.getKey().equals(fTypeCombo.getText())) {
+ Object value = eventTypeEntry.getValue();
+ if (value instanceof IConfigurationElement) {
+ IConfigurationElement ce = (IConfigurationElement) value;
+ fNode.setEventType(ce.getAttribute(TmfTraceType.EVENT_TYPE_ATTR));
+ String categoryId = ce.getAttribute(TmfTraceType.CATEGORY_ATTR);
+ if (categoryId != null) {
+ fNode.setName(TmfTraceType.getCategoryName(categoryId) + SEP
+ + ce.getAttribute(TmfTraceType.NAME_ATTR));
+ } else {
+ fNode.setName(ce.getAttribute(TmfTraceType.NAME_ATTR));
+ }
+ } else if (value instanceof CustomTxtTraceDefinition) {
+ CustomTxtTraceDefinition def = (CustomTxtTraceDefinition) value;
+ fNode.setEventType(CustomTxtEvent.class.getCanonicalName() + ':' + def.categoryName + ':' + def.definitionName);
+ fNode.setName(def.categoryName + SEP + def.definitionName);
+ } else if (value instanceof CustomXmlTraceDefinition) {
+ CustomXmlTraceDefinition def = (CustomXmlTraceDefinition) value;
+ fNode.setEventType(CustomXmlEvent.class.getCanonicalName() + ':' + def.categoryName + ':' + def.definitionName);
+ fNode.setName(def.categoryName + SEP + def.definitionName);
+ }
+ fViewer.refresh(fNode);
+ break;
+ }
+ }
+ }
+ });
+ }
+ }
+
+ private class FilterAndNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterAndNode fNode;
+ Button fNotButton;
+
+ FilterAndNodeComposite(Composite parent, TmfFilterAndNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+ }
+ }
+
+ private class FilterOrNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterOrNode fNode;
+ Button fNotButton;
+
+ FilterOrNodeComposite(Composite parent, TmfFilterOrNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+ }
+ }
+
+ private class FilterContainsNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterContainsNode fNode;
+ Button fNotButton;
+ Combo fFieldCombo;
+ Text fValueText;
+ Button fIgnoreCaseButton;
+
+ FilterContainsNodeComposite(Composite parent, TmfFilterContainsNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_FieldLabel);
+
+ fFieldCombo = new Combo(this, SWT.DROP_DOWN);
+ fFieldCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fFieldCombo.setItems(getFieldsList(fNode));
+ fFieldCombo.setToolTipText(Messages.FilterViewer_Subfilter_ToolTip);
+ if (fNode.getField() != null) {
+ fFieldCombo.setText(fNode.getField());
+ }
+ fFieldCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ fNode.setField(fFieldCombo.getText());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_ValueLabel);
+
+ fValueText = new Text(this, SWT.BORDER);
+ fValueText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (node.getValue() != null && node.getValue().length() > 0) {
+ fValueText.setText(node.getValue());
+ } else {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ fValueText.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (fNode.getValue() == null || fNode.getValue().length() == 0) {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fValueText.setText(""); //$NON-NLS-1$
+ }
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ }
+ });
+ fValueText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (!fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNode.setValue(fValueText.getText());
+ fViewer.refresh(fNode);
+ }
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+
+ fIgnoreCaseButton = new Button(this, SWT.CHECK);
+ fIgnoreCaseButton.setSelection(fNode.isIgnoreCase());
+ fIgnoreCaseButton.setText(Messages.FilterViewer_IgnoreCaseButtonText);
+ fIgnoreCaseButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fIgnoreCaseButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setIgnoreCase(fIgnoreCaseButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+ }
+ }
+
+ private class FilterEqualsNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterEqualsNode fNode;
+ Button fNotButton;
+ Combo fFieldCombo;
+ Text fValueText;
+ Button fIgnoreCaseButton;
+
+ FilterEqualsNodeComposite(Composite parent, TmfFilterEqualsNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_FieldLabel);
+
+ fFieldCombo = new Combo(this, SWT.DROP_DOWN);
+ fFieldCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fFieldCombo.setItems(getFieldsList(fNode));
+ fFieldCombo.setToolTipText(Messages.FilterViewer_Subfilter_ToolTip);
+ if (fNode.getField() != null) {
+ fFieldCombo.setText(fNode.getField());
+ }
+ fFieldCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ fNode.setField(fFieldCombo.getText());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_ValueLabel);
+
+ fValueText = new Text(this, SWT.BORDER);
+ fValueText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (node.getValue() != null && node.getValue().length() > 0) {
+ fValueText.setText(node.getValue());
+ } else {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ fValueText.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (fNode.getValue() == null || fNode.getValue().length() == 0) {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fValueText.setText(""); //$NON-NLS-1$
+ }
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ }
+ });
+ fValueText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (!fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNode.setValue(fValueText.getText());
+ fViewer.refresh(fNode);
+ }
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+
+ fIgnoreCaseButton = new Button(this, SWT.CHECK);
+ fIgnoreCaseButton.setSelection(fNode.isIgnoreCase());
+ fIgnoreCaseButton.setText(Messages.FilterViewer_IgnoreCaseButtonText);
+ fIgnoreCaseButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fIgnoreCaseButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setIgnoreCase(fIgnoreCaseButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+ }
+ }
+
+ private class FilterMatchesNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterMatchesNode fNode;
+ Button fNotButton;
+ Combo fFieldCombo;
+ Text fRegexText;
+
+ FilterMatchesNodeComposite(Composite parent, TmfFilterMatchesNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_FieldLabel);
+
+ fFieldCombo = new Combo(this, SWT.DROP_DOWN);
+ fFieldCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fFieldCombo.setItems(getFieldsList(fNode));
+ fFieldCombo.setToolTipText(Messages.FilterViewer_Subfilter_ToolTip);
+ if (fNode.getField() != null) {
+ fFieldCombo.setText(fNode.getField());
+ }
+ fFieldCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ fNode.setField(fFieldCombo.getText());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_RegexLabel);
+
+ fRegexText = new Text(this, SWT.BORDER);
+ fRegexText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (node.getRegex() != null && node.getRegex().length() > 0) {
+ fRegexText.setText(node.getRegex());
+ } else {
+ fRegexText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fRegexText.setText(Messages.FilterViewer_RegexHint);
+ }
+ fRegexText.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (fNode.getRegex() == null || fNode.getRegex().length() == 0) {
+ fRegexText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fRegexText.setText(Messages.FilterViewer_RegexHint);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (fRegexText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fRegexText.setText(""); //$NON-NLS-1$
+ }
+ fRegexText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ }
+ });
+ fRegexText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (!fRegexText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNode.setRegex(fRegexText.getText());
+ fViewer.refresh(fNode);
+ }
+ }
+ });
+ }
+ }
+
+ private class FilterCompareNodeComposite extends FilterBaseNodeComposite {
+ TmfFilterCompareNode fNode;
+ Button fNotButton;
+ Combo fFieldCombo;
+ Text fValueText;
+ Button fLTButton;
+ Button fEQButton;
+ Button fGTButton;
+ Button fNumButton;
+ Button fAlphaButton;
+ Button fTimestampButton;
+
+ FilterCompareNodeComposite(Composite parent, TmfFilterCompareNode node) {
+ super(parent);
+ fNode = node;
+
+ Label label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_NotLabel);
+
+ fNotButton = new Button(this, SWT.CHECK);
+ fNotButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNotButton.setSelection(fNode.isNot());
+ fNotButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fNode.setNot(fNotButton.getSelection());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_FieldLabel);
+
+ fFieldCombo = new Combo(this, SWT.DROP_DOWN);
+ fFieldCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ fFieldCombo.setItems(getFieldsList(fNode));
+ fFieldCombo.setToolTipText(Messages.FilterViewer_Subfilter_ToolTip);
+ if (fNode.getField() != null) {
+ fFieldCombo.setText(fNode.getField());
+ }
+ fFieldCombo.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ fNode.setField(fFieldCombo.getText());
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_ResultLabel);
+
+ Composite resultGroup = new Composite(this, SWT.NONE);
+ GridLayout rggl = new GridLayout(3, true);
+ rggl.marginHeight = 0;
+ rggl.marginWidth = 0;
+ resultGroup.setLayout(rggl);
+ resultGroup.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+
+ fLTButton = new Button(resultGroup, SWT.RADIO);
+ fLTButton.setSelection(fNode.getResult() < 0);
+ fLTButton.setText("<"); //$NON-NLS-1$
+ fLTButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fLTButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fLTButton.getSelection()) {
+ fNode.setResult(-1);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ fEQButton = new Button(resultGroup, SWT.RADIO);
+ fEQButton.setSelection(fNode.getResult() == 0);
+ fEQButton.setText("="); //$NON-NLS-1$
+ fEQButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fEQButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fEQButton.getSelection()) {
+ fNode.setResult(0);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ fGTButton = new Button(resultGroup, SWT.RADIO);
+ fGTButton.setSelection(fNode.getResult() > 0);
+ fGTButton.setText(">"); //$NON-NLS-1$
+ fGTButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fGTButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fGTButton.getSelection()) {
+ fNode.setResult(1);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_TypeLabel);
+
+ Composite typeGroup = new Composite(this, SWT.NONE);
+ GridLayout tggl = new GridLayout(3, false);
+ tggl.marginHeight = 0;
+ tggl.marginWidth = 0;
+ typeGroup.setLayout(tggl);
+ typeGroup.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+
+ fNumButton = new Button(typeGroup, SWT.RADIO);
+ fNumButton.setSelection(fNode.getType() == Type.NUM);
+ fNumButton.setText(Messages.FilterViewer_NumButtonText);
+ fNumButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fNumButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fNumButton.getSelection()) {
+ fNode.setType(Type.NUM);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ fAlphaButton = new Button(typeGroup, SWT.RADIO);
+ fAlphaButton.setSelection(fNode.getType() == Type.ALPHA);
+ fAlphaButton.setText(Messages.FilterViewer_AlphaButtonText);
+ fAlphaButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fAlphaButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fAlphaButton.getSelection()) {
+ fNode.setType(Type.ALPHA);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ fTimestampButton = new Button(typeGroup, SWT.RADIO);
+ fTimestampButton.setSelection(fNode.getType() == Type.TIMESTAMP);
+ fTimestampButton.setText(Messages.FilterViewer_TimestampButtonText);
+ fTimestampButton.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ fTimestampButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fTimestampButton.getSelection()) {
+ fNode.setType(Type.TIMESTAMP);
+ }
+ fViewer.refresh(fNode);
+ }
+ });
+
+ label = new Label(this, SWT.NONE);
+ label.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
+ label.setText(Messages.FilterViewer_ValueLabel);
+
+ fValueText = new Text(this, SWT.BORDER);
+ fValueText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ if (node.getValue() != null && node.getValue().length() > 0) {
+ fValueText.setText(node.getValue());
+ } else {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ fValueText.addFocusListener(new FocusListener() {
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (fNode.getValue() == null || fNode.getValue().length() == 0) {
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
+ fValueText.setText(Messages.FilterViewer_ValueHint);
+ }
+ }
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ if (fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fValueText.setText(""); //$NON-NLS-1$
+ }
+ fValueText.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
+ }
+ });
+ fValueText.addModifyListener(new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ if (!fValueText.getForeground().equals(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY))) {
+ fNode.setValue(fValueText.getText());
+ fViewer.refresh(fNode);
+ }
+ }
+ });
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/PasteHandler.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/PasteHandler.java
new file mode 100644
index 0000000000..f34a986659
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/filter/PasteHandler.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.filter;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.tracecompass.tmf.core.filter.model.ITmfFilterTreeNode;
+import org.eclipse.tracecompass.tmf.core.filter.model.TmfFilterNode;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Handler for paste command in filter view
+ * @author Xavier Raynaud <xavier.raynaud@kalray.eu>
+ * @since 3.0
+ */
+public class PasteHandler extends AbstractHandler {
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return null;
+ }
+
+ // Get the selection
+ IWorkbenchPage page = window.getActivePage();
+ IWorkbenchPart part = page.getActivePart();
+ if (!(part instanceof FilterView)) {
+ return null;
+ }
+ FilterView v = (FilterView) part;
+
+ ITmfFilterTreeNode objectToPaste = FilterEditUtils.getTransferredTreeNode();
+ objectToPaste = objectToPaste.clone();
+ ITmfFilterTreeNode sel = v.getSelection();
+ if (sel == null || TmfFilterNode.NODE_NAME.equals(objectToPaste.getNodeName())) {
+ sel = v.getFilterRoot();
+ }
+
+ sel.addChild(objectToPaste);
+ v.refresh();
+ v.setSelection(objectToPaste);
+ return null;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ // Check if we are closing down
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ return false;
+ }
+
+ // Get the selection
+ IWorkbenchPage page = window.getActivePage();
+ IWorkbenchPart part = page.getActivePart();
+ if (!(part instanceof FilterView)) {
+ return false;
+ }
+ FilterView v = (FilterView) part;
+ ITmfFilterTreeNode sel = v.getSelection();
+ if (sel == null) {
+ sel = v.getFilterRoot();
+ }
+ ITmfFilterTreeNode objectToPaste = FilterEditUtils.getTransferredTreeNode();
+ if (objectToPaste != null &&
+ (sel.getValidChildren().contains(objectToPaste.getNodeName())
+ || TmfFilterNode.NODE_NAME.equals(objectToPaste.getNodeName()))) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/FullTraceHistogram.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/FullTraceHistogram.java
new file mode 100644
index 0000000000..0d75887f7a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/FullTraceHistogram.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
+ * Patrick Tasse - Update for mouse wheel zoom
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A histogram widget that displays the event distribution of a whole trace.
+ * <p>
+ * It also features a selected range window that can be dragged and zoomed.
+ *
+ * @version 1.1
+ * @author Francois Chouinard
+ */
+public class FullTraceHistogram extends Histogram {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ private final HistogramZoom fZoom;
+
+ private long fRangeStartTime = 0L;
+ private long fRangeDuration;
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ /**
+ * Full Constructor
+ *
+ * @param view A reference to the parent histogram view
+ * @param parent A reference to the parent composite
+ */
+ public FullTraceHistogram(HistogramView view, Composite parent) {
+ super(view, parent);
+ fZoom = new HistogramZoom(this, getStartTime(), getTimeLimit());
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void clear() {
+ fRangeStartTime = 0L;
+ fRangeDuration = 0L;
+ if (fZoom != null) {
+ fZoom.setFullRange(0L, 0L);
+ fZoom.setNewRange(0L, 0L);
+ }
+ super.clear();
+ }
+
+ /**
+ * Sets the time range of the full histogram.
+ *
+ * @param startTime A start time
+ * @param endTime A end time
+ */
+ public void setFullRange(long startTime, long endTime) {
+ fZoom.setFullRange(startTime, endTime);
+ fZoom.setNewRange(fRangeStartTime, fRangeDuration);
+ }
+
+ /**
+ * Sets the selected time range.
+ *
+ * @param startTime The histogram start time
+ * @param duration The histogram duration
+ */
+ public void setTimeRange(long startTime, long duration) {
+ fRangeStartTime = startTime;
+ fRangeDuration = duration;
+ fZoom.setNewRange(fRangeStartTime, fRangeDuration);
+ fDataModel.complete();
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseListener
+ // ------------------------------------------------------------------------
+
+ private int fStartDelta;
+ private boolean fMouseMoved;
+
+ @Override
+ public void mouseDown(MouseEvent event) {
+ if (fScaledData != null && fDragState == DRAG_NONE && fDataModel.getStartTime() < fDataModel.getEndTime()) {
+ if (event.button == 2 || (event.button == 1 && (event.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL)) {
+ fDragState = DRAG_RANGE;
+ fDragButton = event.button;
+ int center = (int) (((fRangeStartTime + fRangeDuration / 2) - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
+ fStartDelta = center - event.x;
+ fMouseMoved = false;
+ return;
+ } else if (event.button == 3) {
+ fDragState = DRAG_ZOOM;
+ fDragButton = event.button;
+ long time = Math.min(getTimestamp(event.x), getEndTime());
+ if ((event.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
+ if (time < fRangeStartTime + fRangeDuration / 2) {
+ fRangeStartTime = fRangeStartTime + fRangeDuration;
+ }
+ } else {
+ fRangeStartTime = time;
+ }
+ fRangeDuration = time - fRangeStartTime;
+ fCanvas.redraw();
+ return;
+ }
+ }
+ super.mouseDown(event);
+ }
+
+ @Override
+ public void mouseUp(MouseEvent event) {
+ if (fDragState == DRAG_RANGE && event.button == fDragButton) {
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ if (!fMouseMoved) {
+ // if single click without move, center on the click
+ long startTime = getTimestamp(event.x) - fRangeDuration / 2;
+ fRangeStartTime = Math.max(getStartTime(), Math.min(getEndTime() - fRangeDuration, startTime));
+ }
+ ((HistogramView) fParentView).updateTimeRange(fRangeStartTime, fRangeStartTime + fRangeDuration);
+ return;
+ } else if (fDragState == DRAG_ZOOM && event.button == fDragButton) {
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ if (fRangeDuration < 0) {
+ fRangeStartTime = fRangeStartTime + fRangeDuration;
+ fRangeDuration = -fRangeDuration;
+ }
+ if (fRangeDuration > 0) {
+ ((HistogramView) fParentView).updateTimeRange(fRangeStartTime, fRangeStartTime + fRangeDuration);
+ } else {
+ fRangeStartTime = fZoom.getStartTime();
+ fRangeDuration = fZoom.getDuration();
+ fCanvas.redraw();
+ }
+ return;
+ }
+ super.mouseUp(event);
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseMoveListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseMove(MouseEvent event) {
+ if (fDragState == DRAG_RANGE) {
+ int center = event.x + fStartDelta;
+ long newStart = getTimestamp(center) - fRangeDuration / 2;
+ fRangeStartTime = Math.max(getStartTime(), Math.min(getEndTime() - fRangeDuration, newStart));
+ fCanvas.redraw();
+ fMouseMoved = true;
+ return;
+ } else if (fDragState == DRAG_ZOOM) {
+ long endTime = Math.max(getStartTime(), Math.min(getEndTime(), getTimestamp(event.x)));
+ fRangeDuration = endTime - fRangeStartTime;
+ fCanvas.redraw();
+ return;
+ }
+ super.mouseMove(event);
+ }
+
+ // ------------------------------------------------------------------------
+ // PaintListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void paintControl(PaintEvent event) {
+ super.paintControl(event);
+
+ Image image = (Image) fCanvas.getData(IMAGE_KEY);
+ assert image != null;
+
+ Image rangeRectangleImage = new Image(image.getDevice(), image, SWT.IMAGE_COPY);
+ GC rangeWindowGC = new GC(rangeRectangleImage);
+
+ if ((fScaledData != null) && (fRangeDuration != 0 || fDragState == DRAG_ZOOM)) {
+ drawTimeRangeWindow(rangeWindowGC, fRangeStartTime, fRangeDuration);
+ }
+
+ // Draws the buffer image onto the canvas.
+ event.gc.drawImage(rangeRectangleImage, 0, 0);
+
+ rangeWindowGC.dispose();
+ rangeRectangleImage.dispose();
+ }
+
+ /**
+ * Get the histogram zoom
+ * @return the histogram zoom
+ * @since 2.0
+ */
+ public HistogramZoom getZoom() {
+ return fZoom;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Histogram.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Histogram.java
new file mode 100644
index 0000000000..25a778d144
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Histogram.java
@@ -0,0 +1,1045 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
+ * Francois Chouinard - Reformat histogram labels on format change
+ * Patrick Tasse - Support selection range
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+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.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.MouseWheelListener;
+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.FontData;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampDelta;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+
+/**
+ * Re-usable histogram widget.
+ *
+ * It has the following features:
+ * <ul>
+ * <li>Y-axis labels displaying min/max count values
+ * <li>X-axis labels displaying time range
+ * <li>a histogram displaying the distribution of values over time (note that
+ * the histogram might not necessarily fill the whole canvas)
+ * </ul>
+ * The widget also has 2 'markers' to identify:
+ * <ul>
+ * <li>a red dashed line over the bar that contains the currently selected event
+ * <li>a dark red dashed line that delimits the right end of the histogram (if
+ * it doesn't fill the canvas)
+ * </ul>
+ * Clicking on the histogram will select the current event at the mouse
+ * location.
+ * <p>
+ * Once the histogram is selected, there is some limited keyboard support:
+ * <ul>
+ * <li>Home: go to the first histogram bar
+ * <li>End: go to the last histogram bar
+ * <li>Left: go to the previous histogram
+ * <li>Right: go to the next histogram bar
+ * </ul>
+ * Finally, when the mouse hovers over the histogram, a tool tip showing the
+ * following information about the corresponding histogram bar time range:
+ * <ul>
+ * <li>start of the time range
+ * <li>end of the time range
+ * <li>number of events in that time range
+ * </ul>
+ *
+ * @version 1.1
+ * @author Francois Chouinard
+ */
+public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseMoveListener, MouseTrackListener, IHistogramModelListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ // Histogram colors
+
+ // System colors, they do not need to be disposed
+ private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
+ private final Color fSelectionForegroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_BLUE);
+ private final Color fSelectionBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+ private final Color fLastEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
+
+ // Application colors, they need to be disposed
+ private final Color[] fHistoBarColors = new Color[] {new Color(Display.getDefault(), 90, 90, 255), // blue
+ new Color(Display.getDefault(), 0, 240, 0), // green
+ new Color(Display.getDefault(), 255, 0, 0), // red
+ new Color(Display.getDefault(), 0, 255, 255), // cyan
+ new Color(Display.getDefault(), 255, 80, 255), // magenta
+ new Color(Display.getDefault(), 200, 200, 0), // yellow
+ new Color(Display.getDefault(), 200, 150, 0), // brown
+ new Color(Display.getDefault(), 150, 255, 150), // light green
+ new Color(Display.getDefault(), 200, 80, 80), // dark red
+ new Color(Display.getDefault(), 30, 150, 150), // dark cyan
+ new Color(Display.getDefault(), 200, 200, 255), // light blue
+ new Color(Display.getDefault(), 0, 120, 0), // dark green
+ new Color(Display.getDefault(), 255, 150, 150), // lighter red
+ new Color(Display.getDefault(), 140, 80, 140), // dark magenta
+ new Color(Display.getDefault(), 150, 100, 50), // brown
+ new Color(Display.getDefault(), 255, 80, 80), // light red
+ new Color(Display.getDefault(), 200, 200, 200), // light grey
+ new Color(Display.getDefault(), 255, 200, 80), // orange
+ new Color(Display.getDefault(), 255, 255, 80), // pale yellow
+ new Color(Display.getDefault(), 255, 200, 200), // pale red
+ new Color(Display.getDefault(), 255, 200, 255), // pale magenta
+ new Color(Display.getDefault(), 255, 255, 200), // pale pale yellow
+ new Color(Display.getDefault(), 200, 255, 255), // pale pale blue
+ };
+ private final Color fTimeRangeColor = new Color(Display.getCurrent(), 255, 128, 0);
+ private final Color fLostEventColor = new Color(Display.getCurrent(), 208, 62, 120);
+
+ // Drag states
+ /**
+ * No drag in progress
+ * @since 2.2
+ */
+ protected final int DRAG_NONE = 0;
+ /**
+ * Drag the selection
+ * @since 2.2
+ */
+ protected final int DRAG_SELECTION = 1;
+ /**
+ * Drag the time range
+ * @since 2.2
+ */
+ protected final int DRAG_RANGE = 2;
+ /**
+ * Drag the zoom range
+ * @since 2.2
+ */
+ protected final int DRAG_ZOOM = 3;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The parent TMF view.
+ */
+ protected TmfView fParentView;
+
+ private Composite fComposite;
+ private Font fFont;
+
+ // Histogram text fields
+ private Label fMaxNbEventsLabel;
+ private Label fMinNbEventsLabel;
+ private Label fTimeRangeStartLabel;
+ private Label fTimeRangeEndLabel;
+
+ /**
+ * Histogram drawing area
+ */
+ protected Canvas fCanvas;
+
+ /**
+ * The histogram data model.
+ */
+ protected final HistogramDataModel fDataModel;
+
+ /**
+ * The histogram data model scaled to current resolution and screen width.
+ */
+ protected HistogramScaledData fScaledData;
+
+ /**
+ * The current event value
+ */
+ protected long fCurrentEventTime = 0L;
+
+ /**
+ * The current selection begin time
+ */
+ private long fSelectionBegin = 0L;
+
+ /**
+ * The current selection end time
+ */
+ private long fSelectionEnd = 0L;
+
+ /**
+ * The drag state
+ * @see #DRAG_NONE
+ * @see #DRAG_SELECTION
+ * @see #DRAG_RANGE
+ * @see #DRAG_ZOOM
+ * @since 2.2
+ */
+ protected int fDragState = DRAG_NONE;
+
+ /**
+ * The button that started a mouse drag, or 0 if no drag in progress
+ * @since 2.2
+ */
+ protected int fDragButton = 0;
+
+ /**
+ * The bucket display offset
+ */
+ private int fOffset = 0;
+
+ /**
+ * show the traces or not
+ * @since 3.0
+ */
+ static boolean showTraces = true;
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ /**
+ * Full constructor.
+ *
+ * @param view A reference to the parent TMF view.
+ * @param parent A parent composite
+ */
+ public Histogram(final TmfView view, final Composite parent) {
+ fParentView = view;
+
+ fComposite = createWidget(parent);
+ fDataModel = new HistogramDataModel();
+ fDataModel.addHistogramListener(this);
+ clear();
+
+ fCanvas.addControlListener(this);
+ fCanvas.addPaintListener(this);
+ fCanvas.addKeyListener(this);
+ fCanvas.addMouseListener(this);
+ fCanvas.addMouseTrackListener(this);
+ fCanvas.addMouseMoveListener(this);
+
+ TmfSignalManager.register(this);
+ }
+
+ /**
+ * Dispose resources and unregisters listeners.
+ */
+ public void dispose() {
+ TmfSignalManager.deregister(this);
+ fLostEventColor.dispose();
+ for (Color c : fHistoBarColors) {
+ c.dispose();
+ }
+ fTimeRangeColor.dispose();
+ fFont.dispose();
+ fDataModel.removeHistogramListener(this);
+ fDataModel.dispose();
+ }
+
+ private Composite createWidget(final Composite parent) {
+
+ fFont = adjustFont(parent);
+
+ final int initalWidth = 10;
+
+ // --------------------------------------------------------------------
+ // Define the histogram
+ // --------------------------------------------------------------------
+
+ final GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 3;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.marginTop = 0;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginLeft = 0;
+ gridLayout.marginRight = 0;
+ final Composite composite = new Composite(parent, SWT.FILL);
+ composite.setLayout(gridLayout);
+
+ // Use all the horizontal space
+ GridData gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.FILL;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.grabExcessVerticalSpace = true;
+ composite.setLayoutData(gridData);
+
+ // Y-axis max event
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.RIGHT;
+ gridData.verticalAlignment = SWT.TOP;
+ fMaxNbEventsLabel = new Label(composite, SWT.RIGHT);
+ fMaxNbEventsLabel.setFont(fFont);
+ fMaxNbEventsLabel.setText("0"); //$NON-NLS-1$
+ fMaxNbEventsLabel.setLayoutData(gridData);
+
+ // Histogram itself
+ Composite canvasComposite = new Composite(composite, SWT.BORDER);
+ gridData = new GridData();
+ gridData.horizontalSpan = 2;
+ gridData.verticalSpan = 2;
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.FILL;
+ gridData.heightHint = 0;
+ gridData.widthHint = 0;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.grabExcessVerticalSpace = true;
+ canvasComposite.setLayoutData(gridData);
+ canvasComposite.setLayout(new FillLayout());
+ fCanvas = new Canvas(canvasComposite, SWT.DOUBLE_BUFFERED);
+ fCanvas.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ Object image = fCanvas.getData(IMAGE_KEY);
+ if (image instanceof Image) {
+ ((Image) image).dispose();
+ }
+ }
+ });
+
+ // Y-axis min event (always 0...)
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.RIGHT;
+ gridData.verticalAlignment = SWT.BOTTOM;
+ fMinNbEventsLabel = new Label(composite, SWT.RIGHT);
+ fMinNbEventsLabel.setFont(fFont);
+ fMinNbEventsLabel.setText("0"); //$NON-NLS-1$
+ fMinNbEventsLabel.setLayoutData(gridData);
+
+ // Dummy cell
+ gridData = new GridData(initalWidth, SWT.DEFAULT);
+ gridData.horizontalAlignment = SWT.RIGHT;
+ gridData.verticalAlignment = SWT.BOTTOM;
+ final Label dummyLabel = new Label(composite, SWT.NONE);
+ dummyLabel.setLayoutData(gridData);
+
+ // Window range start time
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.LEFT;
+ gridData.verticalAlignment = SWT.BOTTOM;
+ fTimeRangeStartLabel = new Label(composite, SWT.NONE);
+ fTimeRangeStartLabel.setFont(fFont);
+ fTimeRangeStartLabel.setLayoutData(gridData);
+
+ // Window range end time
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.RIGHT;
+ gridData.verticalAlignment = SWT.BOTTOM;
+ fTimeRangeEndLabel = new Label(composite, SWT.NONE);
+ fTimeRangeEndLabel.setFont(fFont);
+ fTimeRangeEndLabel.setLayoutData(gridData);
+
+ return composite;
+ }
+
+ private static Font adjustFont(final Composite composite) {
+ // Reduce font size for a more pleasing rendering
+ final int fontSizeAdjustment = -2;
+ final Font font = composite.getFont();
+ final FontData fontData = font.getFontData()[0];
+ return new Font(font.getDevice(), fontData.getName(), fontData.getHeight() + fontSizeAdjustment, fontData.getStyle());
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the start time (equal first bucket time)
+ * @return the start time.
+ */
+ public long getStartTime() {
+ return fDataModel.getFirstBucketTime();
+ }
+
+ /**
+ * Returns the end time.
+ * @return the end time.
+ */
+ public long getEndTime() {
+ return fDataModel.getEndTime();
+ }
+
+ /**
+ * Returns the time limit (end of last bucket)
+ * @return the time limit.
+ */
+ public long getTimeLimit() {
+ return fDataModel.getTimeLimit();
+ }
+
+ /**
+ * Returns a data model reference.
+ * @return data model.
+ */
+ public HistogramDataModel getDataModel() {
+ return fDataModel;
+ }
+
+ /**
+ * Set the max number events to be displayed
+ *
+ * @param maxNbEvents
+ * the maximum number of events
+ */
+ void setMaxNbEvents(long maxNbEvents) {
+ fMaxNbEventsLabel.setText(Long.toString(maxNbEvents));
+ fMaxNbEventsLabel.getParent().layout();
+ fCanvas.redraw();
+ }
+
+ /**
+ * Return <code>true</code> if the traces must be displayed in the histogram,
+ * <code>false</code> otherwise.
+ * @return whether the traces should be displayed
+ * @since 3.0
+ */
+ public boolean showTraces() {
+ return showTraces && fDataModel.getNbTraces() < getMaxNbTraces();
+ }
+
+ /**
+ * Returns the maximum number of traces the histogram can display with separate colors.
+ * If there is more traces, histogram will use only one color to display them.
+ * @return the maximum number of traces the histogram can display.
+ * @since 3.0
+ */
+ public int getMaxNbTraces() {
+ return fHistoBarColors.length;
+ }
+
+ /**
+ * Returns the color used to display the trace at the given index.
+ * @param traceIndex a trace index
+ * @return a {@link Color}
+ * @since 3.0
+ */
+ public Color getTraceColor(int traceIndex) {
+ return fHistoBarColors[traceIndex % fHistoBarColors.length];
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+ /**
+ * Updates the time range.
+ * @param startTime A start time
+ * @param endTime A end time.
+ */
+ public void updateTimeRange(long startTime, long endTime) {
+ if (fDragState == DRAG_NONE) {
+ ((HistogramView) fParentView).updateTimeRange(startTime, endTime);
+ }
+ }
+
+ /**
+ * Clear the histogram and reset the data
+ */
+ public void clear() {
+ fDataModel.clear();
+ if (fDragState == DRAG_SELECTION) {
+ updateSelectionTime();
+ }
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ synchronized (fDataModel) {
+ fScaledData = null;
+ }
+ }
+
+ /**
+ * Sets the current selection time range and refresh the display
+ *
+ * @param beginTime The begin time of the current selection
+ * @param endTime The end time of the current selection
+ * @since 2.1
+ */
+ public void setSelection(final long beginTime, final long endTime) {
+ fSelectionBegin = (beginTime > 0) ? beginTime : 0;
+ fSelectionEnd = (endTime > 0) ? endTime : 0;
+ fDataModel.setSelectionNotifyListeners(beginTime, endTime);
+ }
+
+ /**
+ * Computes the timestamp of the bucket at [offset]
+ *
+ * @param offset offset from the left on the histogram
+ * @return the start timestamp of the corresponding bucket
+ */
+ public synchronized long getTimestamp(final int offset) {
+ assert offset > 0 && offset < fScaledData.fWidth;
+ try {
+ return fScaledData.fFirstBucketTime + fScaledData.fBucketDuration * offset;
+ } catch (final Exception e) {
+ return 0; // TODO: Fix that racing condition (NPE)
+ }
+ }
+
+ /**
+ * Computes the offset of the timestamp in the histogram
+ *
+ * @param timestamp the timestamp
+ * @return the offset of the corresponding bucket (-1 if invalid)
+ */
+ public synchronized int getOffset(final long timestamp) {
+ if (timestamp < fDataModel.getFirstBucketTime() || timestamp > fDataModel.getEndTime()) {
+ return -1;
+ }
+ return (int) ((timestamp - fDataModel.getFirstBucketTime()) / fScaledData.fBucketDuration);
+ }
+
+ /**
+ * Set the bucket display offset
+ *
+ * @param offset
+ * the bucket display offset
+ * @since 2.2
+ */
+ protected void setOffset(final int offset) {
+ fOffset = offset;
+ }
+
+ /**
+ * Move the currently selected bar cursor to a non-empty bucket.
+ *
+ * @param keyCode the SWT key code
+ */
+ protected void moveCursor(final int keyCode) {
+
+ int index;
+ switch (keyCode) {
+
+ case SWT.HOME:
+ index = 0;
+ while (index < fScaledData.fLastBucket && fScaledData.fData[index].isEmpty()) {
+ index++;
+ }
+ if (index < fScaledData.fLastBucket) {
+ fScaledData.fSelectionBeginBucket = index;
+ }
+ break;
+
+ case SWT.ARROW_RIGHT:
+ index = Math.max(0, fScaledData.fSelectionBeginBucket + 1);
+ while (index < fScaledData.fWidth && fScaledData.fData[index].isEmpty()) {
+ index++;
+ }
+ if (index < fScaledData.fLastBucket) {
+ fScaledData.fSelectionBeginBucket = index;
+ }
+ break;
+
+ case SWT.END:
+ index = fScaledData.fLastBucket;
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
+ index--;
+ }
+ if (index >= 0) {
+ fScaledData.fSelectionBeginBucket = index;
+ }
+ break;
+
+ case SWT.ARROW_LEFT:
+ index = Math.min(fScaledData.fLastBucket - 1, fScaledData.fSelectionBeginBucket - 1);
+ while (index >= 0 && fScaledData.fData[index].isEmpty()) {
+ index--;
+ }
+ if (index >= 0) {
+ fScaledData.fSelectionBeginBucket = index;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ fScaledData.fSelectionEndBucket = fScaledData.fSelectionBeginBucket;
+ fSelectionBegin = getTimestamp(fScaledData.fSelectionBeginBucket);
+ fSelectionEnd = fSelectionBegin;
+ updateSelectionTime();
+ }
+
+ /**
+ * Refresh the histogram display
+ */
+ @Override
+ public void modelUpdated() {
+ if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) {
+ fCanvas.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!fCanvas.isDisposed()) {
+ // Retrieve and normalize the data
+ final int canvasWidth = fCanvas.getBounds().width;
+ final int canvasHeight = fCanvas.getBounds().height;
+ if (canvasWidth <= 0 || canvasHeight <= 0) {
+ return;
+ }
+ fDataModel.setSelection(fSelectionBegin, fSelectionEnd);
+ fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight, 1);
+ synchronized (fDataModel) {
+ if (fScaledData != null) {
+ fCanvas.redraw();
+ // Display histogram and update X-,Y-axis labels
+ updateRangeTextControls();
+ long maxNbEvents = HistogramScaledData.hideLostEvents ? fScaledData.fMaxValue : fScaledData.fMaxCombinedValue;
+ fMaxNbEventsLabel.setText(Long.toString(maxNbEvents));
+ // The Y-axis area might need to be re-sized
+ GridData gd = (GridData) fMaxNbEventsLabel.getLayoutData();
+ gd.widthHint = Math.max(gd.widthHint, fMaxNbEventsLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x);
+ fMaxNbEventsLabel.getParent().layout();
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Add a mouse wheel listener to the histogram
+ * @param listener the mouse wheel listener
+ * @since 2.0
+ */
+ public void addMouseWheelListener(MouseWheelListener listener) {
+ fCanvas.addMouseWheelListener(listener);
+ }
+
+ /**
+ * Remove a mouse wheel listener from the histogram
+ * @param listener the mouse wheel listener
+ * @since 2.0
+ */
+ public void removeMouseWheelListener(MouseWheelListener listener) {
+ fCanvas.removeMouseWheelListener(listener);
+ }
+
+ /**
+ * Add a key listener to the histogram
+ * @param listener the key listener
+ * @since 3.1
+ */
+ public void addKeyListener(KeyListener listener) {
+ fCanvas.addKeyListener(listener);
+ }
+
+ /**
+ * Remove a key listener from the histogram
+ * @param listener the key listener
+ * @since 3.1
+ */
+ public void removeKeyListener(KeyListener listener) {
+ fCanvas.removeKeyListener(listener);
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper functions
+ // ------------------------------------------------------------------------
+
+ private void updateSelectionTime() {
+ if (fSelectionBegin > fSelectionEnd) {
+ long end = fSelectionBegin;
+ fSelectionBegin = fSelectionEnd;
+ fSelectionEnd = end;
+ }
+ ((HistogramView) fParentView).updateSelectionTime(fSelectionBegin, fSelectionEnd);
+ }
+
+ /**
+ * Update the range text controls
+ */
+ private void updateRangeTextControls() {
+ if (fDataModel.getStartTime() < fDataModel.getEndTime()) {
+ fTimeRangeStartLabel.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getStartTime()));
+ fTimeRangeEndLabel.setText(TmfTimestampFormat.getDefaulTimeFormat().format(fDataModel.getEndTime()));
+ } else {
+ fTimeRangeStartLabel.setText(""); //$NON-NLS-1$
+ fTimeRangeEndLabel.setText(""); //$NON-NLS-1$
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // PaintListener
+ // ------------------------------------------------------------------------
+ /**
+ * Image key string for the canvas.
+ */
+ protected final String IMAGE_KEY = "double-buffer-image"; //$NON-NLS-1$
+
+ @Override
+ public void paintControl(final PaintEvent event) {
+
+ // Get the geometry
+ final int canvasWidth = fCanvas.getBounds().width;
+ final int canvasHeight = fCanvas.getBounds().height;
+
+ // Make sure we have something to draw upon
+ if (canvasWidth <= 0 || canvasHeight <= 0) {
+ return;
+ }
+
+ // Retrieve image; re-create only if necessary
+ Image image = (Image) fCanvas.getData(IMAGE_KEY);
+ if (image == null || image.getBounds().width != canvasWidth || image.getBounds().height != canvasHeight) {
+ if (image != null) {
+ image.dispose();
+ }
+ image = new Image(event.display, canvasWidth, canvasHeight);
+ fCanvas.setData(IMAGE_KEY, image);
+ }
+
+ // Draw the histogram on its canvas
+ final GC imageGC = new GC(image);
+ formatImage(imageGC, image);
+ event.gc.drawImage(image, 0, 0);
+ imageGC.dispose();
+ }
+
+ private void formatImage(final GC imageGC, final Image image) {
+
+ if (fScaledData == null) {
+ return;
+ }
+
+ final HistogramScaledData scaledData = new HistogramScaledData(fScaledData);
+
+ try {
+ // Get drawing boundaries
+ final int width = image.getBounds().width;
+ final int height = image.getBounds().height;
+
+ // Clear the drawing area
+ imageGC.setBackground(fBackgroundColor);
+ imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1);
+
+ // Draw the histogram bars
+ final int limit = width < scaledData.fWidth ? width : scaledData.fWidth;
+ double factor = HistogramScaledData.hideLostEvents ? scaledData.fScalingFactor : scaledData.fScalingFactorCombined;
+ final boolean showTracesColors = showTraces();
+ for (int i = 0; i < limit; i++) {
+ HistogramBucket hb = scaledData.fData[i];
+ int totalNbEvents = hb.getNbEvents();
+ int value = (int) Math.ceil(totalNbEvents * factor);
+ int x = i + fOffset;
+
+ // in Linux, the last pixel in a line is not drawn,
+ // so draw lost events first, one pixel too far
+ if (!HistogramScaledData.hideLostEvents) {
+ imageGC.setForeground(fLostEventColor);
+ final int lostEventValue = (int) Math.ceil(scaledData.fLostEventsData[i] * factor);
+ if (lostEventValue != 0) {
+ // drawing a line is inclusive, so we should remove 1 from y2
+ // but we don't because Linux
+ imageGC.drawLine(x, height - value - lostEventValue, x, height - value);
+ }
+ }
+
+ // then draw normal events second, to overwrite that extra pixel
+ if (!hb.isEmpty()) {
+ if (showTracesColors) {
+ for (int traceIndex = 0; traceIndex < hb.getNbTraces(); traceIndex++) {
+ int nbEventsForTrace = hb.getNbEvent(traceIndex);
+ if (nbEventsForTrace > 0) {
+ Color c = fHistoBarColors[traceIndex % fHistoBarColors.length];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ totalNbEvents -= nbEventsForTrace;
+ value = (int) Math.ceil(totalNbEvents * scaledData.fScalingFactor);
+ }
+ }
+ } else {
+ Color c = fHistoBarColors[0];
+ imageGC.setForeground(c);
+ imageGC.drawLine(x, height - value, x, height);
+ }
+ }
+ }
+
+ // Draw the selection bars
+ int alpha = imageGC.getAlpha();
+ imageGC.setAlpha(100);
+ imageGC.setForeground(fSelectionForegroundColor);
+ imageGC.setBackground(fSelectionBackgroundColor);
+ final int beginBucket = scaledData.fSelectionBeginBucket + fOffset;
+ if (beginBucket >= 0 && beginBucket < limit) {
+ imageGC.drawLine(beginBucket, 0, beginBucket, height);
+ }
+ final int endBucket = scaledData.fSelectionEndBucket + fOffset;
+ if (endBucket >= 0 && endBucket < limit && endBucket != beginBucket) {
+ imageGC.drawLine(endBucket, 0, endBucket, height);
+ }
+ if (Math.abs(endBucket - beginBucket) > 1) {
+ if (endBucket > beginBucket) {
+ imageGC.fillRectangle(beginBucket + 1, 0, endBucket - beginBucket - 1, height);
+ } else {
+ imageGC.fillRectangle(endBucket + 1, 0, beginBucket - endBucket - 1, height);
+ }
+ }
+ imageGC.setAlpha(alpha);
+
+ // Add a dashed line as a delimiter
+ int delimiterIndex = (int) ((getDataModel().getEndTime() - scaledData.getFirstBucketTime()) / scaledData.fBucketDuration) + 1;
+ drawDelimiter(imageGC, fLastEventColor, height, delimiterIndex);
+
+ // Fill the area to the right of delimiter with background color
+ imageGC.setBackground(fComposite.getBackground());
+ imageGC.fillRectangle(delimiterIndex + 1, 0, width - (delimiterIndex + 1), height);
+
+ } catch (final Exception e) {
+ // Do nothing
+ }
+ }
+
+ private static void drawDelimiter(final GC imageGC, final Color color,
+ final int height, final int index) {
+ imageGC.setBackground(color);
+ final int dash = height / 4;
+ imageGC.fillRectangle(index, 0 * dash, 1, dash - 1);
+ imageGC.fillRectangle(index, 1 * dash, 1, dash - 1);
+ imageGC.fillRectangle(index, 2 * dash, 1, dash - 1);
+ imageGC.fillRectangle(index, 3 * dash, 1, height - 3 * dash);
+ }
+
+ /**
+ * Draw a time range window
+ *
+ * @param imageGC
+ * the GC
+ * @param rangeStartTime
+ * the range start time
+ * @param rangeDuration
+ * the range duration
+ * @since 2.2
+ */
+ protected void drawTimeRangeWindow(GC imageGC, long rangeStartTime, long rangeDuration) {
+
+ if (fScaledData == null) {
+ return;
+ }
+
+ // Map times to histogram coordinates
+ long bucketSpan = Math.max(fScaledData.fBucketDuration, 1);
+ long startTime = Math.min(rangeStartTime, rangeStartTime + rangeDuration);
+ int rangeWidth = (int) (Math.abs(rangeDuration) / bucketSpan);
+
+ int left = (int) ((startTime - fDataModel.getFirstBucketTime()) / bucketSpan);
+ int right = left + rangeWidth;
+ int center = (left + right) / 2;
+ int height = fCanvas.getSize().y;
+ int arc = Math.min(15, rangeWidth);
+
+ // Draw the selection window
+ imageGC.setForeground(fTimeRangeColor);
+ imageGC.setLineWidth(1);
+ imageGC.setLineStyle(SWT.LINE_SOLID);
+ imageGC.drawRoundRectangle(left, 0, rangeWidth, height - 1, arc, arc);
+
+ // Fill the selection window
+ imageGC.setBackground(fTimeRangeColor);
+ imageGC.setAlpha(35);
+ imageGC.fillRoundRectangle(left + 1, 1, rangeWidth - 1, height - 2, arc, arc);
+ imageGC.setAlpha(255);
+
+ // Draw the cross hair
+ imageGC.setForeground(fTimeRangeColor);
+ imageGC.setLineWidth(1);
+ imageGC.setLineStyle(SWT.LINE_SOLID);
+
+ int chHalfWidth = ((rangeWidth < 60) ? (rangeWidth * 2) / 3 : 40) / 2;
+ imageGC.drawLine(center - chHalfWidth, height / 2, center + chHalfWidth, height / 2);
+ imageGC.drawLine(center, (height / 2) - chHalfWidth, center, (height / 2) + chHalfWidth);
+ }
+
+ // ------------------------------------------------------------------------
+ // KeyListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void keyPressed(final KeyEvent event) {
+ moveCursor(event.keyCode);
+ }
+
+ @Override
+ public void keyReleased(final KeyEvent event) {
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseDoubleClick(final MouseEvent event) {
+ }
+
+ @Override
+ public void mouseDown(final MouseEvent event) {
+ if (fScaledData != null && event.button == 1 && fDragState == DRAG_NONE && fDataModel.getStartTime() < fDataModel.getEndTime()) {
+ fDragState = DRAG_SELECTION;
+ fDragButton = event.button;
+ if ((event.stateMask & SWT.MODIFIER_MASK) == SWT.SHIFT) {
+ if (Math.abs(event.x - fScaledData.fSelectionBeginBucket) < Math.abs(event.x - fScaledData.fSelectionEndBucket)) {
+ fScaledData.fSelectionBeginBucket = fScaledData.fSelectionEndBucket;
+ fSelectionBegin = fSelectionEnd;
+ }
+ fSelectionEnd = Math.min(getTimestamp(event.x), getEndTime());
+ fScaledData.fSelectionEndBucket = (int) ((fSelectionEnd - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
+ } else {
+ fSelectionBegin = Math.min(getTimestamp(event.x), getEndTime());
+ fScaledData.fSelectionBeginBucket = (int) ((fSelectionBegin - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
+ fSelectionEnd = fSelectionBegin;
+ fScaledData.fSelectionEndBucket = fScaledData.fSelectionBeginBucket;
+ }
+ fCanvas.redraw();
+ }
+ }
+
+ @Override
+ public void mouseUp(final MouseEvent event) {
+ if (fDragState == DRAG_SELECTION && event.button == fDragButton) {
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ updateSelectionTime();
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseMoveListener
+ // ------------------------------------------------------------------------
+
+ /**
+ * @since 2.2
+ */
+ @Override
+ public void mouseMove(MouseEvent event) {
+ if (fDragState == DRAG_SELECTION && fDataModel.getStartTime() < fDataModel.getEndTime()) {
+ fSelectionEnd = Math.max(getStartTime(), Math.min(getEndTime(), getTimestamp(event.x)));
+ fScaledData.fSelectionEndBucket = (int) ((fSelectionEnd - fScaledData.fFirstBucketTime) / fScaledData.fBucketDuration);
+ fCanvas.redraw();
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseTrackListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseEnter(final MouseEvent event) {
+ }
+
+ @Override
+ public void mouseExit(final MouseEvent event) {
+ }
+
+ @Override
+ public void mouseHover(final MouseEvent event) {
+ if (fDataModel.getStartTime() < fDataModel.getEndTime() && fScaledData != null) {
+ int delimiterIndex = (int) ((fDataModel.getEndTime() - fScaledData.getFirstBucketTime()) / fScaledData.fBucketDuration) + 1;
+ if (event.x < delimiterIndex) {
+ final String tooltip = formatToolTipLabel(event.x - fOffset);
+ fCanvas.setToolTipText(tooltip);
+ return;
+ }
+ }
+ fCanvas.setToolTipText(null);
+ }
+
+ private String formatToolTipLabel(final int index) {
+ long startTime = fScaledData.getBucketStartTime(index);
+ // negative values are possible if time values came into the model in decreasing order
+ if (startTime < 0) {
+ startTime = 0;
+ }
+ final long endTime = fScaledData.getBucketEndTime(index);
+ final int nbEvents = (index >= 0) ? fScaledData.fData[index].getNbEvents() : 0;
+ final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
+ final StringBuffer buffer = new StringBuffer();
+ int selectionBeginBucket = Math.min(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);
+ int selectionEndBucket = Math.max(fScaledData.fSelectionBeginBucket, fScaledData.fSelectionEndBucket);
+ if (selectionBeginBucket <= index && index <= selectionEndBucket && fSelectionBegin != fSelectionEnd) {
+ TmfTimestampDelta delta = new TmfTimestampDelta(Math.abs(fSelectionEnd - fSelectionBegin), ITmfTimestamp.NANOSECOND_SCALE);
+ buffer.append(NLS.bind(Messages.Histogram_selectionSpanToolTip, delta.toString()));
+ buffer.append(newLine);
+ }
+ buffer.append(NLS.bind(Messages.Histogram_bucketRangeToolTip,
+ new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE).toString(),
+ new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE).toString()));
+ buffer.append(newLine);
+ buffer.append(NLS.bind(Messages.Histogram_eventCountToolTip, nbEvents));
+ if (!HistogramScaledData.hideLostEvents) {
+ final int nbLostEvents = (index >= 0) ? fScaledData.fLostEventsData[index] : 0;
+ buffer.append(newLine);
+ buffer.append(NLS.bind(Messages.Histogram_lostEventCountToolTip, nbLostEvents));
+ }
+ return buffer.toString();
+ }
+
+ // ------------------------------------------------------------------------
+ // ControlListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void controlMoved(final ControlEvent event) {
+ fDataModel.complete();
+ }
+
+ @Override
+ public void controlResized(final ControlEvent event) {
+ fDataModel.complete();
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal Handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Format the timestamp and update the display
+ *
+ * @param signal
+ * the incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
+ updateRangeTextControls();
+
+ fComposite.layout();
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramBucket.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramBucket.java
new file mode 100644
index 0000000000..a6ae1625d5
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramBucket.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Kalray
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Xavier Raynaud - Initial API and implementation
+ * Patrick Tasse - Fix concurrency issue
+ *******************************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import java.util.Arrays;
+
+/**
+ * This class counts events for a particular time range, taking into account origin of the event.
+ * @author Xavier Raynaud
+ * @since 3.0
+ */
+public class HistogramBucket {
+
+ private int fNbEvents = 0;
+ private int fEvents[];
+
+ /**
+ * Constructor
+ * @param traceCount number of traces of the experiment.
+ */
+ public HistogramBucket(int traceCount) {
+ fEvents = new int[traceCount];
+ }
+
+ /**
+ * Constructor
+ * @param values list of values
+ */
+ public HistogramBucket(int... values) {
+ fEvents = values;
+ for (int i : fEvents) {
+ fNbEvents += i;
+ }
+ }
+
+ /**
+ * Copy Constructor
+ * @param b a HistogramBucket to copy
+ */
+ public HistogramBucket(HistogramBucket b) {
+ add(b);
+ }
+
+ /**
+ * Merge Constructor
+ * @param b1 a HistogramBucket
+ * @param b2 another HistogramBucket
+ */
+ public HistogramBucket(HistogramBucket b1, HistogramBucket b2) {
+ add(b1);
+ add(b2);
+ }
+
+ /**
+ * @return the number of events in this bucket
+ */
+ public int getNbEvents() {
+ return fNbEvents;
+ }
+
+ /**
+ * Add an event in this bucket
+ * @param traceIndex a trace index - see {@link HistogramDataModel#setTrace}.
+ */
+ public synchronized void addEvent(int traceIndex) {
+ ensureCapacity(traceIndex + 1);
+ fEvents[traceIndex]++;
+ fNbEvents++;
+ }
+
+ private void ensureCapacity(int len) {
+ if (fEvents == null) {
+ fEvents = new int[len];
+ } else if (fEvents.length < len) {
+ int[] oldArray = fEvents;
+ fEvents = new int[len];
+ System.arraycopy(oldArray, 0, fEvents, 0, oldArray.length);
+ }
+ }
+
+ /**
+ * Gets the number of event in this bucket belonging to given trace
+ * @param traceIndex a trace index
+ * @return the number of events in this bucket belonging to the given trace
+ */
+ public int getNbEvent(int traceIndex) {
+ if (fEvents == null || fEvents.length<= traceIndex) {
+ return 0;
+ }
+ return fEvents[traceIndex];
+ }
+
+ /**
+ * @return the number of traces in this bucket
+ */
+ public int getNbTraces() {
+ if (fEvents == null) {
+ return 0;
+ }
+ return fEvents.length;
+ }
+
+ /**
+ * Merge the given bucket in this one.
+ * @param histogramBucket a bucket to merge in this one.
+ */
+ public synchronized void add(HistogramBucket histogramBucket) {
+ if (histogramBucket != null && histogramBucket.fNbEvents != 0) {
+ int len = histogramBucket.fEvents.length;
+ ensureCapacity(len);
+ for (int i = 0; i < len; i++) {
+ int nbEvents = histogramBucket.fEvents[i];
+ fEvents[i] += nbEvents;
+ fNbEvents += nbEvents;
+ }
+ }
+ }
+
+ /**
+ * @return <code>true</code> if this bucket contains no event, <code>false</code> otherwise.
+ */
+ public boolean isEmpty() {
+ return fNbEvents == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(fEvents);
+ result = prime * result + fNbEvents;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ HistogramBucket other = (HistogramBucket) obj;
+ if (fNbEvents != other.fNbEvents) {
+ return false;
+ }
+ if (fNbEvents != 0 && !Arrays.equals(fEvents, other.fEvents)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(fNbEvents);
+ sb.append(": "); //$NON-NLS-1$
+ sb.append(Arrays.toString(fEvents));
+ return sb.toString();
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramCurrentTimeControl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramCurrentTimeControl.java
new file mode 100644
index 0000000000..ed0978ed01
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramCurrentTimeControl.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Francois Chouinard - Simplified constructor, handle interval format change
+ * Patrick Tasse - Update value handling
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import java.text.ParseException;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * This control provides a group containing a text control.
+ *
+ * @version 1.1
+ * @author Francois Chouinard
+ */
+public class HistogramCurrentTimeControl extends HistogramTextControl {
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param parentView A parent histogram view
+ * @param parent A parent composite to draw in
+ * @param label A label
+ * @param value A value
+ * @since 2.0
+ */
+ public HistogramCurrentTimeControl(HistogramView parentView, Composite parent,
+ String label, long value)
+ {
+ super(parentView, parent, label, value);
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected void updateValue() {
+ if (getValue() == Long.MIN_VALUE) {
+ fTextValue.setText(""); //$NON-NLS-1$
+ return;
+ }
+ String string = fTextValue.getText();
+ long value = getValue();
+ try {
+ value = TmfTimestampFormat.getDefaulTimeFormat().parseValue(string, getValue());
+ } catch (ParseException e) {
+ }
+ if (getValue() != value) {
+ // Make sure that the new time is within range
+ ITmfTrace trace = fParentView.getTrace();
+ if (trace != null) {
+ TmfTimeRange range = trace.getTimeRange();
+ long startTime = range.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long endTime = range.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ if (value < startTime) {
+ value = startTime;
+ } else if (value > endTime) {
+ value = endTime;
+ }
+ }
+
+ // Set and propagate
+ setValue(value);
+ updateSelectionTime(value);
+ } else {
+ setValue(value);
+ }
+ }
+
+ /**
+ * Update the selection time
+ *
+ * @param time
+ * the new selected time
+ * @since 2.2
+ */
+ protected void updateSelectionTime(long time) {
+ fParentView.updateSelectionTime(time, time);
+ }
+
+ @Override
+ public void setValue(long time) {
+ if (time != Long.MIN_VALUE) {
+ super.setValue(time, new TmfTimestamp(time, ITmfTimestamp.NANOSECOND_SCALE).toString());
+ } else {
+ super.setValue(time, ""); //$NON-NLS-1$
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal Handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Format the timestamp and update the display. Compute the new text size,
+ * adjust the text and group widgets and then refresh the view layout.
+ *
+ * @param signal the incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
+ setValue(getValue());
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramDataModel.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramDataModel.java
new file mode 100644
index 0000000000..cc723a7626
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramDataModel.java
@@ -0,0 +1,717 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Implementation of new interfaces/listeners and support for
+ * time stamp in any order
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Francois Chouinard - Added support for empty initial buckets
+ * Patrick Tasse - Support selection range
+ * Jean-Christian Kouamé, Simon Delisle - Added support to manage lost events
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+
+/**
+ * Histogram-independent data model.
+ *
+ * It has the following characteristics:
+ * <ul>
+ * <li>The <i>basetime</i> is the timestamp of the first event
+ * <li>There is a fixed number (<i>n</i>) of buckets of uniform duration
+ * (<i>d</i>)
+ * <li>The <i>timespan</i> of the model is thus: <i>n</i> * <i>d</i> time units
+ * <li>Bucket <i>i</i> holds the number of events that occurred in time range:
+ * [<i>basetime</i> + <i>i</i> * <i>d</i>, <i>basetime</i> + (<i>i</i> + 1) *
+ * <i>d</i>)
+ * </ul>
+ * Initially, the bucket durations is set to 1ns. As the events are read, they
+ * are tallied (using <i>countEvent()</i>) in the appropriate bucket (relative
+ * to the <i>basetime</i>).
+ * <p>
+ * Eventually, an event will have a timestamp that exceeds the <i>timespan</i>
+ * high end (determined by <i>n</i>, the number of buckets, and <i>d</i>, the
+ * bucket duration). At this point, the histogram needs to be compacted. This is
+ * done by simply merging adjacent buckets by pair, in effect doubling the
+ * <i>timespan</i> (<i>timespan'</i> = <i>n</i> * <i>d'</i>, where <i>d'</i> =
+ * 2<i>d</i>). This compaction happens as needed as the trace is read.
+ * <p>
+ * The model allows for timestamps in not increasing order. The timestamps can
+ * be fed to the model in any order. If an event has a timestamp less than the
+ * <i>basetime</i>, the buckets will be moved to the right to account for the
+ * new smaller timestamp. The new <i>basetime</i> is a multiple of the bucket
+ * duration smaller then the previous <i>basetime</i>. Note that the
+ * <i>basetime</i> might no longer be the timestamp of an event. If necessary,
+ * the buckets will be compacted before moving to the right. This might be
+ * necessary to not lose any event counts at the end of the buckets array.
+ * <p>
+ * The mapping from the model to the UI is performed by the <i>scaleTo()</i>
+ * method. By keeping the number of buckets <i>n</i> relatively large with
+ * respect to to the number of pixels in the actual histogram, we should achieve
+ * a nice result when visualizing the histogram.
+ * <p>
+ *
+ * @version 2.0
+ * @author Francois Chouinard
+ */
+public class HistogramDataModel implements IHistogramDataModel {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The default number of buckets
+ */
+ public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000;
+
+ /**
+ * Number of events after which listeners will be notified.
+ */
+ public static final int REFRESH_FREQUENCY = DEFAULT_NUMBER_OF_BUCKETS;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ // Trace management
+ private ITmfTrace fTrace = null;
+ private final Map<ITmfTrace, Integer> fTraceMap = new LinkedHashMap<>();
+
+ // Bucket management
+ private final int fNbBuckets;
+ private final HistogramBucket[] fBuckets;
+ private final long[] fLostEventsBuckets;
+ private long fBucketDuration;
+ private long fNbEvents;
+ private int fLastBucket;
+
+ // Timestamps
+ private long fFirstBucketTime; // could be negative when analyzing events with descending order!!!
+ private long fFirstEventTime;
+ private long fEndTime;
+ private long fSelectionBegin;
+ private long fSelectionEnd;
+ private long fTimeLimit;
+
+ // Private listener lists
+ private final ListenerList fModelListeners;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor with default number of buckets.
+ */
+ public HistogramDataModel() {
+ this(0, DEFAULT_NUMBER_OF_BUCKETS);
+ }
+
+ /**
+ * Default constructor with default number of buckets.
+ *
+ * @param startTime
+ * The histogram start time
+ * @since 2.0
+ */
+ public HistogramDataModel(long startTime) {
+ this(startTime, DEFAULT_NUMBER_OF_BUCKETS);
+ }
+
+ /**
+ * Constructor with non-default number of buckets.
+ *
+ * @param nbBuckets
+ * A number of buckets.
+ */
+ public HistogramDataModel(int nbBuckets) {
+ this(0, nbBuckets);
+ }
+
+ /**
+ * Constructor with non-default number of buckets.
+ *
+ * @param startTime
+ * the histogram start time
+ * @param nbBuckets
+ * A number of buckets.
+ * @since 2.0
+ */
+ public HistogramDataModel(long startTime, int nbBuckets) {
+ fFirstBucketTime = fFirstEventTime = fEndTime = startTime;
+ fNbBuckets = nbBuckets;
+ fBuckets = new HistogramBucket[nbBuckets];
+ fLostEventsBuckets = new long[nbBuckets];
+ fModelListeners = new ListenerList();
+ clear();
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other
+ * A model to copy.
+ */
+ public HistogramDataModel(HistogramDataModel other) {
+ fNbBuckets = other.fNbBuckets;
+ fBuckets = new HistogramBucket[fNbBuckets];
+ for (int i = 0; i < fNbBuckets; i++) {
+ fBuckets[i] = new HistogramBucket(other.fBuckets[i]);
+ }
+ fLostEventsBuckets = Arrays.copyOf(other.fLostEventsBuckets, fNbBuckets);
+ fBucketDuration = Math.max(other.fBucketDuration, 1);
+ fNbEvents = other.fNbEvents;
+ fLastBucket = other.fLastBucket;
+ fFirstBucketTime = other.fFirstBucketTime;
+ fFirstEventTime = other.fFirstEventTime;
+ fEndTime = other.fEndTime;
+ fSelectionBegin = other.fSelectionBegin;
+ fSelectionEnd = other.fSelectionEnd;
+ fTimeLimit = other.fTimeLimit;
+ fModelListeners = new ListenerList();
+ Object[] listeners = other.fModelListeners.getListeners();
+ for (Object listener : listeners) {
+ fModelListeners.add(listener);
+ }
+ }
+
+
+ /**
+ * Disposes the data model
+ * @since 3.0
+ */
+ public void dispose() {
+ fTraceMap.clear();
+ fTrace = null;
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the number of events in the data model.
+ *
+ * @return number of events.
+ */
+ public long getNbEvents() {
+ return fNbEvents;
+ }
+
+ /**
+ * Returns the number of buckets in the model.
+ *
+ * @return number of buckets.
+ */
+ public int getNbBuckets() {
+ return fNbBuckets;
+ }
+
+ /**
+ * Returns the current bucket duration.
+ *
+ * @return bucket duration
+ */
+ public long getBucketDuration() {
+ return fBucketDuration;
+ }
+
+ /**
+ * Returns the time value of the first bucket in the model.
+ *
+ * @return time of first bucket.
+ */
+ public long getFirstBucketTime() {
+ return fFirstBucketTime;
+ }
+
+ /**
+ * Returns the time of the first event in the model.
+ *
+ * @return time of first event.
+ */
+ public long getStartTime() {
+ return fFirstEventTime;
+ }
+
+ /**
+ * Sets the trace of this model.
+ * @param trace - a {@link ITmfTrace}
+ * @since 3.0
+ */
+ public void setTrace(ITmfTrace trace) {
+ this.fTrace = trace;
+ fTraceMap.clear();
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces != null) {
+ int i = 0;
+ for (ITmfTrace tr : traces) {
+ fTraceMap.put(tr, i);
+ i++;
+ }
+ }
+ }
+
+ /**
+ * Gets the trace of this model.
+ * @return a {@link ITmfTrace}
+ * @since 3.0
+ */
+ public ITmfTrace getTrace() {
+ return this.fTrace;
+ }
+
+ /**
+ * Gets the traces names of this model.
+ * @return an array of trace names
+ * @since 3.0
+ */
+ public String[] getTraceNames() {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces == null) {
+ return new String[0];
+ }
+ String[] traceNames = new String[traces.length];
+ int i = 0;
+ for (ITmfTrace tr : traces) {
+ traceNames[i] = tr.getName();
+ i++;
+ }
+ return traceNames;
+ }
+
+ /**
+ * Gets the number of traces of this model.
+ * @return the number of traces of this model.
+ * @since 3.0
+ */
+ public int getNbTraces() {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces == null) {
+ return 1; //
+ }
+ return traces.length;
+ }
+
+ /**
+ * Sets the model start time
+ *
+ * @param startTime
+ * the histogram range start time
+ * @param endTime
+ * the histogram range end time
+ * @since 2.0
+ */
+ public void setTimeRange(long startTime, long endTime) {
+ fFirstBucketTime = fFirstEventTime = fEndTime = startTime;
+ fBucketDuration = 1;
+ updateEndTime();
+ while (endTime >= fTimeLimit) {
+ mergeBuckets();
+ }
+ }
+
+ /**
+ * Set the end time. Setting this ensures that the corresponding bucket is
+ * displayed regardless of the event counts.
+ *
+ * @param endTime
+ * the time of the last used bucket
+ * @since 2.2
+ */
+ public void setEndTime(long endTime) {
+ fEndTime = endTime;
+ fLastBucket = (int) ((endTime - fFirstBucketTime) / fBucketDuration);
+ }
+
+ /**
+ * Returns the end time.
+ *
+ * @return the time of the last used bucket
+ */
+ public long getEndTime() {
+ return fEndTime;
+ }
+
+ /**
+ * Returns the begin time of the current selection in the model.
+ *
+ * @return the begin time of the current selection.
+ * @since 2.1
+ */
+ public long getSelectionBegin() {
+ return fSelectionBegin;
+ }
+
+ /**
+ * Returns the end time of the current selection in the model.
+ *
+ * @return the end time of the current selection.
+ * @since 2.1
+ */
+ public long getSelectionEnd() {
+ return fSelectionEnd;
+ }
+
+ /**
+ * Returns the time limit with is: start time + nbBuckets * bucketDuration
+ *
+ * @return the time limit.
+ */
+ public long getTimeLimit() {
+ return fTimeLimit;
+ }
+
+ // ------------------------------------------------------------------------
+ // Listener handling
+ // ------------------------------------------------------------------------
+
+ /**
+ * Add a listener to the model to be informed about model changes.
+ *
+ * @param listener
+ * A listener to add.
+ */
+ public void addHistogramListener(IHistogramModelListener listener) {
+ fModelListeners.add(listener);
+ }
+
+ /**
+ * Remove a given model listener.
+ *
+ * @param listener
+ * A listener to remove.
+ */
+ public void removeHistogramListener(IHistogramModelListener listener) {
+ fModelListeners.remove(listener);
+ }
+
+ // Notify listeners (always)
+ private void fireModelUpdateNotification() {
+ fireModelUpdateNotification(0);
+ }
+
+ // Notify listener on boundary
+ private void fireModelUpdateNotification(long count) {
+ if ((count % REFRESH_FREQUENCY) == 0) {
+ Object[] listeners = fModelListeners.getListeners();
+ for (Object listener2 : listeners) {
+ IHistogramModelListener listener = (IHistogramModelListener) listener2;
+ listener.modelUpdated();
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void complete() {
+ fireModelUpdateNotification();
+ }
+
+ /**
+ * Clear the histogram model.
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.distribution.model.IBaseDistributionModel#clear()
+ */
+ @Override
+ public void clear() {
+ Arrays.fill(fBuckets, null);
+ Arrays.fill(fLostEventsBuckets, 0);
+ fNbEvents = 0;
+ fFirstBucketTime = 0;
+ fEndTime = 0;
+ fSelectionBegin = 0;
+ fSelectionEnd = 0;
+ fLastBucket = 0;
+ fBucketDuration = 1;
+ updateEndTime();
+ fireModelUpdateNotification();
+ }
+
+ /**
+ * Sets the current selection time range (no notification of listeners)
+ *
+ * @param beginTime
+ * The selection begin time.
+ * @param endTime
+ * The selection end time.
+ * @since 2.1
+ */
+ public void setSelection(long beginTime, long endTime) {
+ fSelectionBegin = beginTime;
+ fSelectionEnd = endTime;
+ }
+
+ /**
+ * Sets the current selection time range with notification of listeners
+ *
+ * @param beginTime
+ * The selection begin time.
+ * @param endTime
+ * The selection end time.
+ * @since 2.1
+ */
+ public void setSelectionNotifyListeners(long beginTime, long endTime) {
+ fSelectionBegin = beginTime;
+ fSelectionEnd = endTime;
+ fireModelUpdateNotification();
+ }
+
+ /**
+ * Add event to the correct bucket, compacting the if needed.
+ *
+ * @param eventCount
+ * The current event Count (for notification purposes)
+ * @param timestamp
+ * The timestamp of the event to count
+ * @param trace
+ * The event trace
+ * @since 3.0
+ */
+ @Override
+ public void countEvent(long eventCount, long timestamp, ITmfTrace trace) {
+
+ // Validate
+ if (timestamp < 0) {
+ return;
+ }
+
+ // Set the start/end time if not already done
+ if ((fFirstBucketTime == 0) && (fLastBucket == 0) && (fBuckets[0] == null) && (timestamp > 0)) {
+ fFirstBucketTime = timestamp;
+ fFirstEventTime = timestamp;
+ updateEndTime();
+ }
+
+ if (timestamp < fFirstEventTime) {
+ fFirstEventTime = timestamp;
+ }
+
+ if (fEndTime < timestamp) {
+ fEndTime = timestamp;
+ }
+
+ if (timestamp >= fFirstBucketTime) {
+
+ // Compact as needed
+ while (timestamp >= fTimeLimit) {
+ mergeBuckets();
+ }
+
+ } else {
+
+ // get offset for adjustment
+ int offset = getOffset(timestamp);
+
+ // Compact as needed
+ while ((fLastBucket + offset) >= fNbBuckets) {
+ mergeBuckets();
+ offset = getOffset(timestamp);
+ }
+
+ moveBuckets(offset);
+
+ fLastBucket = fLastBucket + offset;
+
+ fFirstBucketTime = fFirstBucketTime - (offset * fBucketDuration);
+ updateEndTime();
+ }
+
+ // Increment the right bucket
+ int index = (int) ((timestamp - fFirstBucketTime) / fBucketDuration);
+ if (fBuckets[index] == null) {
+ fBuckets[index] = new HistogramBucket(getNbTraces());
+ }
+ Integer traceIndex = fTraceMap.get(trace);
+ if (traceIndex == null) {
+ traceIndex = 0;
+ }
+ fBuckets[index].addEvent(traceIndex);
+ fNbEvents++;
+ if (fLastBucket < index) {
+ fLastBucket = index;
+ }
+
+ fireModelUpdateNotification(eventCount);
+ }
+
+ /**
+ * Add lost event to the correct bucket, compacting the if needed.
+ *
+ * @param timeRange
+ * time range of a lost event
+ * @param nbLostEvents
+ * the number of lost events
+ * @param fullRange
+ * Full range or time range for histogram request
+ * @since 2.2
+ */
+ public void countLostEvent(TmfTimeRange timeRange, long nbLostEvents, boolean fullRange) {
+
+ // Validate
+ if (timeRange.getStartTime().getValue() < 0 || timeRange.getEndTime().getValue() < 0) {
+ return;
+ }
+
+ // Compact as needed
+ if (fullRange) {
+ while (timeRange.getEndTime().getValue() >= fTimeLimit) {
+ mergeBuckets();
+ }
+ }
+
+ int indexStart = (int) ((timeRange.getStartTime().getValue() - fFirstBucketTime) / fBucketDuration);
+ int indexEnd = (int) ((timeRange.getEndTime().getValue() - fFirstBucketTime) / fBucketDuration);
+ int nbBucketRange = (indexEnd - indexStart) + 1;
+
+ int lostEventPerBucket = (int) Math.ceil((double) nbLostEvents / nbBucketRange);
+ long lastLostCol = Math.max(1, nbLostEvents - lostEventPerBucket * (nbBucketRange - 1));
+
+ // Increment the right bucket, bear in mind that ranges make it almost certain that some lost events are out of range
+ for (int index = indexStart; index <= indexEnd && index < fLostEventsBuckets.length; index++) {
+ if (index == (indexStart + nbBucketRange - 1)) {
+ fLostEventsBuckets[index] += lastLostCol;
+ } else {
+ fLostEventsBuckets[index] += lostEventPerBucket;
+ }
+ }
+
+ fNbEvents++;
+
+ fireModelUpdateNotification(nbLostEvents);
+ }
+
+ /**
+ * Scale the model data to the width, height and bar width requested.
+ *
+ * @param width
+ * A width of the histogram canvas
+ * @param height
+ * A height of the histogram canvas
+ * @param barWidth
+ * A width (in pixel) of a histogram bar
+ * @return the result array of size [width] and where the highest value
+ * doesn't exceed [height]
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.histogram.IHistogramDataModel#scaleTo(int,
+ * int, int)
+ */
+ @Override
+ public HistogramScaledData scaleTo(int width, int height, int barWidth) {
+ // Basic validation
+ if ((width <= 0) || (height <= 0) || (barWidth <= 0))
+ {
+ throw new AssertionError("Invalid histogram dimensions (" + width + "x" + height + ", barWidth=" + barWidth + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ }
+
+ // The result structure
+ HistogramScaledData result = new HistogramScaledData(width, height, barWidth);
+
+ // Scale horizontally
+ result.fMaxValue = 0;
+
+ int nbBars = width / barWidth;
+ int bucketsPerBar = (fLastBucket / nbBars) + 1;
+ result.fBucketDuration = Math.max(bucketsPerBar * fBucketDuration, 1);
+ for (int i = 0; i < nbBars; i++) {
+ int count = 0;
+ int countLostEvent = 0;
+ result.fData[i] = new HistogramBucket(getNbTraces());
+ for (int j = i * bucketsPerBar; j < ((i + 1) * bucketsPerBar); j++) {
+ if (fNbBuckets <= j) {
+ break;
+ }
+ if (fBuckets[j] != null) {
+ count += fBuckets[j].getNbEvents();
+ result.fData[i].add(fBuckets[j]);
+ }
+ countLostEvent += fLostEventsBuckets[j];
+ }
+ result.fLostEventsData[i] = countLostEvent;
+ result.fLastBucket = i;
+ if (result.fMaxValue < count) {
+ result.fMaxValue = count;
+ }
+ if (result.fMaxCombinedValue < count + countLostEvent) {
+ result.fMaxCombinedValue = count + countLostEvent;
+ }
+ }
+
+ // Scale vertically
+ if (result.fMaxValue > 0) {
+ result.fScalingFactor = (double) height / result.fMaxValue;
+ }
+ if (result.fMaxCombinedValue > 0) {
+ result.fScalingFactorCombined = (double) height / result.fMaxCombinedValue;
+ }
+
+ fBucketDuration = Math.max(fBucketDuration, 1);
+ // Set selection begin and end index in the scaled histogram
+ result.fSelectionBeginBucket = (int) ((fSelectionBegin - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
+ result.fSelectionEndBucket = (int) ((fSelectionEnd - fFirstBucketTime) / fBucketDuration) / bucketsPerBar;
+
+ result.fFirstBucketTime = fFirstBucketTime;
+ result.fFirstEventTime = fFirstEventTime;
+ return result;
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper functions
+ // ------------------------------------------------------------------------
+
+ private void updateEndTime() {
+ fTimeLimit = fFirstBucketTime + (fNbBuckets * fBucketDuration);
+ }
+
+ private void mergeBuckets() {
+ for (int i = 0; i < (fNbBuckets / 2); i++) {
+ fBuckets[i] = new HistogramBucket(fBuckets[2 * i], fBuckets[(2 * i) + 1]);
+ fLostEventsBuckets[i] = fLostEventsBuckets[2 * i] + fLostEventsBuckets[(2 * i) + 1];
+ }
+ Arrays.fill(fBuckets, fNbBuckets / 2, fNbBuckets, null);
+ Arrays.fill(fLostEventsBuckets, fNbBuckets / 2, fNbBuckets, 0);
+ fBucketDuration *= 2;
+ updateEndTime();
+ fLastBucket = (fNbBuckets / 2) - 1;
+ }
+
+ private void moveBuckets(int offset) {
+ for (int i = fNbBuckets - 1; i >= offset; i--) {
+ fBuckets[i] = new HistogramBucket(fBuckets[i - offset]);
+ fLostEventsBuckets[i] = fLostEventsBuckets[i - offset];
+ }
+
+ for (int i = 0; i < offset; i++) {
+ fBuckets[i] = null;
+ fLostEventsBuckets[i] = 0;
+ }
+ }
+
+ private int getOffset(long timestamp) {
+ int offset = (int) ((fFirstBucketTime - timestamp) / fBucketDuration);
+ if (((fFirstBucketTime - timestamp) % fBucketDuration) != 0) {
+ offset++;
+ }
+ return offset;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramRequest.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramRequest.java
new file mode 100644
index 0000000000..b91ca655a0
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramRequest.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Bourque - Initial API and implementation
+ * Yuriy Vashchuk - Heritage correction.
+ * Francois Chouinard - Cleanup and refactoring
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Simon Delisle - Added a new parameter to the constructor
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfLostEvent;
+import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+
+/**
+ * Class to request events for given time range from a trace to fill a
+ * HistogramDataModel and HistogramView.
+ *
+ * @version 1.0
+ * @author Francois Chouinard
+ * <p>
+ */
+public class HistogramRequest extends TmfEventRequest {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The histogram data model to fill.
+ */
+ protected final HistogramDataModel fHistogram;
+
+ private final boolean fFullRange;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param histogram
+ * The histogram data model
+ * @param range
+ * The time range to request data
+ * @param rank
+ * The index of the first event to retrieve
+ * @param nbEvents
+ * The number of events requested
+ * @param blockSize
+ * The number of events per block
+ * @param execType
+ * The requested execution priority
+ * @param fullRange
+ * Full range or time range for histogram request
+ * @since 3.0
+ */
+ public HistogramRequest(HistogramDataModel histogram, TmfTimeRange range,
+ int rank, int nbEvents, int blockSize,
+ ITmfEventRequest.ExecutionType execType, boolean fullRange) {
+ super(ITmfEvent.class, range, rank, nbEvents, execType);
+ fHistogram = histogram;
+ fFullRange = fullRange;
+ }
+
+ // ------------------------------------------------------------------------
+ // TmfEventRequest
+ // ------------------------------------------------------------------------
+
+ /**
+ * Handle the event from the trace by updating the histogram data model.
+ *
+ * @param event
+ * a event from the trace
+ * @see org.eclipse.tracecompass.tmf.core.request.TmfEventRequest#handleData(org.eclipse.tracecompass.tmf.core.event.ITmfEvent)
+ */
+ @Override
+ public void handleData(ITmfEvent event) {
+ super.handleData(event);
+ if (event instanceof ITmfLostEvent) {
+ ITmfLostEvent lostEvents = (ITmfLostEvent) event;
+ /* clear the old data when it is a new request */
+ fHistogram.countLostEvent(lostEvents.getTimeRange(), lostEvents.getNbLostEvents(), fFullRange);
+
+ } else { /* handle lost event */
+ long timestamp = event.getTimestamp().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fHistogram.countEvent(getNbRead(), timestamp, event.getTrace());
+ }
+ }
+
+ /**
+ * Complete the request. It also notifies the histogram model about the
+ * completion.
+ *
+ * @see org.eclipse.tracecompass.tmf.core.request.TmfEventRequest#handleCompleted()
+ */
+ @Override
+ public void handleCompleted() {
+ fHistogram.complete();
+ super.handleCompleted();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramScaledData.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramScaledData.java
new file mode 100644
index 0000000000..389f814e0d
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramScaledData.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Added setter and getter and bar width support
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Patrick Tasse - Support selection range
+ * Jean-Christian Kouamé - Support to manage lost events
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import java.util.Arrays;
+
+/**
+ * Convenience class/struct for scaled histogram data.
+ *
+ * @version 1.0
+ * @author Francois Chouinard
+ */
+public class HistogramScaledData {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Indicator value that bucket is out of range (not filled).
+ */
+ public static final int OUT_OF_RANGE_BUCKET = -1;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Width of histogram canvas (number of pixels).
+ */
+ public int fWidth;
+ /**
+ * Height of histogram canvas (number of pixels).
+ */
+ public int fHeight;
+ /**
+ * Width of one histogram bar (number of pixels).
+ */
+ public int fBarWidth;
+ /**
+ * Array of scaled values
+ */
+ public HistogramBucket[] fData;
+ /**
+ * Array of scaled values combined including the lost events.
+ * This array contains the number of lost events for each bar in the histogram
+ * @since 2.2
+ */
+ public final int[] fLostEventsData;
+ /**
+ * The bucket duration of a scaled data bucket.
+ */
+ public long fBucketDuration;
+ /**
+ * The maximum number of events of all buckets.
+ */
+ public long fMaxValue;
+ /**
+ * the maximum of events of all buckets including the lost events
+ * @since 2.2
+ */
+ public long fMaxCombinedValue;
+ /**
+ * The index of the selection begin bucket.
+ * @since 2.1
+ */
+ public int fSelectionBeginBucket;
+ /**
+ * The index of the selection end bucket.
+ * @since 2.1
+ */
+ public int fSelectionEndBucket;
+ /**
+ * The index of the last bucket.
+ */
+ public int fLastBucket;
+ /**
+ * The scaling factor used to fill the scaled data.
+ */
+ public double fScalingFactor;
+ /**
+ * The scaling factor used to fill the scaled data including the lost events.
+ * @since 2.2
+ */
+ public double fScalingFactorCombined;
+ /**
+ * The scaling factor used to fill the combining scaled data including lost events
+ */
+ /**
+ * Time of first bucket.
+ */
+ public long fFirstBucketTime;
+ /**
+ * The time of the first event.
+ */
+ public long fFirstEventTime;
+ /**
+ * show the lost events or not
+ * @since 2.2
+ */
+ public static volatile boolean hideLostEvents = false;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ * @param width the canvas width
+ * @param height the canvas height
+ * @param barWidth the required bar width
+ */
+ public HistogramScaledData(int width, int height, int barWidth) {
+ fWidth = width;
+ fHeight = height;
+ fBarWidth = barWidth;
+ fData = new HistogramBucket[width / fBarWidth];
+ fLostEventsData = new int[width / fBarWidth];
+ fBucketDuration = 1;
+ fMaxValue = 0;
+ fMaxCombinedValue = 0;
+ fSelectionBeginBucket = 0;
+ fSelectionEndBucket = 0;
+ fLastBucket = 0;
+ fScalingFactor = 1;
+ fScalingFactorCombined = 1;
+ fFirstBucketTime = 0;
+ }
+
+ /**
+ * Copy constructor
+ * @param other another scaled data.
+ */
+ public HistogramScaledData(HistogramScaledData other) {
+ fWidth = other.fWidth;
+ fHeight = other.fHeight;
+ fBarWidth = other.fBarWidth;
+ fData = Arrays.copyOf(other.fData, other.fData.length);
+ fLostEventsData = Arrays.copyOf(other.fLostEventsData, other.fLostEventsData.length);
+ fBucketDuration = other.fBucketDuration;
+ fMaxValue = other.fMaxValue;
+ fMaxCombinedValue = other.fMaxCombinedValue;
+ fSelectionBeginBucket = other.fSelectionBeginBucket;
+ fSelectionEndBucket = other.fSelectionEndBucket;
+ fLastBucket = other.fLastBucket;
+ fScalingFactor = other.fScalingFactor;
+ fScalingFactorCombined = other.fScalingFactorCombined;
+ fFirstBucketTime = other.fFirstBucketTime;
+ }
+
+ // ------------------------------------------------------------------------
+ // Setter and Getter
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the time of the first bucket of the scaled data.
+ * @return the time of the first bucket.
+ */
+ public long getFirstBucketTime() {
+ return fFirstBucketTime;
+ }
+
+ /**
+ * Set the first event time.
+ * @param firstEventTime The time to set
+ */
+ public void setFirstBucketTime(long firstEventTime) {
+ fFirstBucketTime = firstEventTime;
+ }
+
+ /**
+ * Returns the time of the last bucket.
+ * @return last bucket time
+ */
+ public long getLastBucketTime() {
+ return getBucketStartTime(fLastBucket);
+ }
+
+ /**
+ * Returns the time of the bucket start time for given index.
+ * @param index A bucket index.
+ * @return the time of the bucket start time
+ */
+ public long getBucketStartTime(int index) {
+ return fFirstBucketTime + index * fBucketDuration;
+ }
+
+ /**
+ * Returns the time of the bucket end time for given index.
+ * @param index A bucket index.
+ * @return the time of the bucket end time
+ */
+ public long getBucketEndTime(int index) {
+ return getBucketStartTime(index) + fBucketDuration;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionEndControl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionEndControl.java
new file mode 100644
index 0000000000..c87cb403ca
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionEndControl.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Text control for selection end time
+ *
+ * @since 2.2
+ */
+public class HistogramSelectionEndControl extends HistogramCurrentTimeControl {
+
+ /**
+ * Standard constructor
+ *
+ * @param parentView A parent histogram view
+ * @param parent A parent composite to draw in
+ * @param label A label
+ * @param value A value
+ */
+ public HistogramSelectionEndControl(HistogramView parentView, Composite parent, String label, long value) {
+ super(parentView, parent, label, value);
+ }
+
+ @Override
+ protected void updateSelectionTime(long time) {
+ long begin = Math.min(fParentView.getSelectionBegin(), time);
+ long end = Math.max(fParentView.getSelectionBegin(), time);
+ fParentView.updateSelectionTime(begin, end);
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionStartControl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionStartControl.java
new file mode 100644
index 0000000000..14cc546143
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramSelectionStartControl.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * Text control for selection start time
+ *
+ * @since 2.2
+ */
+public class HistogramSelectionStartControl extends HistogramCurrentTimeControl {
+
+ /**
+ * Standard constructor
+ *
+ * @param parentView A parent histogram view
+ * @param parent A parent composite to draw in
+ * @param label A label
+ * @param value A value
+ */
+ public HistogramSelectionStartControl(HistogramView parentView, Composite parent, String label, long value) {
+ super(parentView, parent, label, value);
+ }
+
+ @Override
+ protected void updateSelectionTime(long time) {
+ if (fParentView.getLinkState()) {
+ fParentView.updateSelectionTime(time, time);
+ } else {
+ long begin = Math.min(time, fParentView.getSelectionEnd());
+ long end = Math.max(time, fParentView.getSelectionEnd());
+ fParentView.updateSelectionTime(begin, end);
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTextControl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTextControl.java
new file mode 100644
index 0000000000..5e8c588011
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTextControl.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wiliam Bourque - Adapted from SpinnerGroup (in TimeFrameView)
+ * Francois Chouinard - Cleanup and refactoring
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Francois Chouinard - Better handling of control display, support for signals
+ * Patrick Tasse - Update for mouse wheel zoom
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
+
+/**
+ * This control provides a group containing a text control.
+ *
+ * @version 1.1
+ * @author Francois Chouinard
+ */
+public abstract class HistogramTextControl implements FocusListener, KeyListener {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The parent histogram view.
+ */
+ protected final HistogramView fParentView;
+
+ // Controls data
+ private final Composite fParent;
+ private Font fFont;
+ private final Composite fComposite;
+ private final Label fLabel;
+
+ /**
+ * The text value field.
+ */
+ protected final Text fTextValue;
+
+ private long fValue;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor with given group and text values.
+ *
+ * @param parentView The parent histogram view.
+ * @param parent The parent composite
+ * @param label The text label
+ * @param value The initial value
+ * @since 2.0
+ */
+ public HistogramTextControl(HistogramView parentView, Composite parent, String label, long value)
+ {
+ fParentView = parentView;
+ fParent = parent;
+
+ // --------------------------------------------------------------------
+ // Reduce font size for a more pleasing rendering
+ // --------------------------------------------------------------------
+
+ final int fontSizeAdjustment = -1;
+ final Font font = parent.getFont();
+ final FontData fontData = font.getFontData()[0];
+ fFont = new Font(font.getDevice(), fontData.getName(), fontData.getHeight() + fontSizeAdjustment, fontData.getStyle());
+
+ // --------------------------------------------------------------------
+ // Create the group
+ // --------------------------------------------------------------------
+
+ // Re-used layout variables
+ GridLayout gridLayout;
+ GridData gridData;
+
+ // Composite
+ gridLayout = new GridLayout(3, false);
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ fComposite = new Composite(fParent, SWT.NONE);
+ fComposite.setLayout(gridLayout);
+
+ gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ Label filler = new Label(fComposite, SWT.NONE);
+ filler.setLayoutData(gridData);
+
+ // Label
+ gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+ fLabel = new Label(fComposite, SWT.NONE);
+ fLabel.setText(label);
+ fLabel.setFont(fFont);
+
+ // Text control
+ gridData = new GridData(SWT.CENTER, SWT.CENTER, false, false);
+ fTextValue = new Text(fComposite, SWT.BORDER);
+ fTextValue.setFont(fFont);
+ fTextValue.setLayoutData(gridData);
+
+ // --------------------------------------------------------------------
+ // Add listeners
+ // --------------------------------------------------------------------
+
+ fTextValue.addFocusListener(this);
+ fTextValue.addKeyListener(this);
+
+ TmfSignalManager.register(this);
+ }
+
+ /**
+ * Dispose of the widget
+ * @since 2.0
+ */
+ public void dispose() {
+ fFont.dispose();
+ TmfSignalManager.deregister(this);
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns if widget isDisposed or not
+ * @return <code>true</code> if widget is disposed else <code>false</code>
+ */
+ public boolean isDisposed() {
+ return fComposite.isDisposed();
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Updates the text value.
+ */
+ protected abstract void updateValue();
+
+ /**
+ * Set the Grid Layout Data for the group.
+ * @param layoutData A GridData to set.
+ */
+ public void setLayoutData(GridData layoutData) {
+ fComposite.setLayoutData(layoutData);
+ }
+
+ /**
+ * Enables the receiver if the argument is <code>true</code>,
+ * and disables it otherwise. A disabled control is typically
+ * not selectable from the user interface and draws with an
+ * inactive or "grayed" look.
+ *
+ * @param enabled the new enabled state
+ * @since 2.2
+ */
+ public void setEnabled(boolean enabled) {
+ fTextValue.setEnabled(enabled);
+ }
+
+ /**
+ * The time value in to set in the text field.
+ *
+ * @param time the time to set
+ * @param displayTime the display value
+ * @since 2.0
+ */
+ protected void setValue(final long time, final String displayTime) {
+ // If this is the UI thread, process now
+ Display display = Display.getCurrent();
+ if (display != null) {
+ if (!isDisposed()) {
+ fValue = time;
+ fTextValue.setText(displayTime);
+ fComposite.layout();
+ fParent.getParent().layout();
+ }
+ return;
+ }
+
+ // Call self from the UI thread
+ if (!isDisposed()) {
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!isDisposed()) {
+ setValue(time, displayTime);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * @param time the time value to display
+ */
+ public abstract void setValue(long time);
+
+ /**
+ * Returns the time value.
+ * @return time value.
+ */
+ public long getValue() {
+ return fValue;
+ }
+
+ /**
+ * Add a mouse wheel listener to the text control
+ * @param listener the mouse wheel listener
+ * @since 2.0
+ */
+ public void addMouseWheelListener(MouseWheelListener listener) {
+ fTextValue.addMouseWheelListener(listener);
+ }
+
+ /**
+ * Remove a mouse wheel listener from the text control
+ * @param listener the mouse wheel listener
+ * @since 2.0
+ */
+ public void removeMouseWheelListener(MouseWheelListener listener) {
+ fTextValue.removeMouseWheelListener(listener);
+ }
+
+ // ------------------------------------------------------------------------
+ // FocusListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void focusGained(FocusEvent event) {
+ }
+
+ @Override
+ public void focusLost(FocusEvent event) {
+ updateValue();
+ }
+
+ // ------------------------------------------------------------------------
+ // KeyListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void keyPressed(KeyEvent event) {
+ switch (event.character) {
+ case SWT.CR:
+ updateValue();
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTimeRangeControl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTimeRangeControl.java
new file mode 100644
index 0000000000..0eaa50fb7a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramTimeRangeControl.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Francois Chouinard - Simplified constructor, handle interval format change
+ * Patrick Tasse - Update value handling
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import java.text.ParseException;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestampFormat;
+
+/**
+ * This control provides a group containing a text control.
+ *
+ * @version 2.0
+ * @author Francois Chouinard
+ */
+public class HistogramTimeRangeControl extends HistogramTextControl {
+
+ // ------------------------------------------------------------------------
+ // Construction
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor with given group and text values.
+ *
+ * @param parentView The parent histogram view.
+ * @param parent The parent composite
+ * @param groupLabel A group value
+ * @param value A text value
+ * @since 2.0
+ */
+ public HistogramTimeRangeControl(HistogramView parentView, Composite parent,
+ String groupLabel, long value)
+ {
+ super(parentView, parent, groupLabel, value);
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected void updateValue() {
+ if (getValue() == Long.MIN_VALUE) {
+ fTextValue.setText(""); //$NON-NLS-1$
+ return;
+ }
+ String string = fTextValue.getText();
+ long value = getValue();
+ try {
+ value = TmfTimestampFormat.getDefaulIntervalFormat().parseValue(string);
+ if (value < 1) {
+ value = getValue();
+ }
+ } catch (ParseException e) {
+ }
+ if (getValue() != value) {
+ fParentView.updateTimeRange(value);
+ } else {
+ setValue(value);
+ }
+ }
+
+ @Override
+ public void setValue(long time) {
+ if (time != Long.MIN_VALUE) {
+ ITmfTimestamp ts = new TmfTimestamp(time, ITmfTimestamp.NANOSECOND_SCALE);
+ super.setValue(time, ts.toString(TmfTimestampFormat.getDefaulIntervalFormat()));
+ } else {
+ super.setValue(time, ""); //$NON-NLS-1$
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal Handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Format the interval and update the display. Compute the new text size,
+ * adjust the text and group widgets and then refresh the view layout.
+ *
+ * @param signal the incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void intervalFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
+ setValue(getValue());
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramView.java
new file mode 100644
index 0000000000..a575619a58
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramView.java
@@ -0,0 +1,887 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Bourque - Initial API and implementation
+ * Yuriy Vashchuk - GUI reorganisation, simplification and some related code improvements.
+ * Yuriy Vashchuk - Histograms optimisation.
+ * Yuriy Vashchuk - Histogram Canvas Heritage correction
+ * Francois Chouinard - Cleanup and refactoring
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Patrick Tasse - Update for mouse wheel zoom
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseWheelListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest.ExecutionType;
+import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalThrottler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * The purpose of this view is to provide graphical time distribution statistics about the trace events.
+ * <p>
+ * The view is composed of two histograms and two controls:
+ * <ul>
+ * <li>an event distribution histogram for the whole trace;
+ * <li>an event distribution histogram for current time window (window span);
+ * <li>the timestamp of the currently selected event;
+ * <li>the window span (size of the time window of the smaller histogram).
+ * </ul>
+ * The histograms x-axis show their respective time range.
+ *
+ * @version 2.0
+ * @author Francois Chouinard
+ */
+public class HistogramView extends TmfView {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The view ID as defined in plugin.xml
+ */
+ public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.histogram"; //$NON-NLS-1$
+
+ private static final Image LINK_IMG = Activator.getDefault().getImageFromPath("/icons/etool16/link.gif"); //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ // Parent widget
+ private Composite fParent;
+
+ // The current trace
+ private ITmfTrace fTrace;
+
+ // Current timestamp/time window - everything in the TIME_SCALE
+ private long fTraceStartTime;
+ private long fTraceEndTime;
+ private long fWindowStartTime;
+ private long fWindowEndTime;
+ private long fWindowSpan;
+ private long fSelectionBeginTime;
+ private long fSelectionEndTime;
+
+ // Time controls
+ private HistogramTextControl fSelectionStartControl;
+ private HistogramTextControl fSelectionEndControl;
+ private HistogramTextControl fTimeSpanControl;
+
+ // Link
+ private Label fLinkButton;
+ private boolean fLinkState;
+
+ // Histogram/request for the full trace range
+ private static FullTraceHistogram fFullTraceHistogram;
+ private HistogramRequest fFullTraceRequest;
+
+ // Histogram/request for the selected time range
+ private static TimeRangeHistogram fTimeRangeHistogram;
+ private HistogramRequest fTimeRangeRequest;
+
+ // Legend area
+ private Composite fLegendArea;
+ private Image[] fLegendImages;
+
+ // Throttlers for the time sync and time-range sync signals
+ private final TmfSignalThrottler fTimeSyncThrottle;
+ private final TmfSignalThrottler fTimeRangeSyncThrottle;
+
+ // Action for toggle showing the lost events
+ private Action hideLostEventsAction;
+ // Action for toggle showing the traces
+ private Action showTraceAction;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public HistogramView() {
+ super(ID);
+ fTimeSyncThrottle = new TmfSignalThrottler(this, 200);
+ fTimeRangeSyncThrottle = new TmfSignalThrottler(this, 200);
+ }
+
+ @Override
+ public void dispose() {
+ if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
+ fTimeRangeRequest.cancel();
+ }
+ if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
+ fFullTraceRequest.cancel();
+ }
+ fFullTraceHistogram.dispose();
+ fTimeRangeHistogram.dispose();
+ fSelectionStartControl.dispose();
+ fSelectionEndControl.dispose();
+ fTimeSpanControl.dispose();
+ super.dispose();
+ }
+
+ // ------------------------------------------------------------------------
+ // TmfView
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ fParent = parent;
+
+ // Control labels
+ final String selectionStartLabel = Messages.HistogramView_selectionStartLabel;
+ final String selectionEndLabel = Messages.HistogramView_selectionEndLabel;
+ final String windowSpanLabel = Messages.HistogramView_windowSpanLabel;
+
+ // --------------------------------------------------------------------
+ // Set the HistogramView layout
+ // --------------------------------------------------------------------
+
+ Composite viewComposite = new Composite(fParent, SWT.FILL);
+ GridLayout gridLayout = new GridLayout();
+ gridLayout.numColumns = 2;
+ gridLayout.horizontalSpacing = 5;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ viewComposite.setLayout(gridLayout);
+
+ // --------------------------------------------------------------------
+ // Time controls
+ // --------------------------------------------------------------------
+
+ Composite controlsComposite = new Composite(viewComposite, SWT.NONE);
+ gridLayout = new GridLayout();
+ gridLayout.numColumns = 2;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.horizontalSpacing = 5;
+ gridLayout.verticalSpacing = 1;
+ gridLayout.makeColumnsEqualWidth = false;
+ controlsComposite.setLayout(gridLayout);
+ GridData gridData = new GridData(SWT.FILL, SWT.CENTER, false, false);
+ controlsComposite.setLayoutData(gridData);
+
+ Composite selectionGroup = new Composite(controlsComposite, SWT.BORDER);
+ gridLayout = new GridLayout();
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ selectionGroup.setLayout(gridLayout);
+
+ // Selection start control
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.CENTER;
+ fSelectionStartControl = new HistogramSelectionStartControl(this, selectionGroup, selectionStartLabel, 0L);
+ fSelectionStartControl.setLayoutData(gridData);
+ fSelectionStartControl.setValue(Long.MIN_VALUE);
+
+ // Selection end control
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.CENTER;
+ fSelectionEndControl = new HistogramSelectionEndControl(this, selectionGroup, selectionEndLabel, 0L);
+ fSelectionEndControl.setLayoutData(gridData);
+ fSelectionEndControl.setValue(Long.MIN_VALUE);
+
+ // Link button
+ gridData = new GridData();
+ fLinkButton = new Label(controlsComposite, SWT.NONE);
+ fLinkButton.setImage(LINK_IMG);
+ fLinkButton.setLayoutData(gridData);
+ addLinkButtonListeners();
+
+ // Window span time control
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.CENTER;
+ fTimeSpanControl = new HistogramTimeRangeControl(this, controlsComposite, windowSpanLabel, 0L);
+ fTimeSpanControl.setLayoutData(gridData);
+ fTimeSpanControl.setValue(Long.MIN_VALUE);
+
+ // --------------------------------------------------------------------
+ // Time range histogram
+ // --------------------------------------------------------------------
+
+ Composite timeRangeComposite = new Composite(viewComposite, SWT.NONE);
+ gridLayout = new GridLayout();
+ gridLayout.numColumns = 1;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.marginTop = 5;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginLeft = 5;
+ gridLayout.marginRight = 5;
+ timeRangeComposite.setLayout(gridLayout);
+
+ // Use remaining horizontal space
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.FILL;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.grabExcessVerticalSpace = true;
+ timeRangeComposite.setLayoutData(gridData);
+
+ // Histogram
+ fTimeRangeHistogram = new TimeRangeHistogram(this, timeRangeComposite);
+
+ // --------------------------------------------------------------------
+ // Full range histogram
+ // --------------------------------------------------------------------
+
+ Composite fullRangeComposite = new Composite(viewComposite, SWT.FILL);
+ gridLayout = new GridLayout();
+ gridLayout.numColumns = 1;
+ gridLayout.marginHeight = 0;
+ gridLayout.marginWidth = 0;
+ gridLayout.marginTop = 5;
+ gridLayout.horizontalSpacing = 0;
+ gridLayout.verticalSpacing = 0;
+ gridLayout.marginLeft = 5;
+ gridLayout.marginRight = 5;
+ fullRangeComposite.setLayout(gridLayout);
+
+ // Use remaining horizontal space
+ gridData = new GridData();
+ gridData.horizontalAlignment = SWT.FILL;
+ gridData.verticalAlignment = SWT.FILL;
+ gridData.horizontalSpan = 2;
+ gridData.grabExcessHorizontalSpace = true;
+ gridData.grabExcessVerticalSpace = true;
+ fullRangeComposite.setLayoutData(gridData);
+
+ // Histogram
+ fFullTraceHistogram = new FullTraceHistogram(this, fullRangeComposite);
+
+ fLegendArea = new Composite(viewComposite, SWT.FILL);
+ fLegendArea.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false, 2, 1));
+ fLegendArea.setLayout(new RowLayout());
+
+ // Add mouse wheel listener to time span control
+ MouseWheelListener listener = fFullTraceHistogram.getZoom();
+ fTimeSpanControl.addMouseWheelListener(listener);
+
+
+ // View Action Handling
+ contributeToActionBars();
+
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ fFullTraceHistogram.fCanvas.setFocus();
+ }
+
+ void refresh() {
+ fParent.layout(true);
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the current trace handled by the view
+ *
+ * @return the current trace
+ * @since 2.0
+ */
+ public ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Returns the time range of the current selected window (base on default time scale).
+ *
+ * @return the time range of current selected window.
+ * @since 2.0
+ */
+ public TmfTimeRange getTimeRange() {
+ return new TmfTimeRange(
+ new TmfTimestamp(fWindowStartTime, ITmfTimestamp.NANOSECOND_SCALE),
+ new TmfTimestamp(fWindowEndTime, ITmfTimestamp.NANOSECOND_SCALE));
+ }
+
+ /**
+ * get the show lost events action
+ *
+ * @return The action object
+ * @since 2.2
+ */
+ public Action getShowLostEventsAction() {
+ if (hideLostEventsAction == null) {
+ /* show lost events */
+ hideLostEventsAction = new Action(Messages.HistogramView_hideLostEvents, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ HistogramScaledData.hideLostEvents = hideLostEventsAction.isChecked();
+ long maxNbEvents = HistogramScaledData.hideLostEvents ? fFullTraceHistogram.fScaledData.fMaxValue : fFullTraceHistogram.fScaledData.fMaxCombinedValue;
+ fFullTraceHistogram.setMaxNbEvents(maxNbEvents);
+ maxNbEvents = HistogramScaledData.hideLostEvents ? fTimeRangeHistogram.fScaledData.fMaxValue : fTimeRangeHistogram.fScaledData.fMaxCombinedValue;
+ fTimeRangeHistogram.setMaxNbEvents(maxNbEvents);
+ }
+ };
+ hideLostEventsAction.setText(Messages.HistogramView_hideLostEvents);
+ hideLostEventsAction.setToolTipText(Messages.HistogramView_hideLostEvents);
+ hideLostEventsAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_LOST_EVENTS));
+ }
+ return hideLostEventsAction;
+ }
+
+ /**
+ * get the show trace action
+ *
+ * @return The action object
+ * @since 3.0
+ */
+ public Action getShowTraceAction() {
+ if (showTraceAction == null) {
+ /* show lost events */
+ showTraceAction = new Action(Messages.HistogramView_showTraces, IAction.AS_CHECK_BOX) {
+ @Override
+ public void run() {
+ Histogram.showTraces = showTraceAction.isChecked();
+ fFullTraceHistogram.fCanvas.redraw();
+ fTimeRangeHistogram.fCanvas.redraw();
+ updateLegendArea();
+ }
+ };
+ showTraceAction.setChecked(true);
+ showTraceAction.setText(Messages.HistogramView_showTraces);
+ showTraceAction.setToolTipText(Messages.HistogramView_showTraces);
+ showTraceAction.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SHOW_HIST_TRACES));
+ }
+ return showTraceAction;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Broadcast TmfSignal about new current selection time range.
+ * @param beginTime the begin time of current selection.
+ * @param endTime the end time of current selection.
+ */
+ void updateSelectionTime(long beginTime, long endTime) {
+ updateDisplayedSelectionTime(beginTime, endTime);
+ TmfTimestamp beginTs = new TmfTimestamp(beginTime, ITmfTimestamp.NANOSECOND_SCALE);
+ TmfTimestamp endTs = new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE);
+ TmfTimeSynchSignal signal = new TmfTimeSynchSignal(this, beginTs, endTs);
+ fTimeSyncThrottle.queue(signal);
+ }
+
+ /**
+ * Get selection begin time
+ * @return the begin time of current selection
+ */
+ long getSelectionBegin() {
+ return fSelectionBeginTime;
+ }
+
+ /**
+ * Get selection end time
+ * @return the end time of current selection
+ */
+ long getSelectionEnd() {
+ return fSelectionEndTime;
+ }
+
+ /**
+ * Get the link state
+ * @return true if begin and end selection time should be linked
+ */
+ boolean getLinkState() {
+ return fLinkState;
+ }
+
+ /**
+ * Broadcast TmfSignal about new selection time range.
+ * @param startTime the new start time
+ * @param endTime the new end time
+ */
+ void updateTimeRange(long startTime, long endTime) {
+ if (fTrace != null) {
+ // Build the new time range; keep the current time
+ TmfTimeRange timeRange = new TmfTimeRange(
+ new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE),
+ new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE));
+ fTimeSpanControl.setValue(endTime - startTime);
+
+ updateDisplayedTimeRange(startTime, endTime);
+
+ // Send the FW signal
+ TmfRangeSynchSignal signal = new TmfRangeSynchSignal(this, timeRange);
+ fTimeRangeSyncThrottle.queue(signal);
+ }
+ }
+
+ /**
+ * Broadcast TmfSignal about new selected time range.
+ * @param newDuration new duration (relative to current start time)
+ */
+ public synchronized void updateTimeRange(long newDuration) {
+ if (fTrace != null) {
+ long delta = newDuration - fWindowSpan;
+ long newStartTime = fWindowStartTime - (delta / 2);
+ setNewRange(newStartTime, newDuration);
+ }
+ }
+
+ private void setNewRange(long startTime, long duration) {
+ long realStart = startTime;
+
+ if (realStart < fTraceStartTime) {
+ realStart = fTraceStartTime;
+ }
+
+ long endTime = realStart + duration;
+ if (endTime > fTraceEndTime) {
+ endTime = fTraceEndTime;
+ if ((endTime - duration) > fTraceStartTime) {
+ realStart = endTime - duration;
+ } else {
+ realStart = fTraceStartTime;
+ }
+ }
+ updateTimeRange(realStart, endTime);
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Handles trace opened signal. Loads histogram if new trace time range is not
+ * equal <code>TmfTimeRange.NULL_RANGE</code>
+ * @param signal the trace opened signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ assert (signal != null);
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+
+ /**
+ * Handles trace selected signal. Loads histogram if new trace time range is not
+ * equal <code>TmfTimeRange.NULL_RANGE</code>
+ * @param signal the trace selected signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ assert (signal != null);
+ if (fTrace != signal.getTrace()) {
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+ }
+
+ private void loadTrace() {
+ initializeHistograms();
+ fParent.redraw();
+ }
+
+ /**
+ * Handles trace closed signal. Clears the view and data model and cancels requests.
+ * @param signal the trace closed signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+
+ // Kill any running request
+ if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
+ fTimeRangeRequest.cancel();
+ }
+ if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
+ fFullTraceRequest.cancel();
+ }
+
+ // Initialize the internal data
+ fTrace = null;
+ fTraceStartTime = 0L;
+ fTraceEndTime = 0L;
+ fWindowStartTime = 0L;
+ fWindowEndTime = 0L;
+ fWindowSpan = 0L;
+ fSelectionBeginTime = 0L;
+ fSelectionEndTime = 0L;
+
+ // Clear the UI widgets
+ fFullTraceHistogram.clear();
+ fTimeRangeHistogram.clear();
+ fSelectionStartControl.setValue(Long.MIN_VALUE);
+ fSelectionEndControl.setValue(Long.MIN_VALUE);
+
+ fTimeSpanControl.setValue(Long.MIN_VALUE);
+
+ for (Control c: fLegendArea.getChildren()) {
+ c.dispose();
+ }
+ if (fLegendImages != null) {
+ for (Image i: fLegendImages) {
+ i.dispose();
+ }
+ }
+ fLegendImages = null;
+ fLegendArea.layout();
+ fLegendArea.getParent().layout();
+ }
+
+ /**
+ * Handles trace range updated signal. Extends histogram according to the new time range. If a
+ * HistogramRequest is already ongoing, it will be cancelled and a new request with the new range
+ * will be issued.
+ *
+ * @param signal the trace range updated signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceRangeUpdated(TmfTraceRangeUpdatedSignal signal) {
+
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+
+ TmfTimeRange fullRange = signal.getRange();
+
+ fTraceStartTime = fullRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fTraceEndTime = fullRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+
+ fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+ fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+
+ sendFullRangeRequest(fullRange);
+ }
+
+ /**
+ * Handles the trace updated signal. Used to update time limits (start and end time)
+ * @param signal the trace updated signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceUpdated(TmfTraceUpdatedSignal signal) {
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+ TmfTimeRange fullRange = signal.getTrace().getTimeRange();
+ fTraceStartTime = fullRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fTraceEndTime = fullRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+
+ fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+ fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+
+ if ((fFullTraceRequest != null) && fFullTraceRequest.getRange().getEndTime().compareTo(signal.getRange().getEndTime()) < 0) {
+ sendFullRangeRequest(fullRange);
+ }
+}
+
+ /**
+ * Handles the current time updated signal. Sets the current time in the time range
+ * histogram as well as the full histogram.
+ *
+ * @param signal the signal to process
+ */
+ @TmfSignalHandler
+ public void currentTimeUpdated(final TmfTimeSynchSignal signal) {
+ if (Display.getCurrent() == null) {
+ // Make sure the signal is handled in the UI thread
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fParent.isDisposed()) {
+ return;
+ }
+ currentTimeUpdated(signal);
+ }
+ });
+ return;
+ }
+
+ // Update the selected time range
+ ITmfTimestamp beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE);
+ ITmfTimestamp endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE);
+ updateDisplayedSelectionTime(beginTime.getValue(), endTime.getValue());
+ }
+
+ /**
+ * Updates the current time range in the time range histogram and full range histogram.
+ * @param signal the signal to process
+ */
+ @TmfSignalHandler
+ public void timeRangeUpdated(final TmfRangeSynchSignal signal) {
+ if (Display.getCurrent() == null) {
+ // Make sure the signal is handled in the UI thread
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fParent.isDisposed()) {
+ return;
+ }
+ timeRangeUpdated(signal);
+ }
+ });
+ return;
+ }
+
+ if (fTrace != null) {
+ // Validate the time range
+ TmfTimeRange range = signal.getCurrentRange().getIntersection(fTrace.getTimeRange());
+ if (range == null) {
+ return;
+ }
+
+ updateDisplayedTimeRange(
+ range.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue(),
+ range.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue());
+
+ // Send the event request to populate the small histogram
+ sendTimeRangeRequest(fWindowStartTime, fWindowEndTime);
+
+ fTimeSpanControl.setValue(fWindowSpan);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper functions
+ // ------------------------------------------------------------------------
+
+ private void initializeHistograms() {
+ TmfTimeRange fullRange = updateTraceTimeRange();
+ long selectionBeginTime = fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long selectionEndTime = fTraceManager.getSelectionEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long startTime = fTraceManager.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long duration = fTraceManager.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue() - startTime;
+
+ if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
+ fTimeRangeRequest.cancel();
+ }
+ fTimeRangeHistogram.clear();
+ fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+ fTimeRangeHistogram.setTimeRange(startTime, duration);
+ fTimeRangeHistogram.setSelection(selectionBeginTime, selectionEndTime);
+ fTimeRangeHistogram.fDataModel.setTrace(fTrace);
+
+ if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
+ fFullTraceRequest.cancel();
+ }
+ fFullTraceHistogram.clear();
+ fFullTraceHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+ fFullTraceHistogram.setTimeRange(startTime, duration);
+ fFullTraceHistogram.setSelection(selectionBeginTime, selectionEndTime);
+ fFullTraceHistogram.fDataModel.setTrace(fTrace);
+
+ fWindowStartTime = startTime;
+ fWindowSpan = duration;
+ fWindowEndTime = startTime + duration;
+
+ fSelectionBeginTime = selectionBeginTime;
+ fSelectionEndTime = selectionEndTime;
+ fSelectionStartControl.setValue(fSelectionBeginTime);
+ fSelectionEndControl.setValue(fSelectionEndTime);
+
+ fTimeSpanControl.setValue(duration);
+
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ if (traces != null) {
+ this.showTraceAction.setEnabled(traces.length < fFullTraceHistogram.getMaxNbTraces());
+ }
+ updateLegendArea();
+
+ if (!fullRange.equals(TmfTimeRange.NULL_RANGE)) {
+ sendTimeRangeRequest(startTime, startTime + duration);
+ sendFullRangeRequest(fullRange);
+ }
+ }
+
+ private void updateLegendArea() {
+ for (Control c: fLegendArea.getChildren()) {
+ c.dispose();
+ }
+ if (fLegendImages != null) {
+ for (Image i: fLegendImages) {
+ i.dispose();
+ }
+ }
+ fLegendImages = null;
+ if (fFullTraceHistogram.showTraces()) {
+ ITmfTrace[] traces = TmfTraceManager.getTraceSet(fTrace);
+ fLegendImages = new Image[traces.length];
+ int traceIndex = 0;
+ for (ITmfTrace trace : traces) {
+ fLegendImages[traceIndex] = new Image(fLegendArea.getDisplay(), 16, 16);
+ GC gc = new GC(fLegendImages[traceIndex]);
+ gc.setBackground(fFullTraceHistogram.getTraceColor(traceIndex));
+ gc.fillRectangle(0, 0, 15, 15);
+ gc.setForeground(fLegendArea.getDisplay().getSystemColor(SWT.COLOR_BLACK));
+ gc.drawRectangle(0, 0, 15, 15);
+ gc.dispose();
+
+ CLabel label = new CLabel(fLegendArea, SWT.NONE);
+ label.setText(trace.getName());
+ label.setImage(fLegendImages[traceIndex]);
+ traceIndex++;
+ }
+ }
+ fLegendArea.layout();
+ fLegendArea.getParent().layout();
+ }
+
+ private void updateDisplayedSelectionTime(long beginTime, long endTime) {
+ fSelectionBeginTime = beginTime;
+ fSelectionEndTime = endTime;
+
+ fFullTraceHistogram.setSelection(fSelectionBeginTime, fSelectionEndTime);
+ fTimeRangeHistogram.setSelection(fSelectionBeginTime, fSelectionEndTime);
+ fSelectionStartControl.setValue(fSelectionBeginTime);
+ fSelectionEndControl.setValue(fSelectionEndTime);
+ }
+
+ private void updateDisplayedTimeRange(long start, long end) {
+ fWindowStartTime = start;
+ fWindowEndTime = end;
+ fWindowSpan = fWindowEndTime - fWindowStartTime;
+ fFullTraceHistogram.setTimeRange(fWindowStartTime, fWindowSpan);
+ }
+
+ private TmfTimeRange updateTraceTimeRange() {
+ fTraceStartTime = 0L;
+ fTraceEndTime = 0L;
+
+ TmfTimeRange timeRange = fTrace.getTimeRange();
+ if (!timeRange.equals(TmfTimeRange.NULL_RANGE)) {
+ fTraceStartTime = timeRange.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fTraceEndTime = timeRange.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ }
+ return timeRange;
+ }
+
+ private void sendTimeRangeRequest(long startTime, long endTime) {
+ if ((fTimeRangeRequest != null) && !fTimeRangeRequest.isCompleted()) {
+ fTimeRangeRequest.cancel();
+ }
+ TmfTimestamp startTS = new TmfTimestamp(startTime, ITmfTimestamp.NANOSECOND_SCALE);
+ TmfTimestamp endTS = new TmfTimestamp(endTime, ITmfTimestamp.NANOSECOND_SCALE);
+ TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS);
+
+ fTimeRangeHistogram.clear();
+ fTimeRangeHistogram.setFullRange(fTraceStartTime, fTraceEndTime);
+ fTimeRangeHistogram.setTimeRange(startTime, endTime - startTime);
+
+ int cacheSize = fTrace.getCacheSize();
+ fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram.getDataModel(),
+ timeRange, 0, ITmfEventRequest.ALL_DATA, cacheSize, ExecutionType.FOREGROUND, false);
+ fTrace.sendRequest(fTimeRangeRequest);
+ }
+
+ private void sendFullRangeRequest(TmfTimeRange fullRange) {
+ if ((fFullTraceRequest != null) && !fFullTraceRequest.isCompleted()) {
+ fFullTraceRequest.cancel();
+ }
+ int cacheSize = fTrace.getCacheSize();
+ fFullTraceRequest = new HistogramRequest(fFullTraceHistogram.getDataModel(),
+ fullRange,
+ (int) fFullTraceHistogram.fDataModel.getNbEvents(),
+ ITmfEventRequest.ALL_DATA,
+ cacheSize,
+ ExecutionType.BACKGROUND, true);
+ fTrace.sendRequest(fFullTraceRequest);
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ bars.getToolBarManager().add(getShowLostEventsAction());
+ bars.getToolBarManager().add(getShowTraceAction());
+ bars.getToolBarManager().add(new Separator());
+ }
+
+ private void addLinkButtonListeners() {
+ fLinkButton.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseDown(MouseEvent e) {
+ fSelectionEndControl.setEnabled(fLinkState);
+ fLinkState = !fLinkState;
+ fLinkButton.redraw();
+ }
+ });
+
+ fLinkButton.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ if (fLinkState) {
+ Rectangle r = fLinkButton.getBounds();
+ r.x = -1;
+ r.y = -1;
+ e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
+ e.gc.drawRectangle(r);
+ r.x = 0;
+ r.y = 0;
+ e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_DARK_GRAY));
+ e.gc.drawRectangle(r);
+ }
+ }
+ });
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramZoom.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramZoom.java
new file mode 100644
index 0000000000..296b2c79fd
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/HistogramZoom.java
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Patrick Tasse - Update for mouse wheel zoom
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseWheelListener;
+
+/**
+ * Class to handle zooming within histogram windows..
+ *
+ * @version 1.0
+ * @author Francois Chouinard
+ * <p>
+ */
+public class HistogramZoom implements MouseWheelListener, KeyListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ private final static double ZOOM_FACTOR = 0.8;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ private final Histogram fHistogram;
+
+ private long fAbsoluteStartTime;
+ private long fAbsoluteEndTime;
+ private final long fMinWindowSize;
+
+ private long fRangeStartTime;
+ private long fRangeDuration;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor.
+ *
+ * @param histogram
+ * The parent histogram object
+ * @param start
+ * The start time of the zoom area
+ * @param end
+ * The end time of the zoom area
+ * @since 2.0
+ */
+ public HistogramZoom(Histogram histogram, long start, long end) {
+ fHistogram = histogram;
+ fAbsoluteStartTime = start;
+ fAbsoluteEndTime = end;
+ fMinWindowSize = 0;
+
+ fRangeStartTime = fAbsoluteStartTime;
+ fRangeDuration = fAbsoluteStartTime + fMinWindowSize;
+
+ histogram.addMouseWheelListener(this);
+ histogram.addKeyListener(this);
+ }
+
+ // ------------------------------------------------------------------------
+ // Accessors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Get start time of the zoom window.
+ * @return the start time.
+ */
+ public synchronized long getStartTime() {
+ return fRangeStartTime;
+ }
+
+ /**
+ * Get the end time of the zoom window.
+ * @return the end time
+ */
+ public synchronized long getEndTime() {
+ return fRangeStartTime + fRangeDuration;
+ }
+
+ /**
+ * Get the duration of the zoom window.
+ * @return the duration of the zoom window.
+ */
+ public synchronized long getDuration() {
+ return fRangeDuration;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * The the full time range of the histogram
+ *
+ * @param startTime the start time the histogram
+ * @param endTime the end time of the histogram
+ */
+ public synchronized void setFullRange(long startTime, long endTime) {
+ fAbsoluteStartTime = startTime;
+ fAbsoluteEndTime = endTime;
+ }
+
+ /**
+ * Sets the new zoom window
+ * @param startTime the start time
+ * @param duration the duration
+ */
+ public synchronized void setNewRange(long startTime, long duration) {
+ long realStart = startTime;
+
+ if (realStart < fAbsoluteStartTime) {
+ realStart = fAbsoluteStartTime;
+ }
+
+ long endTime = realStart + duration;
+ if (endTime > fAbsoluteEndTime) {
+ endTime = fAbsoluteEndTime;
+ if (endTime - duration > fAbsoluteStartTime) {
+ realStart = endTime - duration;
+ } else {
+ realStart = fAbsoluteStartTime;
+ }
+ }
+
+ fRangeStartTime = realStart;
+ fRangeDuration = endTime - realStart;
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseWheelListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseScrolled(MouseEvent event) {
+ zoom(event.count);
+ }
+
+ /**
+ * @since 3.1
+ */
+ @Override
+ public void keyPressed(KeyEvent e) {
+ if (e.character == '+') {
+ zoom(1);
+ } else if (e.character == '-') {
+ zoom(-1);
+ }
+ }
+
+ /**
+ * @since 3.1
+ */
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+
+ private synchronized void zoom(int nbClicks) {
+ // Compute the new time range
+ long requestedRange = (nbClicks > 0) ? Math.round(ZOOM_FACTOR * fRangeDuration) : (long) Math.ceil(fRangeDuration * (1.0 / ZOOM_FACTOR));
+
+ // Distribute delta and adjust for boundaries
+ long requestedStart = validateStart(fRangeStartTime + (fRangeDuration - requestedRange) / 2);
+ long requestedEnd = validateEnd(requestedStart, requestedStart + requestedRange);
+ requestedStart = validateStart(requestedEnd - requestedRange);
+
+ fHistogram.updateTimeRange(requestedStart, requestedEnd);
+ }
+
+ private long validateStart(long start) {
+ long realStart = start;
+
+ if (realStart < fAbsoluteStartTime) {
+ realStart = fAbsoluteStartTime;
+ }
+ if (realStart > fAbsoluteEndTime) {
+ realStart = fAbsoluteEndTime - fMinWindowSize;
+ }
+ return realStart;
+ }
+
+ private long validateEnd(long start, long end) {
+ long realEnd = end;
+
+ if (realEnd > fAbsoluteEndTime) {
+ realEnd = fAbsoluteEndTime;
+ }
+ if (realEnd < start + fMinWindowSize) {
+ realEnd = start + fMinWindowSize;
+ }
+ return realEnd;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramDataModel.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramDataModel.java
new file mode 100644
index 0000000000..56f1e89747
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramDataModel.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Xavier Raynaud - Support multi-trace coloring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.views.distribution.model.IBaseDistributionModel;
+
+/**
+ * Histogram data model interface.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public interface IHistogramDataModel extends IBaseDistributionModel {
+ /**
+ * Add event to the correct bucket, compacting the if needed.
+ *
+ * @param eventCount the event to count
+ * @param timestamp the timestamp of the event to count
+ * @param trace the trace corresponding to given events
+ * @since 3.0
+ */
+ void countEvent(long eventCount, long timestamp, ITmfTrace trace);
+
+ /**
+ * Scale the model data to the width, height and bar width requested.
+ *
+ * @param width A width of the histogram canvas
+ * @param height A height of the histogram canvas
+ * @param barWidth A width (in pixel) of a histogram bar
+ * @return the result array of size [width] and where the highest value doesn't exceed [height]
+ * while considering the bar width [barWidth]
+ */
+ HistogramScaledData scaleTo(int width, int height, int barWidth);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramModelListener.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramModelListener.java
new file mode 100644
index 0000000000..10c6a07a94
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/IHistogramModelListener.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ * Francois Chouinard - Moved from LTTng to TMF
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+/**
+ * Listener interface for receiving histogram data model notifications.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public interface IHistogramModelListener {
+ /**
+ * Method to implement to receive notification about model updates.
+ */
+ void modelUpdated();
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Messages.java
new file mode 100644
index 0000000000..9141c11fb0
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/Messages.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Bourque - Initial API and implementation
+ * Francois Chouinard - Cleanup and refactoring
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Patrick Tasse - Update for histogram selection range and tool tip
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages file for the histogram widgets.
+ * <p>
+ *
+ * @version 1.0
+ * @author Francois Chouinard
+ */
+public class Messages extends NLS {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.histogram.messages"; //$NON-NLS-1$
+
+ /**
+ * @since 3.0
+ */
+ public static String HistogramView_showTraces;
+
+ /**
+ * @since 2.2
+ */
+ public static String HistogramView_hideLostEvents;
+ /**
+ * The label for the selection start time
+ * @since 2.2
+ */
+ public static String HistogramView_selectionStartLabel;
+ /**
+ * The label for the selection end time
+ * @since 2.2
+ */
+ public static String HistogramView_selectionEndLabel;
+ /**
+ * The label for the window span.
+ */
+ public static String HistogramView_windowSpanLabel;
+ /**
+ * The tool tip text for the selection span.
+ * @since 2.2
+ */
+ public static String Histogram_selectionSpanToolTip;
+ /**
+ * The tool tip text for the bucket range.
+ * @since 2.2
+ */
+ public static String Histogram_bucketRangeToolTip;
+ /**
+ * The tool tip text for the event count.
+ * @since 2.2
+ */
+ public static String Histogram_eventCountToolTip;
+ /**
+ * The tool tip text for the lost event count.
+ * @since 2.2
+ */
+ public static String Histogram_lostEventCountToolTip;
+
+ // ------------------------------------------------------------------------
+ // Initializer
+ // ------------------------------------------------------------------------
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ private Messages() {
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/TimeRangeHistogram.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/TimeRangeHistogram.java
new file mode 100644
index 0000000000..caf56e03b6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/TimeRangeHistogram.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Francois Chouinard - Initial API and implementation
+ * Bernd Hufmann - Changed to updated histogram data model
+ * Francois Chouinard - Moved from LTTng to TMF
+ * Patrick Tasse - Update for mouse wheel zoom
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.histogram;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+
+/**
+ * A basic histogram widget that displays the event distribution of a specific time range of a trace.
+ * It has the following additional features:
+ * <ul>
+ * <li>zoom in: mouse wheel up (or forward)
+ * <li>zoom out: mouse wheel down (or backward)
+ * </ul>
+ *
+ * @version 1.1
+ * @author Francois Chouinard
+ */
+public class TimeRangeHistogram extends Histogram {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ private HistogramZoom fZoom = null;
+
+ private long fRangeStartTime = 0L;
+ private long fRangeDuration;
+ private long fFullRangeStartTime = 0L;
+ private long fFullRangeEndTime = 0L;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor
+ * @param view The parent histogram view
+ * @param parent The parent composite
+ */
+ public TimeRangeHistogram(HistogramView view, Composite parent) {
+ super(view, parent);
+ fZoom = new HistogramZoom(this, getStartTime(), getTimeLimit());
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public synchronized void clear() {
+ fRangeStartTime = 0L;
+ fRangeDuration = 0L;
+ fFullRangeStartTime = 0L;
+ fFullRangeEndTime = 0L;
+ setOffset(0);
+ if (fZoom != null) {
+ fZoom.setFullRange(0L, 0L);
+ fZoom.setNewRange(0L, 0L);
+ }
+ super.clear();
+ }
+
+ /**
+ * Sets the time range of the histogram
+ * @param startTime The start time
+ * @param duration The duration of the time range
+ */
+ public synchronized void setTimeRange(long startTime, long duration) {
+ fRangeStartTime = startTime;
+ fRangeDuration = duration;
+ fZoom.setNewRange(startTime, duration);
+ if (getDataModel().getNbEvents() == 0) {
+ getDataModel().setTimeRange(startTime, startTime + duration);
+ getDataModel().setEndTime(startTime + duration);
+ }
+ }
+
+ /**
+ * Sets the full time range of the whole trace.
+ * @param startTime The start time
+ * @param endTime The end time
+ */
+ public void setFullRange(long startTime, long endTime) {
+ fFullRangeStartTime = startTime;
+ fFullRangeEndTime = endTime;
+ fZoom.setFullRange(startTime, endTime);
+ fZoom.setNewRange(fRangeStartTime, fRangeDuration);
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseListener
+ // ------------------------------------------------------------------------
+
+ private int fStartPosition;
+ private int fMinOffset;
+ private int fMaxOffset;
+
+ @Override
+ public void mouseDown(MouseEvent event) {
+ if (fScaledData != null && fDragState == DRAG_NONE && fDataModel.getStartTime() < fDataModel.getEndTime()) {
+ if (event.button == 2 || (event.button == 1 && (event.stateMask & SWT.MODIFIER_MASK) == SWT.CTRL)) {
+ fDragState = DRAG_RANGE;
+ fDragButton = event.button;
+ fStartPosition = event.x;
+ long maxOffset = (fRangeStartTime - fFullRangeStartTime) / fScaledData.fBucketDuration;
+ long minOffset = (fRangeStartTime + fRangeDuration - fFullRangeEndTime) / fScaledData.fBucketDuration;
+ fMaxOffset = (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, maxOffset));
+ fMinOffset = (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, minOffset));
+ return;
+ } else if (event.button == 3) {
+ fDragState = DRAG_ZOOM;
+ fDragButton = event.button;
+ fRangeStartTime = Math.min(getTimestamp(event.x), getEndTime());
+ fRangeDuration = 0;
+ fCanvas.redraw();
+ return;
+ }
+ }
+ super.mouseDown(event);
+ }
+
+ @Override
+ public void mouseUp(MouseEvent event) {
+ if (fDragState == DRAG_RANGE && event.button == fDragButton) {
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ if (event.x != fStartPosition) {
+ int nbBuckets = event.x - fStartPosition;
+ long delta = nbBuckets * fScaledData.fBucketDuration;
+ long startTime = fRangeStartTime - delta;
+ fRangeStartTime = Math.max(fFullRangeStartTime, Math.min(fFullRangeEndTime - fRangeDuration, startTime));
+ ((HistogramView) fParentView).updateTimeRange(fRangeStartTime, fRangeStartTime + fRangeDuration);
+ setOffset(0);
+ }
+ return;
+ } else if (fDragState == DRAG_ZOOM && event.button == fDragButton) {
+ fDragState = DRAG_NONE;
+ fDragButton = 0;
+ if (fRangeDuration < 0) {
+ fRangeStartTime = fRangeStartTime + fRangeDuration;
+ fRangeDuration = -fRangeDuration;
+ }
+ if (fRangeDuration > 0) {
+ ((HistogramView) fParentView).updateTimeRange(fRangeStartTime, fRangeStartTime + fRangeDuration);
+ } else {
+ fRangeStartTime = fZoom.getStartTime();
+ fRangeDuration = fZoom.getDuration();
+ fCanvas.redraw();
+ }
+ return;
+ }
+ super.mouseUp(event);
+ }
+
+ // ------------------------------------------------------------------------
+ // MouseMoveListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void mouseMove(MouseEvent event) {
+ if (fDragState == DRAG_RANGE) {
+ int offset = Math.max(fMinOffset, Math.min(fMaxOffset, event.x - fStartPosition));
+ setOffset(offset);
+ fCanvas.redraw();
+ return;
+ } else if (fDragState == DRAG_ZOOM) {
+ long endTime = Math.max(getStartTime(), Math.min(getEndTime(), getTimestamp(event.x)));
+ fRangeDuration = endTime - fRangeStartTime;
+ fCanvas.redraw();
+ return;
+ }
+ super.mouseMove(event);
+ }
+
+ // ------------------------------------------------------------------------
+ // PaintListener
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void paintControl(PaintEvent event) {
+ super.paintControl(event);
+
+ if (fDragState == DRAG_ZOOM) {
+ Image image = (Image) fCanvas.getData(IMAGE_KEY);
+ assert image != null;
+
+ Image rangeRectangleImage = new Image(image.getDevice(), image, SWT.IMAGE_COPY);
+ GC rangeWindowGC = new GC(rangeRectangleImage);
+
+ drawTimeRangeWindow(rangeWindowGC, fRangeStartTime, fRangeDuration);
+
+ // Draws the buffer image onto the canvas.
+ event.gc.drawImage(rangeRectangleImage, 0, 0);
+
+ rangeWindowGC.dispose();
+ rangeRectangleImage.dispose();
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/messages.properties
new file mode 100644
index 0000000000..116ec9acc3
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/histogram/messages.properties
@@ -0,0 +1,21 @@
+###############################################################################
+# Copyright (c) 2013, 2014 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+###############################################################################
+
+HistogramView_hideLostEvents=Hide Lost Events
+HistogramView_showTraces=Activate Trace Coloring
+HistogramView_selectionStartLabel=Selection Start
+HistogramView_selectionEndLabel=Selection End
+HistogramView_windowSpanLabel=Window Span
+Histogram_selectionSpanToolTip=Selection Span = {0}
+Histogram_bucketRangeToolTip=Bucket Range = [{0},{1})
+Histogram_eventCountToolTip=Event count = {0}
+Histogram_lostEventCountToolTip=Lost event count = {0}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/Messages.java
new file mode 100644
index 0000000000..10da8eef3a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/Messages.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alexandre Montplaisir - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.statesystem;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Localizable strings in the State System Visualizer.
+ *
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.statesystem.messages"; //$NON-NLS-1$
+
+ /**
+ * Initializer
+ */
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ /**
+ * Private constructor (static class)
+ */
+ private Messages() {}
+
+ /** Label for the first column */
+ public static String TreeNodeColumnLabel;
+
+ /** Label for the "quark" column" */
+ public static String QuarkColumnLabel;
+
+ /** Label for the "value" column */
+ public static String ValueColumnLabel;
+
+ /** Label for the "type" column
+ * @since 2.1*/
+ public static String TypeColumnLabel;
+
+ /** Label for the "start time" column */
+ public static String StartTimeColumLabel;
+
+ /** Label for the "end time" column */
+ public static String EndTimeColumLabel;
+
+ /** Label for the "attribute path" column */
+ public static String AttributePathColumnLabel;
+
+ /**
+ * Printing "out of range" in the value column when the current timestamp is
+ * outside of the SS's range.
+ */
+ public static String OutOfRangeMsg;
+
+ /** Label for the Filter button
+ * @since 2.1*/
+ public static String FilterButton;
+
+ /** Label for the type Interger
+ * @since 2.1*/
+ public static String TypeInteger;
+
+ /** Label for the type Long
+ * @since 2.1*/
+ public static String TypeLong;
+
+ /** Label for type Double
+ * @since 3.0*/
+ public static String TypeDouble;
+
+ /** Label for the type String
+ * @since 2.1*/
+ public static String TypeString;
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemExplorer.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemExplorer.java
new file mode 100644
index 0000000000..fb658c2370
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemExplorer.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 École Polytechnique de Montréal, Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ * Alexandre Montplaisir - Refactoring, performance tweaks
+ * Bernd Hufmann - Updated signal handling
+ * Marc-Andre Laperle - Add time zone preference
+ * Geneviève Bastien - Use a tree viewer instead of a tree
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.statesystem;
+
+import java.io.File;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * Displays the State System at a current time.
+ *
+ * @author Florian Wininger
+ * @author Alexandre Montplaisir
+ * @since 2.0
+ */
+public class TmfStateSystemExplorer extends TmfView {
+
+ /** The Environment View's ID */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.ssview"; //$NON-NLS-1$
+
+ private static final Image FILTER_IMAGE =
+ Activator.getDefault().getImageFromPath( File.separator + "icons" + File.separator + "elcl16" + File.separator + "filter_items.gif"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ private TmfStateSystemViewer fViewer;
+
+ /**
+ * Default constructor
+ */
+ public TmfStateSystemExplorer() {
+ super(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // ViewPart
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite parent) {
+
+ fViewer = new TmfStateSystemViewer(parent);
+
+ fillToolBar() ;
+
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ fViewer.traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+
+ }
+
+ // ------------------------------------------------------------------------
+ // Part For Button Action
+ // ------------------------------------------------------------------------
+
+ private void fillToolBar() {
+ Action fFilterAction = new FilterAction();
+ fFilterAction.setImageDescriptor(ImageDescriptor.createFromImage(FILTER_IMAGE));
+ fFilterAction.setToolTipText(Messages.FilterButton) ;
+ fFilterAction.setChecked(false);
+
+ IActionBars bars = getViewSite().getActionBars();
+ IToolBarManager manager = bars.getToolBarManager();
+ manager.add(fFilterAction);
+ }
+
+ private class FilterAction extends Action {
+ @Override
+ public void run() {
+ fViewer.changeFilterStatus();
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (fViewer != null) {
+ fViewer.dispose();
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemViewer.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemViewer.java
new file mode 100644
index 0000000000..1c732c1e44
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/TmfStateSystemViewer.java
@@ -0,0 +1,463 @@
+/*******************************************************************************
+ * Copyright (c) 2014 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Florian Wininger - Initial API and implementation
+ * Alexandre Montplaisir - Refactoring, performance tweaks
+ * Bernd Hufmann - Updated signal handling
+ * Marc-Andre Laperle - Add time zone preference
+ * Geneviève Bastien - Moved state system explorer to use the abstract tree viewer
+ * Patrick Tasse - Refactoring
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.statesystem;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.viewers.AbstractTreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.linuxtools.statesystem.core.ITmfStateSystem;
+import org.eclipse.linuxtools.statesystem.core.exceptions.AttributeNotFoundException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.StateSystemDisposedException;
+import org.eclipse.linuxtools.statesystem.core.exceptions.TimeRangeException;
+import org.eclipse.linuxtools.statesystem.core.interval.ITmfStateInterval;
+import org.eclipse.linuxtools.statesystem.core.statevalue.ITmfStateValue;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.tracecompass.tmf.core.statesystem.ITmfAnalysisModuleWithStateSystems;
+import org.eclipse.tracecompass.tmf.core.statesystem.TmfStateSystemAnalysisModule;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.viewers.tree.AbstractTmfTreeViewer;
+import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeColumnDataProvider;
+import org.eclipse.tracecompass.tmf.ui.viewers.tree.ITmfTreeViewerEntry;
+import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeColumnData;
+import org.eclipse.tracecompass.tmf.ui.viewers.tree.TmfTreeViewerEntry;
+
+/**
+ * Displays the content of the state systems at the current time
+ *
+ * @author Florian Wininger
+ * @author Alexandre Montplaisir
+ * @author Geneviève Bastien
+ * @since 3.0
+ */
+public class TmfStateSystemViewer extends AbstractTmfTreeViewer {
+
+ private static final String EMPTY_STRING = ""; //$NON-NLS-1$
+ private static final int DEFAULT_AUTOEXPAND = 2;
+ private boolean fFilterStatus = false;
+ private long fSelection = 0;
+
+ /* Order of columns */
+ private static final int ATTRIBUTE_NAME_COL = 0;
+ private static final int QUARK_COL = 1;
+ private static final int VALUE_COL = 2;
+ private static final int TYPE_COL = 3;
+ private static final int START_TIME_COL = 4;
+ private static final int END_TIME_COL = 5;
+ private static final int ATTRIBUTE_FULLPATH_COL = 6;
+
+ /**
+ * Base class to provide the labels for the tree viewer. Views extending
+ * this class typically need to override the getColumnText method if they
+ * have more than one column to display
+ */
+ protected static class StateSystemTreeLabelProvider extends TreeLabelProvider {
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof StateEntry) {
+ StateEntry entry = (StateEntry) element;
+ switch (columnIndex) {
+ case ATTRIBUTE_NAME_COL:
+ return entry.getName();
+ case QUARK_COL:
+ return String.valueOf(entry.getQuark());
+ case VALUE_COL:
+ return entry.getValue();
+ case TYPE_COL:
+ return entry.getType();
+ case START_TIME_COL:
+ return entry.getStartTime();
+ case END_TIME_COL:
+ return entry.getEndTime();
+ case ATTRIBUTE_FULLPATH_COL:
+ return entry.getFullPath();
+ default:
+ return EMPTY_STRING;
+ }
+ }
+ return super.getColumnText(element, columnIndex);
+ }
+
+ @Override
+ public Color getBackground(Object element, int columnIndex) {
+ if (element instanceof StateEntry) {
+ if (((StateEntry) element).isModified()) {
+ return Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW);
+ }
+ }
+ return super.getBackground(element, columnIndex);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param parent
+ * The parent containing this viewer
+ */
+ public TmfStateSystemViewer(Composite parent) {
+ super(parent, false);
+ this.setLabelProvider(new StateSystemTreeLabelProvider());
+ getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND);
+ }
+
+ @Override
+ protected ITmfTreeColumnDataProvider getColumnDataProvider() {
+ return new ITmfTreeColumnDataProvider() {
+
+ @Override
+ public List<TmfTreeColumnData> getColumnData() {
+ List<TmfTreeColumnData> columns = new ArrayList<>();
+ TmfTreeColumnData column = new TmfTreeColumnData(Messages.TreeNodeColumnLabel);
+ columns.add(column);
+ column.setComparator(new ViewerComparator() {
+ @Override
+ public int compare(Viewer viewer, Object e1, Object e2) {
+ TmfTreeViewerEntry n1 = (TmfTreeViewerEntry) e1;
+ TmfTreeViewerEntry n2 = (TmfTreeViewerEntry) e2;
+
+ return n1.getName().compareTo(n2.getName());
+ }
+ });
+ columns.add(new TmfTreeColumnData(Messages.QuarkColumnLabel));
+ columns.add(new TmfTreeColumnData(Messages.ValueColumnLabel));
+ columns.add(new TmfTreeColumnData(Messages.TypeColumnLabel));
+ columns.add(new TmfTreeColumnData(Messages.StartTimeColumLabel));
+ columns.add(new TmfTreeColumnData(Messages.EndTimeColumLabel));
+ columns.add(new TmfTreeColumnData(Messages.AttributePathColumnLabel));
+ return columns;
+ }
+
+ };
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected ITmfTreeViewerEntry updateElements(long start, long end, boolean selection) {
+
+ if (selection) {
+ fSelection = start;
+ } else {
+ fSelection = TmfTraceManager.getInstance().getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ }
+
+ if (getTrace() == null) {
+ return null;
+ }
+
+ ITmfTreeViewerEntry root = getInput();
+
+ if (root == null) {
+ root = createRoot();
+ } else if (fFilterStatus) {
+ clearStateSystemEntries(root);
+ }
+
+ /*
+ * Update the values of the elements of the state systems at the
+ * selection start time
+ */
+ boolean changed = updateStateSystemEntries(root, fSelection);
+
+ return selection || changed ? root : null;
+ }
+
+ private ITmfTreeViewerEntry createRoot() {
+ // 'Fake' root node
+ TmfTreeViewerEntry rootEntry = new TmfTreeViewerEntry("root"); //$NON-NLS-1$
+
+ for (final ITmfTrace trace : TmfTraceManager.getTraceSetWithExperiment(getTrace())) {
+ if (trace != null) {
+ rootEntry.addChild(createTraceEntry(trace));
+ }
+ }
+ return rootEntry;
+ }
+
+ private static TmfTreeViewerEntry createTraceEntry(ITmfTrace trace) {
+ TmfTreeViewerEntry traceEntry = new TmfTreeViewerEntry(trace.getName());
+ Iterable<ITmfAnalysisModuleWithStateSystems> modules = trace.getAnalysisModulesOfClass(ITmfAnalysisModuleWithStateSystems.class);
+ for (ITmfAnalysisModuleWithStateSystems module : modules) {
+ /* Just schedule the module, the data will be filled when available */
+ module.schedule();
+ if (module instanceof TmfStateSystemAnalysisModule) {
+ // TODO: add this method to ITmfAnalysisModuleWithStateSystems
+ ((TmfStateSystemAnalysisModule) module).waitForInitialization();
+ }
+ for (ITmfStateSystem ss : module.getStateSystems()) {
+ if (ss != null) {
+ traceEntry.addChild(new StateSystemEntry(ss));
+ }
+ }
+ }
+ return traceEntry;
+ }
+
+ private static void clearStateSystemEntries(ITmfTreeViewerEntry root) {
+ for (ITmfTreeViewerEntry traceEntry : root.getChildren()) {
+ for (ITmfTreeViewerEntry ssEntry : traceEntry.getChildren()) {
+ ssEntry.getChildren().clear();
+ }
+ }
+ }
+
+ private boolean updateStateSystemEntries(ITmfTreeViewerEntry root, long timestamp) {
+ boolean changed = false;
+ for (ITmfTreeViewerEntry traceEntry : root.getChildren()) {
+ for (ITmfTreeViewerEntry ssEntry : traceEntry.getChildren()) {
+ StateSystemEntry stateSystemEntry = (StateSystemEntry) ssEntry;
+ ITmfStateSystem ss = stateSystemEntry.getSS();
+ try {
+ List<ITmfStateInterval> fullState = ss.queryFullState(timestamp);
+ changed |= updateStateEntries(ss, fullState, stateSystemEntry, -1, timestamp);
+ } catch (TimeRangeException e) {
+ markOutOfRange(stateSystemEntry);
+ changed = true;
+ } catch (StateSystemDisposedException e) {
+ /* Ignored */
+ }
+ }
+ }
+ return changed;
+ }
+
+ private boolean updateStateEntries(ITmfStateSystem ss, List<ITmfStateInterval> fullState, TmfTreeViewerEntry parent, int parentQuark, long timestamp) {
+ boolean changed = false;
+ try {
+ for (int quark : ss.getSubAttributes(parentQuark, false)) {
+ if (quark >= fullState.size()) {
+ // attribute was created after the full state query
+ continue;
+ }
+ ITmfStateInterval interval = fullState.get(quark);
+ StateEntry stateEntry = findStateEntry(parent, quark);
+ if (stateEntry == null) {
+ boolean modified = fFilterStatus ?
+ interval.getStartTime() == timestamp :
+ !interval.getStateValue().isNull();
+ stateEntry = new StateEntry(ss.getAttributeName(quark), quark, ss.getFullAttributePath(quark),
+ interval.getStateValue(),
+ new TmfTimestamp(interval.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE),
+ new TmfTimestamp(interval.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE),
+ modified);
+
+ // update children first to know if parent is really needed
+ updateStateEntries(ss, fullState, stateEntry, quark, timestamp);
+
+ /*
+ * Add this entry to parent if filtering is off, or
+ * if the entry has children to display, or
+ * if there is a state change at the current timestamp
+ */
+ if (!fFilterStatus || stateEntry.hasChildren() || interval.getStartTime() == timestamp) {
+ parent.addChild(stateEntry);
+ changed = true;
+ }
+ } else {
+ stateEntry.update(interval.getStateValue(),
+ new TmfTimestamp(interval.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE),
+ new TmfTimestamp(interval.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE));
+
+ // update children recursively
+ updateStateEntries(ss, fullState, stateEntry, quark, timestamp);
+ }
+
+ }
+ } catch (AttributeNotFoundException e) {
+ /* Should not happen, we're iterating on known attributes */
+ }
+ return changed;
+ }
+
+ private static StateEntry findStateEntry(TmfTreeViewerEntry parent, int quark) {
+ for (ITmfTreeViewerEntry child : parent.getChildren()) {
+ StateEntry stateEntry = (StateEntry) child;
+ if (stateEntry.getQuark() == quark) {
+ return stateEntry;
+ }
+ }
+ return null;
+ }
+ /**
+ * Set the entries as out of range
+ */
+ private static void markOutOfRange(ITmfTreeViewerEntry parent) {
+ for (ITmfTreeViewerEntry entry : parent.getChildren()) {
+ if (entry instanceof StateEntry) {
+ ((StateEntry) entry).setOutOfRange();
+
+ /* Update this node's children recursively */
+ markOutOfRange(entry);
+ }
+ }
+ }
+
+ /**
+ * Set the filter status of the viewer. By default, all entries of all state
+ * system are present, and the values that changed since last refresh are
+ * shown in yellow. When the filter status is true, only the entries with
+ * values modified at current time are displayed.
+ */
+ public void changeFilterStatus() {
+ fFilterStatus = !fFilterStatus;
+ if (fFilterStatus) {
+ getTreeViewer().setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
+ } else {
+ getTreeViewer().setAutoExpandLevel(DEFAULT_AUTOEXPAND);
+ clearContent();
+ }
+ updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
+ }
+
+ /**
+ * Update the display to use the updated timestamp format
+ *
+ * @param signal
+ * the incoming signal
+ */
+ @TmfSignalHandler
+ public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
+ updateContent(getSelectionBeginTime(), getSelectionEndTime(), true);
+ }
+
+ private static class StateSystemEntry extends TmfTreeViewerEntry {
+ private final @NonNull ITmfStateSystem fSS;
+
+ public StateSystemEntry(@NonNull ITmfStateSystem ss) {
+ super(ss.getSSID());
+ fSS = ss;
+ }
+
+ public @NonNull ITmfStateSystem getSS() {
+ return fSS;
+ }
+ }
+
+ private class StateEntry extends TmfTreeViewerEntry {
+
+ private final int fQuark;
+ private final String fFullPath;
+ private @NonNull TmfTimestamp fStart;
+ private @NonNull TmfTimestamp fEnd;
+ private ITmfStateValue fValue;
+ private boolean fModified;
+ private boolean fOutOfRange = false;
+
+ public StateEntry(String name, int quark, String fullPath, ITmfStateValue value, @NonNull TmfTimestamp start, @NonNull TmfTimestamp end, boolean modified) {
+ super(name);
+ fQuark = quark;
+ fFullPath = fullPath;
+ fStart = start;
+ fEnd = end;
+ fValue = value;
+ fModified = modified;
+ }
+
+ public int getQuark() {
+ return fQuark;
+ }
+
+ public String getFullPath() {
+ return fFullPath;
+ }
+
+ public String getStartTime() {
+ if (fOutOfRange) {
+ return EMPTY_STRING;
+ }
+ return fStart.toString();
+ }
+
+ public String getEndTime() {
+ if (fOutOfRange) {
+ return EMPTY_STRING;
+ }
+ return fEnd.toString();
+ }
+
+ public String getValue() {
+ if (fOutOfRange) {
+ return Messages.OutOfRangeMsg;
+ }
+ switch (fValue.getType()) {
+ case INTEGER:
+ case LONG:
+ case DOUBLE:
+ case STRING:
+ return fValue.toString();
+ case NULL:
+ default:
+ return EMPTY_STRING;
+ }
+ }
+
+ public String getType() {
+ if (fOutOfRange) {
+ return EMPTY_STRING;
+ }
+ switch (fValue.getType()) {
+ case INTEGER:
+ return Messages.TypeInteger;
+ case LONG:
+ return Messages.TypeLong;
+ case DOUBLE:
+ return Messages.TypeDouble;
+ case STRING:
+ return Messages.TypeString;
+ case NULL:
+ default:
+ return EMPTY_STRING;
+ }
+ }
+
+ public boolean isModified() {
+ return fModified;
+ }
+
+ public void update(ITmfStateValue value, @NonNull TmfTimestamp start, @NonNull TmfTimestamp end) {
+ fModified = false;
+ fOutOfRange = false;
+ if (!start.equals(fStart)) {
+ fModified = true;
+ fStart = start;
+ fEnd = end;
+ fValue = value;
+ }
+ }
+
+ public void setOutOfRange() {
+ fModified = false;
+ fOutOfRange = true;
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/messages.properties
new file mode 100644
index 0000000000..33a5a3d741
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statesystem/messages.properties
@@ -0,0 +1,28 @@
+###############################################################################
+# Copyright (c) 2013 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+###############################################################################
+
+# Column names
+TreeNodeColumnLabel=State System / Attribute
+QuarkColumnLabel=Quark
+ValueColumnLabel=Value at timestamp
+TypeColumnLabel=Type
+StartTimeColumLabel=Start time
+EndTimeColumLabel=End time
+AttributePathColumnLabel=Full attribute path
+
+# Other messages
+OutOfRangeMsg=Out of Range
+FilterButton=Only Display Changes at Selected Timestamp
+TypeInteger=Int
+TypeLong=Long
+TypeDouble=Double
+TypeString=String
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/Messages.java
new file mode 100755
index 0000000000..3824dc61f5
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/Messages.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Initial API and Implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.statistics;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages file for statistics view strings.
+ *
+ * @version 2.0
+ * @author Mathieu Denis
+ * @since 2.0
+ */
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.statistics.messages"; //$NON-NLS-1$
+
+ /**
+ * String for the global tab name
+ * @since 2.0
+ */
+ public static String TmfStatisticsView_GlobalTabName;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/TmfStatisticsView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/TmfStatisticsView.java
new file mode 100755
index 0000000000..01e772e1e0
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/TmfStatisticsView.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mathieu Denis <mathieu.denis@polymtl.ca> - Generalized version based on LTTng
+ * Bernd Hufmann - Updated to use trace reference in TmfEvent and streaming
+ * Mathieu Denis - New request added to update the statistics from the selected time range
+ * Mathieu Denis - Generalization of the view to instantiate a viewer specific to a trace type
+ *
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.statistics;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.viewers.ITmfViewer;
+import org.eclipse.tracecompass.tmf.ui.viewers.statistics.TmfStatisticsViewer;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.widgets.tabsview.TmfViewerFolder;
+
+/**
+ * The generic Statistics View displays statistics for any kind of traces.
+ *
+ * It is implemented according to the MVC pattern. - The model is a
+ * TmfStatisticsTreeNode built by the State Manager. - The view is built with a
+ * TreeViewer. - The controller that keeps model and view synchronized is an
+ * observer of the model.
+ *
+ * @version 2.0
+ * @author Mathieu Denis
+ */
+public class TmfStatisticsView extends TmfView {
+
+ /**
+ * The ID corresponds to the package in which this class is embedded.
+ */
+ public static final @NonNull String ID = "org.eclipse.linuxtools.tmf.ui.views.statistics"; //$NON-NLS-1$
+
+ /**
+ * The view name.
+ */
+ public static final String TMF_STATISTICS_VIEW = "StatisticsView"; //$NON-NLS-1$
+
+ /**
+ * The viewer that builds the columns to show the statistics.
+ *
+ * @since 2.0
+ */
+ protected final TmfViewerFolder fStatsViewers;
+
+ /**
+ * Stores a reference to the selected trace.
+ */
+ private ITmfTrace fTrace;
+
+ /**
+ * Constructor of a statistics view.
+ *
+ * @param viewName The name to give to the view.
+ */
+ public TmfStatisticsView(String viewName) {
+ super(viewName);
+ /*
+ * Create a fake parent for initialization purpose, than set the parent
+ * as soon as createPartControl is called.
+ */
+ Composite temporaryParent = new Shell();
+ fStatsViewers = new TmfViewerFolder(temporaryParent);
+ }
+
+ /**
+ * Default constructor.
+ */
+ public TmfStatisticsView() {
+ this(TMF_STATISTICS_VIEW);
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ fStatsViewers.setParent(parent);
+ createStatisticsViewers();
+
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ fStatsViewers.dispose();
+ }
+
+ /**
+ * Handler called when an trace is opened.
+ *
+ * @param signal
+ * Contains the information about the selection.
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ /*
+ * Dispose the current viewer and adapt the new one to the trace
+ * type of the trace opened
+ */
+ fStatsViewers.clear();
+ // Update the current trace
+ fTrace = signal.getTrace();
+ createStatisticsViewers();
+ fStatsViewers.layout();
+ }
+
+ /**
+ * Handler called when an trace is selected. Checks if the trace
+ * has changed and requests the selected trace if it has not yet been
+ * cached.
+ *
+ * @param signal
+ * Contains the information about the selection.
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ // Does not reload the same trace if already opened
+ if (signal.getTrace() != fTrace) {
+ /*
+ * Dispose the current viewer and adapt the new one to the trace
+ * type of the trace selected
+ */
+ fStatsViewers.clear();
+ // Update the current trace
+ fTrace = signal.getTrace();
+ createStatisticsViewers();
+ fStatsViewers.layout();
+
+ TmfTraceRangeUpdatedSignal updateSignal = new TmfTraceRangeUpdatedSignal(this, fTrace, fTrace.getTimeRange());
+
+ for (ITmfViewer viewer : fStatsViewers.getViewers()) {
+ TmfStatisticsViewer statsViewer = (TmfStatisticsViewer) viewer;
+ statsViewer.sendPartialRequestOnNextUpdate();
+ statsViewer.traceRangeUpdated(updateSignal);
+ }
+ } else {
+ /*
+ * If the same trace is reselected, sends a notification to
+ * the viewers to make sure they reload correctly their partial
+ * event count.
+ */
+ for (ITmfViewer viewer : fStatsViewers.getViewers()) {
+ TmfStatisticsViewer statsViewer = (TmfStatisticsViewer) viewer;
+ // Will update the partial event count if needed.
+ statsViewer.sendPartialRequestOnNextUpdate();
+ }
+ }
+ }
+
+ /**
+ * @param signal the incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+
+ // Clear the internal data
+ fTrace = null;
+
+ // Clear the UI widgets
+ fStatsViewers.clear(); // Also cancels ongoing requests
+ createStatisticsViewers();
+ fStatsViewers.layout();
+ }
+
+ @Override
+ public void setFocus() {
+ fStatsViewers.setFocus();
+ }
+
+ /**
+ * Creates the statistics viewers for all traces in an experiment and
+ * populates a viewer folder. Each viewer is placed in a different tab and
+ * the first one is selected automatically.
+ *
+ * It uses the extension point that defines the statistics viewer to build
+ * from the trace type. If no viewer is defined, another tab won't be
+ * created, since the global viewer already contains all the basic
+ * statistics. If there is no trace selected, a global statistics viewer will
+ * still be created.
+ *
+ * @since 2.0
+ */
+ protected void createStatisticsViewers() {
+ // Default style for the tabs that will be created
+ int defaultStyle = SWT.NONE;
+
+ // The folder composite that will contain the tabs
+ Composite folder = fStatsViewers.getParentFolder();
+
+ // Instantiation of the global viewer
+ if (fTrace != null) {
+ // Shows the name of the trace in the global tab
+ TmfStatisticsViewer globalViewer = new TmfStatisticsViewer(folder, Messages.TmfStatisticsView_GlobalTabName + " - " + fTrace.getName(), fTrace); //$NON-NLS-1$
+ fStatsViewers.addTab(globalViewer, Messages.TmfStatisticsView_GlobalTabName, defaultStyle);
+
+ } else {
+ // There is no trace selected. Shows an empty global tab
+ TmfStatisticsViewer globalViewer = new TmfStatisticsViewer(folder, Messages.TmfStatisticsView_GlobalTabName, fTrace);
+ fStatsViewers.addTab(globalViewer, Messages.TmfStatisticsView_GlobalTabName, defaultStyle);
+ }
+ // Makes the global viewer visible
+ fStatsViewers.setSelection(0);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/messages.properties
new file mode 100755
index 0000000000..1a7d06c1e2
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/statistics/messages.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2013 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+###############################################################################
+
+TmfStatisticsView_GlobalTabName=Global
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/Messages.java
new file mode 100644
index 0000000000..e2e6f03b73
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/Messages.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2013 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial implementation and API
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.synchronization;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Message file for the synchronization view
+ * @since 3.0
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.synchronization.messages"; //$NON-NLS-1$
+ public static String TmfSynchronizationView_NameColumn;
+ public static String TmfSynchronizationView_ValueColumn;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/TmfSynchronizationView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/TmfSynchronizationView.java
new file mode 100644
index 0000000000..8021e1dabb
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/TmfSynchronizationView.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2013 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial implementation and API
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.synchronization;
+
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSynchronizedSignal;
+import org.eclipse.tracecompass.tmf.core.synchronization.SynchronizationAlgorithm;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfExperiment;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+
+/**
+ * Small view to display statistics about a synchronization
+ *
+ * @author Geneviève Bastien
+ * @since 3.0
+ */
+public class TmfSynchronizationView extends TmfView {
+
+ /**
+ * The ID corresponds to the package in which this class is embedded.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.synchronization"; //$NON-NLS-1$
+
+ /**
+ * The view name.
+ */
+ public static final String TMF_SYNCHRONIZATION_VIEW = "SynchronizationView"; //$NON-NLS-1$
+
+ /**
+ * The synchronization algorithm to display stats for
+ */
+ private SynchronizationAlgorithm fAlgoSync;
+
+ private Tree fTree;
+
+ /**
+ * Default constructor
+ */
+ public TmfSynchronizationView() {
+ super(TMF_SYNCHRONIZATION_VIEW);
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ fTree = new Tree(parent, SWT.NONE);
+ TreeColumn nameCol = new TreeColumn(fTree, SWT.NONE, 0);
+ TreeColumn valueCol = new TreeColumn(fTree, SWT.NONE, 1);
+ nameCol.setText(Messages.TmfSynchronizationView_NameColumn);
+ valueCol.setText(Messages.TmfSynchronizationView_ValueColumn);
+
+ fTree.setItemCount(0);
+
+ fTree.setHeaderVisible(true);
+ nameCol.pack();
+ valueCol.pack();
+
+ ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+ }
+
+ private void updateTable() {
+ fTree.setItemCount(0);
+ if (fAlgoSync == null) {
+ return;
+ }
+
+ for (Map.Entry<String, Map<String, Object>> entry : fAlgoSync.getStats().entrySet()) {
+ TreeItem item = new TreeItem(fTree, SWT.NONE);
+ item.setText(0, entry.getKey().toString());
+ item.setText(1, entry.getValue().toString());
+
+ for (Map.Entry<String, Object> subentry : entry.getValue().entrySet()) {
+ TreeItem subitem = new TreeItem(item, SWT.NONE);
+ subitem.setText(0, subentry.getKey().toString());
+ subitem.setText(1, subentry.getValue().toString());
+ }
+ }
+
+ /* Expand the tree items */
+ for (int i = 0; i < fTree.getItemCount(); i++) {
+ fTree.getItem(i).setExpanded(true);
+ }
+
+ for (TreeColumn column : fTree.getColumns()) {
+ column.pack();
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ fTree.setFocus();
+ }
+
+ /**
+ * Handler called when a trace is selected
+ *
+ * @param signal
+ * Contains information about the selected trace
+ * @since 3.1
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ fAlgoSync = null;
+ if (signal.getTrace() instanceof TmfExperiment) {
+ fAlgoSync = ((TmfExperiment) signal.getTrace()).synchronizeTraces();
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ updateTable();
+ }
+ });
+ }
+
+ /**
+ * Handler called when traces are synchronized
+ *
+ * @param signal
+ * Contains the information about the selection.
+ */
+ @TmfSignalHandler
+ public void traceSynchronized(TmfTraceSynchronizedSignal signal) {
+ if (signal.getSyncAlgo() != fAlgoSync) {
+ fAlgoSync = signal.getSyncAlgo();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ updateTable();
+ }
+ });
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/messages.properties
new file mode 100644
index 0000000000..86c84fe49e
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/synchronization/messages.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2014 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+###############################################################################
+TmfSynchronizationView_NameColumn=Synchronization Information
+TmfSynchronizationView_ValueColumn=Value
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisEntry.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisEntry.java
new file mode 100644
index 0000000000..512b0e223f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisEntry.java
@@ -0,0 +1,277 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timechart;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+
+/**
+ * An entry (row) in the time chart analysis view
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeChartAnalysisEntry implements ITimeGraphEntry {
+
+ private final ITmfTrace fTrace;
+ private final Vector<TimeChartEvent> fTraceEvents;
+ private int fPower = 0; // 2^fPower nanoseconds per vector position
+ private long fReferenceTime = -1; // time corresponding to beginning of index 0
+ private long fStartTime = -1; // time of first event
+ private long fStopTime = -1; // time of last event
+ private long fLastRank = -1; // rank of last processed trace event
+
+ TimeChartAnalysisEntry(ITmfTrace trace, int modelSize) {
+ fTrace = trace;
+ fTraceEvents = new Vector<>(modelSize);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public List<ITimeGraphEntry> getChildren() {
+ return null;
+ }
+
+ @Override
+ public ITimeGraphEntry getParent() {
+ return null;
+ }
+
+ @Override
+ public boolean hasChildren() {
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ return fTrace.getName();
+ }
+
+ @Override
+ public long getStartTime() {
+ return fStartTime;
+ }
+
+ @Override
+ public long getEndTime() {
+ return fStopTime;
+ }
+
+ @Override
+ public boolean hasTimeEvents() {
+ return true;
+ }
+
+ @Override
+ public Iterator<ITimeEvent> getTimeEventsIterator() {
+ return new EntryIterator(0, Long.MAX_VALUE, 0);
+ }
+
+ @Override
+ public Iterator<ITimeEvent> getTimeEventsIterator(long startTime, long stopTime, long maxDuration) {
+ return new EntryIterator(startTime, stopTime, maxDuration);
+ }
+
+ private class EntryIterator implements Iterator<ITimeEvent> {
+ private final long fIteratorStartTime;
+ private final long fIteratorStopTime;
+ private final long fIteratorMaxDuration;
+ private long lastTime = -1;
+ private TimeChartEvent next = null;
+ private Iterator<ITimeEvent> nestedIterator = null;
+
+ public EntryIterator(long startTime, long stopTime, long maxDuration) {
+ fIteratorStartTime = startTime;
+ fIteratorStopTime = stopTime;
+ fIteratorMaxDuration = maxDuration;
+ }
+
+ @Override
+ public boolean hasNext() {
+ synchronized (fTraceEvents) {
+ if (next != null) {
+ return true;
+ }
+ if (nestedIterator != null) {
+ if (nestedIterator.hasNext()) {
+ return true;
+ }
+ nestedIterator = null;
+ }
+ long time = (lastTime == -1) ? fStartTime : lastTime;
+ int index = (fReferenceTime == -1) ? 0 : (int) ((time - fReferenceTime) >> fPower);
+ while (index < fTraceEvents.size()) {
+ TimeChartEvent event = fTraceEvents.get(index++);
+ if (event != null && (lastTime == -1 || event.getTime() > time)) {
+ if (event.getTime() + event.getDuration() >= fIteratorStartTime && event.getTime() <= fIteratorStopTime) {
+ if (event.getItemizedEntry() == null || event.getDuration() <= fIteratorMaxDuration) {
+ lastTime = event.getTime() + event.getDuration();
+ next = event;
+ return true;
+ }
+ nestedIterator = event.getItemizedEntry().getTimeEventsIterator(fIteratorStartTime, fIteratorStopTime, fIteratorMaxDuration);
+ return nestedIterator.hasNext();
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public TimeChartEvent next() {
+ synchronized (fTraceEvents) {
+ if (nestedIterator != null) {
+ TimeChartEvent event = (TimeChartEvent) nestedIterator.next();
+ lastTime = event.getTime() + event.getDuration();
+ return event;
+ }
+ if (hasNext()) {
+ TimeChartEvent event = next;
+ next = null;
+ return event;
+ }
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+ /**
+ * Add a time event to the time chart entry
+ *
+ * @param timeEvent
+ * The event to add
+ */
+ public void addTraceEvent(ITimeEvent timeEvent) {
+ long time = timeEvent.getTime();
+ synchronized (fTraceEvents) {
+ long index = (fReferenceTime == -1) ? 0 : (time - fReferenceTime) >> fPower;
+ if (index < 0) {
+ if (fTraceEvents.capacity() - fTraceEvents.size() < -index) {
+ int powershift = (-index + fTraceEvents.size() <= 2 * fTraceEvents.capacity()) ? 1 :
+ (int) Math.ceil(Math.log((double) (-index + fTraceEvents.size()) / fTraceEvents.capacity()) / Math.log(2));
+ merge(powershift);
+ index = (int) ((time - fReferenceTime) >> fPower);
+ }
+ shift((int) -index);
+ index = 0;
+ fTraceEvents.set(0, (TimeChartEvent) timeEvent);
+ } else if (index < fTraceEvents.capacity()) {
+ if (index >= fTraceEvents.size()) {
+ fTraceEvents.setSize((int) index + 1);
+ }
+ } else {
+ int powershift = (index < 2 * fTraceEvents.capacity()) ? 1 :
+ (int) Math.ceil(Math.log((double) (index + 1) / fTraceEvents.capacity()) / Math.log(2));
+ merge(powershift);
+ index = (int) ((time - fReferenceTime) >> fPower);
+ fTraceEvents.setSize((int) index + 1);
+ }
+ TimeChartEvent event = fTraceEvents.get((int) index);
+ if (event == null) {
+ fTraceEvents.set((int) index, (TimeChartEvent) timeEvent);
+ } else {
+ if (event.getItemizedEntry() == null) {
+ event.merge((TimeChartEvent) timeEvent);
+ } else {
+ event.mergeDecorations((TimeChartEvent) timeEvent);
+ event.getItemizedEntry().addTraceEvent(timeEvent);
+ }
+ }
+ if (fReferenceTime == -1 || time < fReferenceTime) {
+ fReferenceTime = (time >> fPower) << fPower;
+ }
+ if (fStartTime == -1 || time < fStartTime) {
+ fStartTime = time;
+ }
+ if (fStopTime == -1 || time > fStopTime) {
+ fStopTime = time;
+ }
+ }
+ }
+
+ private void merge(int powershift) {
+ fPower += powershift;
+ fReferenceTime = (fReferenceTime >> fPower) << fPower;
+ int index = 0;
+ for (int i = 0; i < fTraceEvents.size(); i++) {
+ TimeChartEvent event = fTraceEvents.get(i);
+ if (event != null) {
+ index = (int) ((event.getTime() - fReferenceTime) >> fPower);
+ TimeChartEvent mergedEvent = fTraceEvents.get(index);
+ if (mergedEvent == null) {
+ fTraceEvents.set(index, event);
+ } else {
+ mergedEvent.merge(event);
+ }
+ if (i != index) {
+ fTraceEvents.set(i, null);
+ }
+ }
+ }
+ fTraceEvents.setSize(index + 1);
+ }
+
+ private void shift(int indexshift) {
+ int oldSize = fTraceEvents.size();
+ fTraceEvents.setSize(oldSize + indexshift);
+ for (int i = oldSize - 1; i >= 0; i--) {
+ fTraceEvents.set(i + indexshift, fTraceEvents.get(i));
+ }
+ for (int i = 0; i < indexshift; i++) {
+ fTraceEvents.set(i, null);
+ }
+ }
+
+ /**
+ * Retrieve the trace associated with this entry
+ *
+ * @return The trace object
+ */
+ public ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Set the last rank of the entry
+ *
+ * @param rank
+ * The rank to set
+ */
+ public void setLastRank(long rank) {
+ fLastRank = rank;
+ }
+
+ /**
+ * Retrieve the last rank of the entry
+ *
+ * @return The last rank
+ */
+ public long getLastRank() {
+ return fLastRank;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisProvider.java
new file mode 100644
index 0000000000..ba935bdd87
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartAnalysisProvider.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timechart;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting;
+import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.StateItem;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+
+/**
+ * Provider for a time chart analysis view
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeChartAnalysisProvider extends TimeGraphPresentationProvider {
+
+ private static final Color BOOKMARK_INNER_COLOR = new Color(Display.getDefault(), 115, 165, 224);
+ private static final Color BOOKMARK_OUTER_COLOR = new Color(Display.getDefault(), 2, 70, 140);
+ private static final Color SEARCH_MATCH_COLOR = new Color(Display.getDefault(), 177, 118, 14);
+
+ private int lastX = Integer.MIN_VALUE;
+ private int currX = Integer.MIN_VALUE;
+ private int lastPriority;
+ private int lastBookmarkX = Integer.MIN_VALUE;
+
+ @Override
+ public StateItem[] getStateTable() {
+
+ ColorSetting[] settings = ColorSettingsManager.getColorSettings();
+ StateItem[] stateItems = new StateItem[settings.length];
+ for (int i = 0; i < settings.length; i++) {
+ stateItems[i] = new StateItem(settings[i].getTickColorRGB());
+ }
+ return stateItems;
+ }
+
+ @Override
+ public int getStateTableIndex(ITimeEvent event) {
+ if (! ((TimeChartEvent) event).isVisible()) {
+ return ITimeGraphPresentationProvider.INVISIBLE;
+ }
+ int priority = ((TimeChartEvent) event).getColorSettingPriority();
+ if (currX == lastX) {
+ priority = Math.min(priority, lastPriority);
+ }
+ lastPriority = priority;
+ return priority;
+ }
+
+ @Override
+ public void postDrawEvent(ITimeEvent event, Rectangle rect, GC gc) {
+ if (! ((TimeChartEvent) event).isVisible()) {
+ return;
+ }
+ lastX = currX;
+ currX = rect.x;
+ if (lastBookmarkX == rect.x || ((TimeChartEvent) event).isBookmarked()) {
+ drawBookmark(rect, gc);
+ lastBookmarkX = rect.x;
+ } else if (lastBookmarkX == rect.x - 1) {
+ Rectangle r = new Rectangle(lastBookmarkX, rect.y, rect.width, rect.height);
+ drawBookmark(r, gc);
+ } else {
+ lastBookmarkX = Integer.MIN_VALUE;
+ }
+ if (((TimeChartEvent) event).isSearchMatch()) {
+ drawSearchMatch(rect, gc);
+ }
+ }
+
+ private static void drawBookmark(Rectangle r, GC gc) {
+ gc.setForeground(BOOKMARK_OUTER_COLOR);
+ gc.drawLine(r.x - 1, r.y - 2, r.x - 1, r.y + 2);
+ gc.drawLine(r.x + 1, r.y - 2, r.x + 1, r.y + 2);
+ gc.drawPoint(r.x, r.y - 2);
+ gc.setForeground(BOOKMARK_INNER_COLOR);
+ gc.drawLine(r.x, r.y - 1, r.x, r.y + 1);
+ gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
+ gc.drawPoint(r.x - 1, r.y + 3);
+ gc.drawPoint(r.x, r.y + 2);
+ gc.drawPoint(r.x + 1, r.y + 3);
+ }
+
+ private static void drawSearchMatch(Rectangle r, GC gc) {
+ gc.setForeground(SEARCH_MATCH_COLOR);
+ gc.drawPoint(r.x, r.y + r.height);
+ gc.drawLine(r.x - 1, r.y + r.height + 1, r.x + 1, r.y + r.height + 1);
+ gc.drawLine(r.x - 2, r.y + r.height + 2, r.x + 2, r.y + r.height + 2);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartDecorationProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartDecorationProvider.java
new file mode 100644
index 0000000000..1dbd59dd0f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartDecorationProvider.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timechart;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.filter.ITmfFilter;
+
+/**
+ * Provider for decorations in the time chart view
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeChartDecorationProvider {
+
+ private final IFile fBookmarksFile;
+ private final Set<Long> fBookmarksSet = new HashSet<>();
+ private ITmfFilter fFilterFilter;
+ private ITmfFilter fSearchFilter;
+
+ /**
+ * Constructor
+ *
+ * @param bookmarksFile
+ * Bookmark file associated with the trace
+ */
+ public TimeChartDecorationProvider(IFile bookmarksFile) {
+ fBookmarksFile = bookmarksFile;
+ refreshBookmarks();
+ }
+
+ /**
+ * Retrieve the bookmark file that was assigned to this provider
+ *
+ * @return The bookmark file
+ */
+ public IFile getBookmarksFile() {
+ return fBookmarksFile;
+ }
+
+ /**
+ * Verify if the selected rank has a bookmark assigned to it.
+ *
+ * @param rank
+ * The rank to check for
+ * @return If there is a bookmark there
+ */
+ public boolean isBookmark(long rank) {
+ return fBookmarksSet.contains(rank);
+ }
+
+ /**
+ * Refresh the bookmark display.
+ */
+ public void refreshBookmarks() {
+ try {
+ fBookmarksSet.clear();
+ if (fBookmarksFile == null) {
+ return;
+ }
+ for (IMarker bookmark : fBookmarksFile.findMarkers(
+ IMarker.BOOKMARK, false, IResource.DEPTH_ZERO)) {
+ int location = bookmark.getAttribute(IMarker.LOCATION, -1);
+ if (location != -1) {
+ Long rank = (long) location;
+ fBookmarksSet.add(rank);
+ }
+ }
+ } catch (CoreException e) {
+ Activator.getDefault().logError("Error refreshing bookmarks", e); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Notify that a filter is now applied on the view.
+ *
+ * @param filter
+ * The filter that was applied
+ */
+ public void filterApplied(ITmfFilter filter) {
+ fFilterFilter = filter;
+ }
+
+ /**
+ * Check if an event is currently visible in the view or not.
+ *
+ * @param event
+ * The event to check for
+ * @return If the event is visible or not
+ */
+ public boolean isVisible(ITmfEvent event) {
+ if (fFilterFilter != null) {
+ return fFilterFilter.matches(event);
+ }
+ return true;
+ }
+
+ /**
+ * Notify that a search is applied on the view.
+ *
+ * @param filter
+ * The search filter that was applied
+ */
+ public void searchApplied(ITmfFilter filter) {
+ fSearchFilter = filter;
+ }
+
+ /**
+ * Verify if the currently active search filter applies to the given event
+ * or not.
+ *
+ * @param event
+ * The event to check for
+ * @return If the event matches
+ */
+ public boolean isSearchMatch(ITmfEvent event) {
+ if (fSearchFilter != null) {
+ return fSearchFilter.matches(event);
+ }
+ return false;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartEvent.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartEvent.java
new file mode 100644
index 0000000000..9a5850cebc
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartEvent.java
@@ -0,0 +1,375 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timechart;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+
+/**
+ * Event in the time chart view
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeChartEvent implements ITimeEvent {
+
+ private static final byte TIMESTAMP_SCALE = -9;
+
+ private final TimeChartAnalysisEntry fParentEntry;
+ private long fTime;
+ private long fDuration;
+ private long fFirstRank;
+ private long fLastRank;
+ private final RankRangeList fRankRangeList;
+ private long fNbEvents;
+ private int fColorSettingPriority;
+ private boolean fIsBookmark;
+ private boolean fIsVisible;
+ private boolean fIsSearchMatch;
+ private TimeChartAnalysisEntry fItemizedEntry;
+ private boolean fItemizing;
+
+ /**
+ * Standard constructor
+ *
+ * @param parentEntry
+ * The parent entry
+ * @param event
+ * The event from which this time chart event originates
+ * @param rank
+ * The rank of the event in the trace
+ * @param decorationProvider
+ * The decoration provider to use
+ */
+ public TimeChartEvent(TimeChartAnalysisEntry parentEntry, ITmfEvent event,
+ long rank, TimeChartDecorationProvider decorationProvider) {
+ fParentEntry = parentEntry;
+ fTime = event.getTimestamp().normalize(0, TIMESTAMP_SCALE).getValue();
+ fDuration = 0;
+ fFirstRank = fLastRank = rank;
+ fRankRangeList = new RankRangeList(rank);
+ fNbEvents = 1;
+ fColorSettingPriority = ColorSettingsManager.getColorSettingPriority(event);
+ fIsBookmark = decorationProvider.isBookmark(rank);
+ fIsVisible = decorationProvider.isVisible(event);
+ fIsSearchMatch = decorationProvider.isSearchMatch(event);
+ }
+
+ @Override
+ public ITimeGraphEntry getEntry() {
+ return fParentEntry;
+ }
+
+ @Override
+ public long getTime() {
+ return fTime;
+ }
+
+ @Override
+ public long getDuration() {
+ return fDuration;
+ }
+
+ /**
+ * Retrieve the rank of the trace event which started this time event.
+ *
+ * @return The rank of the beginning
+ */
+ public long getFirstRank() {
+ return fFirstRank;
+ }
+
+ /**
+ * Retrieve the rank of the trace event which *finished* this time event.
+ *
+ * @return The rank of the end
+ */
+ public long getLastRank() {
+ return fLastRank;
+ }
+
+ /**
+ * Get the list of rank ranges corresponding to this time event.
+ *
+ * @return The rank range list
+ */
+ public RankRangeList getRankRangeList() {
+ return fRankRangeList;
+ }
+
+ /**
+ * Merge another time event with this one.
+ *
+ * @param event
+ * The other event
+ */
+ public void merge(TimeChartEvent event) {
+ mergeDecorations(event);
+ if (fTime == event.getTime() && fDuration == event.getDuration()) {
+ return;
+ }
+ long endTime = Math.max(fTime + fDuration, event.getTime() + event.getDuration());
+ fTime = Math.min(fTime, event.getTime());
+ fDuration = endTime - fTime;
+ fFirstRank = Math.min(fFirstRank, event.fFirstRank);
+ fLastRank = Math.max(fLastRank, event.fLastRank);
+ fNbEvents += event.fNbEvents;
+ fItemizedEntry = null;
+ synchronized (fRankRangeList) {
+ fRankRangeList.merge(event.getRankRangeList());
+ }
+ }
+
+ /**
+ * Merge the decorations of another time event with the decorations of this
+ * one.
+ *
+ * @param event
+ * The other event
+ */
+ public void mergeDecorations(TimeChartEvent event) {
+ fColorSettingPriority = Math.min(fColorSettingPriority, event.getColorSettingPriority());
+ fIsBookmark |= event.fIsBookmark;
+ fIsVisible |= event.fIsVisible;
+ fIsSearchMatch |= event.fIsSearchMatch;
+ }
+
+ /**
+ * Get the number of time events that have been merged with this one (starts
+ * counting at 1 if no merge happened).
+ *
+ * @return The current number of events in the bath
+ */
+ public long getNbEvents() {
+ return fNbEvents;
+ }
+
+ /**
+ * Retrieve the color setting priority.
+ *
+ * @return The priority
+ */
+ public int getColorSettingPriority() {
+ return fColorSettingPriority;
+ }
+
+ /**
+ * Set the color setting priority.
+ *
+ * @param priority
+ * The priority to set
+ */
+ public void setColorSettingPriority(int priority) {
+ fColorSettingPriority = priority;
+ }
+
+ /**
+ * Check if this time event is bookmarked
+ *
+ * @return Y/N
+ */
+ public boolean isBookmarked() {
+ return fIsBookmark;
+ }
+
+ /**
+ * Set this time event to be bookmarked or not.
+ *
+ * @param isBookmarked
+ * Should time time event become a bookmark, or not
+ */
+ public void setIsBookmarked(boolean isBookmarked) {
+ fIsBookmark = isBookmarked;
+ }
+
+ /**
+ * Check if this time is currently visible or not.
+ *
+ * @return If the event is visible
+ */
+ public boolean isVisible() {
+ return fIsVisible;
+ }
+
+ /**
+ * Set this time event to visible (or to non-visible).
+ *
+ * @param isVisible The new status
+ */
+ public void setIsVisible(boolean isVisible) {
+ fIsVisible = isVisible;
+ }
+
+ /**
+ * Check if the time event matches the current search.
+ *
+ * @return If it matches, Y/N
+ */
+ public boolean isSearchMatch() {
+ return fIsSearchMatch;
+ }
+
+ /**
+ * Mark this event as matching (or non-matching) the current search.
+ *
+ * @param isSearchMatch
+ * The new matching status
+ */
+ public void setIsSearchMatch(boolean isSearchMatch) {
+ fIsSearchMatch = isSearchMatch;
+ }
+
+ /**
+ * Set this event's itemized entry.
+ *
+ * @param timeAnalysisEntry
+ * The entry to set
+ */
+ public void setItemizedEntry(TimeChartAnalysisEntry timeAnalysisEntry) {
+ fItemizedEntry = timeAnalysisEntry;
+ }
+
+ /**
+ * Retrieve this event's itemized entry.
+ *
+ * @return The itemized entry that was previously set
+ */
+ public TimeChartAnalysisEntry getItemizedEntry() {
+ return fItemizedEntry;
+ }
+
+ /**
+ * @return Has this time event been set to itemizing?
+ */
+ public boolean isItemizing() {
+ return fItemizing;
+ }
+
+ /**
+ * Set this event's itemizing flag to true or false.
+ *
+ * @param itemizing
+ * The new value
+ */
+ public void setItemizing(boolean itemizing) {
+ fItemizing = itemizing;
+ }
+
+ /**
+ * Inner class to define a range in terms of ranks in the trace.
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+ public class RankRange {
+ private long firstRank;
+ private long lastRank;
+
+ /**
+ * Standard constructor
+ *
+ * @param firstRank
+ * The first (earliest) rank of the range
+ * @param lastRank
+ * The last (latest) rank of the range
+ */
+ public RankRange(long firstRank, long lastRank) {
+ this.firstRank = firstRank;
+ this.lastRank = lastRank;
+ }
+
+ /**
+ * Retrieve the start rank of this range.
+ *
+ * @return The first rank
+ */
+ public long getFirstRank() {
+ return firstRank;
+ }
+
+ /**
+ * Retrieve the end rank of this range
+ *
+ * @return The end rank
+ */
+ public long getLastRank() {
+ return lastRank;
+ }
+
+ /**
+ * Calculate the minimal distance between two RankRange's
+ *
+ * @param range
+ * The other range
+ * @return The distance, in "number of events" between the two ranges
+ */
+ public long distanceFrom(RankRange range) {
+ if (range.lastRank < fFirstRank) {
+ return fFirstRank - range.lastRank;
+ } else if (range.firstRank > fLastRank) {
+ return range.firstRank - fLastRank;
+ } else {
+ return 0;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "["+firstRank+","+lastRank+"]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ private class RankRangeList extends ArrayList<RankRange> {
+
+ private static final long serialVersionUID = 6060485531208535986L;
+
+ public RankRangeList(long rank) {
+ super(1);
+ add(new RankRange(rank, rank));
+ }
+
+ public void merge(RankRangeList rankRangeList) {
+ long threshold = fParentEntry.getTrace().getCacheSize();
+ for (RankRange newRange : rankRangeList) {
+ boolean merged = false;
+ for (RankRange oldRange : fRankRangeList) {
+ if (newRange.distanceFrom(oldRange) <= threshold) {
+ oldRange.firstRank = Math.min(oldRange.firstRank, newRange.firstRank);
+ oldRange.lastRank = Math.max(oldRange.lastRank, newRange.lastRank);
+ merged = true;
+ break;
+ }
+ }
+ if (!merged) {
+ add(newRange);
+ }
+ }
+ Iterator<RankRange> iterator = fRankRangeList.iterator();
+ RankRange previous = null;
+ while (iterator.hasNext()) {
+ RankRange range = iterator.next();
+ if (previous != null && range.distanceFrom(previous) <= threshold) {
+ previous.firstRank = Math.min(previous.firstRank, range.firstRank);
+ previous.lastRank = Math.max(previous.lastRank, range.lastRank);
+ iterator.remove();
+ }
+ previous = range;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java
new file mode 100644
index 0000000000..73dd074a18
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java
@@ -0,0 +1,754 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timechart;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.signal.TmfEventFilterAppliedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfEventSearchAppliedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceUpdatedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfContext;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSetting;
+import org.eclipse.tracecompass.tmf.ui.views.colors.ColorSettingsManager;
+import org.eclipse.tracecompass.tmf.ui.views.colors.IColorSettingsListener;
+import org.eclipse.tracecompass.tmf.ui.views.timechart.TimeChartEvent.RankRange;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphSelectionEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+
+/**
+ * Generic Time Chart view, which is similar to a Gantt chart for trace analysis
+ *
+ * @version 1.0
+ * @author Patrick Tasse
+ */
+public class TimeChartView extends TmfView implements ITimeGraphRangeListener, ITimeGraphSelectionListener, ITimeGraphTimeListener, IColorSettingsListener, IResourceChangeListener {
+
+ /** TimeChartView's ID */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.timechart"; //$NON-NLS-1$
+
+ private static final int TIMESTAMP_SCALE = -9;
+
+ private final int fDisplayWidth;
+ private TimeGraphViewer fViewer;
+ private final ArrayList<TimeChartAnalysisEntry> fTimeAnalysisEntries = new ArrayList<>();
+ private final Map<ITmfTrace, TimeChartDecorationProvider> fDecorationProviders = new HashMap<>();
+ private final ArrayList<DecorateThread> fDecorateThreads = new ArrayList<>();
+ private long fStartTime = 0;
+ private long fStopTime = Long.MAX_VALUE;
+ private boolean fRefreshBusy = false;
+ private boolean fRefreshPending = false;
+ private boolean fRedrawBusy = false;
+ private boolean fRedrawPending = false;
+ private final Object fSyncObj = new Object();
+ private ITimeGraphPresentationProvider fPresentationProvider;
+
+ /**
+ * Default constructor
+ */
+ public TimeChartView() {
+ super("Time Chart"); //$NON-NLS-1$
+ fDisplayWidth = Display.getDefault().getBounds().width;
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ fViewer = new TimeGraphViewer(parent, SWT.NONE);
+ fPresentationProvider = new TimeChartAnalysisProvider();
+ fViewer.setTimeGraphProvider(fPresentationProvider);
+ fViewer.setTimeFormat(TimeFormat.CALENDAR);
+ fViewer.addTimeListener(this);
+ fViewer.addRangeListener(this);
+ fViewer.addSelectionListener(this);
+ fViewer.setMinimumItemWidth(1);
+
+ IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
+ fViewer.getTimeGraphControl().setStatusLineManager(statusLineManager);
+
+ for (ITmfTrace trace : TmfTraceManager.getInstance().getOpenedTraces()) {
+ IFile bookmarksFile = TmfTraceManager.getInstance().getTraceEditorFile(trace);
+ TimeChartAnalysisEntry timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2);
+ fTimeAnalysisEntries.add(timeAnalysisEntry);
+ fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile));
+ Thread thread = new ProcessTraceThread(timeAnalysisEntry);
+ thread.start();
+ }
+ fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0]));
+
+ ColorSettingsManager.addColorSettingsListener(this);
+ ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
+ }
+
+ @Override
+ public void dispose() {
+ ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
+ for (DecorateThread thread : fDecorateThreads) {
+ thread.cancel();
+ }
+ ColorSettingsManager.removeColorSettingsListener(this);
+ super.dispose();
+ }
+
+ @Override
+ public void setFocus() {
+ fViewer.setFocus();
+ }
+
+ private class ProcessTraceThread extends Thread {
+
+ private final TimeChartAnalysisEntry fTimeAnalysisEntry;
+
+ public ProcessTraceThread(TimeChartAnalysisEntry timeAnalysisEntry) {
+ super("ProcessTraceJob:" + timeAnalysisEntry.getName()); //$NON-NLS-1$
+ fTimeAnalysisEntry = timeAnalysisEntry;
+ }
+
+ @Override
+ public void run() {
+ updateTraceEntry(fTimeAnalysisEntry, Long.MAX_VALUE, 0, Long.MAX_VALUE);
+ }
+ }
+
+ private void updateTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry, long stopRank, long startTime, long stopTime) {
+ ITmfTrace trace = timeAnalysisEntry.getTrace();
+ TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(trace);
+ if (decorationProvider == null) {
+ return; // the trace has been closed
+ }
+ ITmfContext context = null;
+ // TmfTimestamp lastTimestamp = null;
+ boolean done = false;
+ while (!done) {
+ synchronized (timeAnalysisEntry) {
+ if (timeAnalysisEntry.getLastRank() >= trace.getNbEvents()) {
+ done = true;
+ break;
+ }
+ if (context == null || context.getRank() != timeAnalysisEntry.getLastRank()) {
+ if (context != null) {
+ context.dispose();
+ }
+ if (timeAnalysisEntry.getLastRank() != -1) {
+ context = trace.seekEvent(timeAnalysisEntry.getLastRank());
+ } else {
+ // context = trace.seekLocation(null);
+ context = trace.seekEvent(0);
+ }
+ }
+ while (true) {
+ long rank = context.getRank();
+ ITmfEvent event = trace.getNext(context);
+ if (event == null) {
+ done = true;
+ break;
+ }
+ // if (!event.getTimestamp().equals(lastTimestamp)) {
+ TimeChartEvent timeEvent = new TimeChartEvent(timeAnalysisEntry, event, rank, decorationProvider);
+ if (timeEvent.getTime() >= startTime && timeEvent.getTime() <= stopTime) {
+ timeAnalysisEntry.addTraceEvent(timeEvent);
+ }
+ // lastTimestamp = event.getTimestamp();
+ // } *** commented out so that color setting priority gets
+ // set even if the event has same time
+ if (context.getRank() == trace.getNbEvents() || context.getRank() == stopRank) {
+ done = true;
+ break;
+ }
+ if (context.getRank() % trace.getCacheSize() == 1) {
+ // break for UI refresh
+ break;
+ }
+ }
+ // timeAnalysisEntry.setLastRank(Math.min(trace.getNbEvents(),
+ // stopRank));
+ timeAnalysisEntry.setLastRank(context.getRank());
+ }
+ redrawViewer(true);
+ }
+ if (context != null) {
+ context.dispose();
+ }
+ }
+
+ private void refreshViewer() {
+ synchronized (fSyncObj) {
+ if (fRefreshBusy) {
+ fRefreshPending = true;
+ return;
+ }
+ fRefreshBusy = true;
+ }
+ // Perform the refresh on the UI thread
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fViewer.getControl().isDisposed()) {
+ return;
+ }
+ fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0]));
+ fViewer.resetStartFinishTime();
+ synchronized (fSyncObj) {
+ fRefreshBusy = false;
+ if (fRefreshPending) {
+ fRefreshPending = false;
+ refreshViewer();
+ }
+ }
+ }
+ });
+ }
+
+ private void redrawViewer(boolean resetTimeIntervals) {
+ synchronized (fSyncObj) {
+ if (fRedrawBusy) {
+ fRedrawPending = true;
+ return;
+ }
+ fRedrawBusy = true;
+ }
+ final boolean reset = resetTimeIntervals;
+ // Perform the refresh on the UI thread
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fViewer.getControl().isDisposed()) {
+ return;
+ }
+ if (reset) {
+ fViewer.setTimeRange(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0]));
+ fViewer.setTimeBounds();
+ }
+ fViewer.getControl().redraw();
+ fViewer.getControl().update();
+ synchronized (fSyncObj) {
+ fRedrawBusy = false;
+ if (fRedrawPending) {
+ fRedrawPending = false;
+ redrawViewer(reset);
+ }
+ }
+ }
+ });
+ }
+
+ private void itemize(long startTime, long stopTime) {
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ Thread thread = new ItemizeThread(fTimeAnalysisEntries.get(i), startTime, stopTime);
+ thread.start();
+ }
+ }
+
+ private class ItemizeThread extends Thread {
+
+ private final TimeChartAnalysisEntry fTimeAnalysisEntry;
+ private final long startTime;
+ private final long stopTime;
+ private final long fMaxDuration;
+
+ private ItemizeThread(TimeChartAnalysisEntry timeAnalysisEntry, long startTime, long stopTime) {
+ super("Itemize Thread:" + timeAnalysisEntry.getName()); //$NON-NLS-1$
+ fTimeAnalysisEntry = timeAnalysisEntry;
+ this.startTime = startTime;
+ this.stopTime = stopTime;
+ fMaxDuration = 3 * (stopTime - startTime) / fDisplayWidth;
+ }
+
+ @Override
+ public void run() {
+ itemizeTraceEntry(fTimeAnalysisEntry);
+ }
+
+ public void itemizeTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry) {
+ Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator();
+ TimeChartEvent event = null;
+ boolean hasNext = true;
+ while (hasNext) {
+ synchronized (timeAnalysisEntry) {
+ while ((hasNext = iterator.hasNext()) == true) {
+ event = (TimeChartEvent) iterator.next();
+ if (event.getTime() + event.getDuration() > startTime && event.getTime() < stopTime && event.getDuration() > fMaxDuration
+ && event.getNbEvents() > 1) {
+ break;
+ }
+ }
+ }
+ if (hasNext && event != null) {
+ if (event.getItemizedEntry() == null) {
+ itemizeEvent(event);
+ } else {
+ itemizeTraceEntry(event.getItemizedEntry());
+ }
+ }
+ }
+ }
+
+ public void itemizeEvent(TimeChartEvent event) {
+ synchronized (event) {
+ if (event.isItemizing()) {
+ return;
+ }
+ event.setItemizing(true);
+ }
+ TimeChartAnalysisEntry timeAnalysisEntry = new TimeChartAnalysisEntry(fTimeAnalysisEntry.getTrace(), (int) Math.min(
+ event.getNbEvents() + 1, fDisplayWidth * 2));
+ synchronized (event.getRankRangeList()) {
+ for (RankRange range : event.getRankRangeList()) {
+ timeAnalysisEntry.setLastRank(range.getFirstRank());
+ updateTraceEntry(timeAnalysisEntry, range.getLastRank() + 1, event.getTime(), event.getTime() + event.getDuration());
+ }
+ }
+ event.setItemizedEntry(timeAnalysisEntry);
+ redrawViewer(false);
+ itemizeTraceEntry(timeAnalysisEntry);
+ synchronized (event) {
+ event.setItemizing(false);
+ }
+ }
+ }
+
+ private void redecorate() {
+ synchronized (fDecorateThreads) {
+ for (DecorateThread thread : fDecorateThreads) {
+ thread.cancel();
+ }
+ fDecorateThreads.clear();
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ DecorateThread thread = new DecorateThread(fTimeAnalysisEntries.get(i));
+ thread.start();
+ fDecorateThreads.add(thread);
+ }
+ }
+ }
+
+ private class DecorateThread extends Thread {
+ private volatile boolean interrupted = false;
+ private final TimeChartAnalysisEntry fTimeAnalysisEntry;
+ private final TimeChartDecorationProvider fDecorationProvider;
+ private ITmfContext fContext;
+ private int fCount = 0;
+
+ private DecorateThread(TimeChartAnalysisEntry timeAnalysisEntry) {
+ super("Decorate Thread:" + timeAnalysisEntry.getName()); //$NON-NLS-1$
+ fTimeAnalysisEntry = timeAnalysisEntry;
+ fDecorationProvider = fDecorationProviders.get(timeAnalysisEntry.getTrace());
+ }
+
+ @Override
+ public void run() {
+ resetTraceEntry(fTimeAnalysisEntry);
+ redrawViewer(false);
+ decorateTraceEntry(fTimeAnalysisEntry, null);
+ redrawViewer(false);
+ synchronized (fDecorateThreads) {
+ fDecorateThreads.remove(this);
+ }
+ if (fContext != null) {
+ fContext.dispose();
+ }
+ }
+
+ public void resetTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry) {
+ Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator();
+ TimeChartEvent event = null;
+ boolean hasNext = true;
+ while (!interrupted && hasNext) {
+ synchronized (timeAnalysisEntry) {
+ while ((hasNext = iterator.hasNext()) == true) {
+ event = (TimeChartEvent) iterator.next();
+ break;
+ }
+ }
+ if (hasNext && event != null) {
+ // TODO possible concurrency problem here with ItemizeJob
+ event.setColorSettingPriority(ColorSettingsManager.PRIORITY_NONE);
+ if (event.getItemizedEntry() != null) {
+ resetTraceEntry(event.getItemizedEntry());
+ }
+ }
+ }
+ }
+
+ public void decorateTraceEntry(TimeChartAnalysisEntry timeAnalysisEntry, TimeChartEvent parentEvent) {
+ // Set max duration high to ensure iterator does not consider
+ // itemized events
+ Iterator<ITimeEvent> iterator = timeAnalysisEntry.getTimeEventsIterator(0, Long.MAX_VALUE, Long.MAX_VALUE);
+ TimeChartEvent event = null;
+ int entryPriority = ColorSettingsManager.PRIORITY_NONE;
+ boolean entryIsBookmarked = false;
+ boolean entryIsVisible = false;
+ boolean entryIsSearchMatch = false;
+ boolean hasNext = true;
+ while (!interrupted && hasNext) {
+ synchronized (timeAnalysisEntry) {
+ while ((hasNext = iterator.hasNext()) == true) {
+ event = (TimeChartEvent) iterator.next();
+ break;
+ }
+ }
+ if (hasNext && event != null) {
+ // TODO possible concurrency problem here with ItemizeJob
+ if (event.getItemizedEntry() == null) {
+ decorateEvent(event);
+ } else {
+ decorateTraceEntry(event.getItemizedEntry(), event);
+ }
+ entryPriority = Math.min(entryPriority, event.getColorSettingPriority());
+ entryIsBookmarked |= event.isBookmarked();
+ entryIsVisible |= event.isVisible();
+ entryIsSearchMatch |= event.isSearchMatch();
+ if (++fCount % timeAnalysisEntry.getTrace().getCacheSize() == 0) {
+ redrawViewer(false);
+ }
+ }
+ }
+ if (parentEvent != null) {
+ parentEvent.setColorSettingPriority(entryPriority);
+ parentEvent.setIsBookmarked(entryIsBookmarked);
+ parentEvent.setIsVisible(entryIsVisible);
+ parentEvent.setIsSearchMatch(entryIsSearchMatch);
+ }
+ }
+
+ public void decorateEvent(TimeChartEvent timeChartEvent) {
+ // TODO possible concurrency problem here with ItemizeJob
+ TimeChartAnalysisEntry timeAnalysisEntry = (TimeChartAnalysisEntry) timeChartEvent.getEntry();
+ ITmfTrace trace = timeAnalysisEntry.getTrace();
+ int priority = ColorSettingsManager.PRIORITY_NONE;
+ boolean isBookmarked = false;
+ boolean isVisible = false;
+ boolean isSearchMatch = false;
+ synchronized (timeChartEvent.getRankRangeList()) {
+ for (RankRange range : timeChartEvent.getRankRangeList()) {
+ if (interrupted) {
+ return;
+ }
+ if (fContext == null || fContext.getRank() != range.getFirstRank()) {
+ if (fContext != null) {
+ fContext.dispose();
+ }
+ fContext = trace.seekEvent(range.getFirstRank());
+ fContext.setRank(range.getFirstRank());
+ }
+ while (true) {
+ if (interrupted) {
+ return;
+ }
+ long rank = fContext.getRank();
+ ITmfEvent event = trace.getNext(fContext);
+ if (event == null) {
+ break;
+ }
+ long eventTime = event.getTimestamp().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ if (eventTime >= timeChartEvent.getTime() && eventTime <= timeChartEvent.getTime() + timeChartEvent.getDuration()) {
+ priority = Math.min(priority, ColorSettingsManager.getColorSettingPriority(event));
+ }
+ isBookmarked |= fDecorationProvider.isBookmark(rank);
+ isVisible |= fDecorationProvider.isVisible(event);
+ isSearchMatch |= fDecorationProvider.isSearchMatch(event);
+ if (fContext.getRank() > range.getLastRank()) {
+ break;
+ }
+ }
+ }
+ }
+ timeChartEvent.setColorSettingPriority(priority);
+ timeChartEvent.setIsBookmarked(isBookmarked);
+ timeChartEvent.setIsVisible(isVisible);
+ timeChartEvent.setIsSearchMatch(isSearchMatch);
+ }
+
+ public void cancel() {
+ interrupted = true;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Listeners
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
+ fStartTime = event.getStartTime();
+ fStopTime = event.getEndTime();
+ itemize(fStartTime, fStopTime);
+ final ITmfTimestamp startTimestamp = new TmfTimestamp(event.getStartTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ final ITmfTimestamp endTimestamp = new TmfTimestamp(event.getEndTime(), ITmfTimestamp.NANOSECOND_SCALE);
+ TmfTimeRange range = new TmfTimeRange(startTimestamp, endTimestamp);
+ broadcast(new TmfRangeSynchSignal(this, range));
+ }
+
+ @Override
+ public void selectionChanged(TimeGraphSelectionEvent event) {
+ ITimeGraphEntry timeAnalysisEntry = null;
+ if (event.getSelection() instanceof TimeChartAnalysisEntry) {
+ timeAnalysisEntry = event.getSelection();
+ } else if (event.getSelection() instanceof TimeChartEvent) {
+ timeAnalysisEntry = ((TimeChartEvent) event.getSelection()).getEntry();
+ }
+ if (timeAnalysisEntry instanceof TimeChartAnalysisEntry) {
+ broadcast(new TmfTraceSelectedSignal(this, ((TimeChartAnalysisEntry) timeAnalysisEntry).getTrace()));
+ }
+ }
+
+ @Override
+ public void timeSelected(TimeGraphTimeEvent event) {
+ broadcast(new TmfTimeSynchSignal(this, new TmfTimestamp(event.getBeginTime(), TIMESTAMP_SCALE), new TmfTimestamp(event.getEndTime(), TIMESTAMP_SCALE)));
+ }
+
+ @Override
+ public void colorSettingsChanged(ColorSetting[] colorSettings) {
+ // Set presentation provider again to trigger re-creation of new color settings which are stored
+ // in the TimeGraphControl class
+ fViewer.setTimeGraphProvider(fPresentationProvider);
+ redecorate();
+ }
+
+ @Override
+ public void resourceChanged(IResourceChangeEvent event) {
+ for (IMarkerDelta delta : event.findMarkerDeltas(IMarker.BOOKMARK, false)) {
+ for (TimeChartDecorationProvider provider : fDecorationProviders.values()) {
+ if (delta.getResource().equals(provider.getBookmarksFile())) {
+ if (delta.getKind() == IResourceDelta.CHANGED && delta.getMarker().getAttribute(IMarker.LOCATION, -1) != -1) {
+ provider.refreshBookmarks();
+ } else if (delta.getKind() == IResourceDelta.REMOVED) {
+ provider.refreshBookmarks();
+ }
+ }
+ }
+ }
+ redecorate();
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Handler for the Trace Opened signal
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ final ITmfTrace trace = signal.getTrace();
+ final IFile bookmarksFile = signal.getEditorFile();
+ TimeChartAnalysisEntry timeAnalysisEntry = null;
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) {
+ timeAnalysisEntry = fTimeAnalysisEntries.get(i);
+ break;
+ }
+ }
+ if (timeAnalysisEntry == null) {
+ timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2);
+ fTimeAnalysisEntries.add(timeAnalysisEntry);
+ fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile));
+ Thread thread = new ProcessTraceThread(timeAnalysisEntry);
+ thread.start();
+ }
+ refreshViewer();
+ }
+
+ /**
+ * Handler for the Trace Closed signal
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+ final ITmfTrace trace = signal.getTrace();
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) {
+ fTimeAnalysisEntries.remove(i);
+ fDecorationProviders.remove(trace);
+ synchronized (fDecorateThreads) {
+ for (DecorateThread thread : fDecorateThreads) {
+ if (thread.fTimeAnalysisEntry.getTrace() == trace) {
+ thread.cancel();
+ fDecorateThreads.remove(thread);
+ break;
+ }
+ }
+ }
+ refreshViewer();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handler for the Trace Selected signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ if (signal.getSource() != this) {
+ ITmfTrace trace = signal.getTrace();
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ if (fTimeAnalysisEntries.get(i).getTrace().equals(trace)) {
+ fViewer.setSelection(fTimeAnalysisEntries.get(i));
+ break;
+ }
+ }
+ long beginTime = fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long endTime = fTraceManager.getSelectionEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fViewer.setSelectionRange(beginTime, endTime);
+ }
+ }
+
+ /**
+ * Handler for the Trace Updated signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void traceUpdated(TmfTraceUpdatedSignal signal) {
+ final ITmfTrace trace = signal.getTrace();
+ for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
+ TimeChartAnalysisEntry timeAnalysisEntry = fTimeAnalysisEntries.get(i);
+ if (timeAnalysisEntry.getTrace().equals(trace)) {
+ updateTraceEntry(timeAnalysisEntry, Long.MAX_VALUE, 0, Long.MAX_VALUE);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Handler for the Time Synch signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void currentTimeUpdated(TmfTimeSynchSignal signal) {
+ final long beginTime = signal.getBeginTime().normalize(0, TIMESTAMP_SCALE).getValue();
+ final long endTime = signal.getEndTime().normalize(0, TIMESTAMP_SCALE).getValue();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (beginTime == endTime) {
+ fViewer.setSelectedTime(beginTime, true);
+ if (fStartTime != fViewer.getTime0() || fStopTime != fViewer.getTime1()) {
+ fStartTime = fViewer.getTime0();
+ fStopTime = fViewer.getTime1();
+ itemize(fStartTime, fStopTime);
+ }
+ } else {
+ fViewer.setSelectionRange(beginTime, endTime);
+ }
+ }
+ });
+ }
+
+ /**
+ * Handler for the Time Range Synch signal
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void synchToRange(final TmfRangeSynchSignal signal) {
+ if (signal.getSource() == this) {
+ return;
+ }
+ final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ fStartTime = startTime;
+ fStopTime = endTime;
+ itemize(fStartTime, fStopTime);
+ fViewer.setStartFinishTime(startTime, endTime);
+ }
+ });
+ }
+
+ /**
+ * Handler for the Event Filter Applied signal
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void filterApplied(TmfEventFilterAppliedSignal signal) {
+ TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(signal.getTrace());
+ if (decorationProvider == null) {
+ return;
+ }
+ decorationProvider.filterApplied(signal.getEventFilter());
+ redecorate();
+ }
+
+ /**
+ * Handler for the Event Search Applied signal
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void searchApplied(TmfEventSearchAppliedSignal signal) {
+ TimeChartDecorationProvider decorationProvider = fDecorationProviders.get(signal.getTrace());
+ if (decorationProvider == null) {
+ return;
+ }
+ decorationProvider.searchApplied(signal.getSearchFilter());
+ redecorate();
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
new file mode 100644
index 0000000000..79ca26cac3
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
@@ -0,0 +1,1271 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2014 Ericsson, École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Patrick Tasse - Initial API and implementation
+ * Bernd Hufmann - Updated signal handling
+ * Geneviève Bastien - Move code to provide base classes for time graph view
+ * Marc-Andre Laperle - Add time zone preference
+ * Geneviève Bastien - Add event links between entries
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timegraph;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimestampFormatUpdateSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfNanoTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.ui.TmfUiRefreshHandler;
+import org.eclipse.tracecompass.tmf.ui.views.TmfView;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphContentProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphPresentationProvider2;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphRangeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphSelectionListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.ITimeGraphTimeListener;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphCombo;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphPresentationProvider;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphRangeUpdateEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.TimeGraphViewer;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ILinkEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeEvent;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.ITimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.TimeGraphEntry;
+import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * An abstract view all time graph views can inherit
+ *
+ * This view contains either a time graph viewer, or a time graph combo which is
+ * divided between a tree viewer on the left and a time graph viewer on the right.
+ *
+ * @since 2.1
+ */
+public abstract class AbstractTimeGraphView extends TmfView {
+
+ /**
+ * Redraw state enum
+ */
+ private enum State {
+ IDLE, BUSY, PENDING
+ }
+
+ // ------------------------------------------------------------------------
+ // Fields
+ // ------------------------------------------------------------------------
+
+ /** The timegraph wrapper */
+ private ITimeGraphWrapper fTimeGraphWrapper;
+
+ /** The selected trace */
+ private ITmfTrace fTrace;
+
+ /** The timegraph entry list */
+ private List<TimeGraphEntry> fEntryList;
+
+ /** The trace to entry list hash map */
+ private final Map<ITmfTrace, List<TimeGraphEntry>> fEntryListMap = new HashMap<>();
+
+ /** The trace to build thread hash map */
+ private final Map<ITmfTrace, BuildThread> fBuildThreadMap = new HashMap<>();
+
+ /** The start time */
+ private long fStartTime;
+
+ /** The end time */
+ private long fEndTime;
+
+ /** The display width */
+ private final int fDisplayWidth;
+
+ /** The zoom thread */
+ private ZoomThread fZoomThread;
+
+ /** The next resource action */
+ private Action fNextResourceAction;
+
+ /** The previous resource action */
+ private Action fPreviousResourceAction;
+
+ /** A comparator class */
+ private Comparator<ITimeGraphEntry> fEntryComparator = null;
+
+ /** The redraw state used to prevent unnecessary queuing of display runnables */
+ private State fRedrawState = State.IDLE;
+
+ /** The redraw synchronization object */
+ private final Object fSyncObj = new Object();
+
+ /** The presentation provider for this view */
+ private final TimeGraphPresentationProvider fPresentation;
+
+ /** The tree column label array, or null if combo is not used */
+ private String[] fColumns;
+
+ /** The tree label provider, or null if combo is not used */
+ private TreeLabelProvider fLabelProvider = null;
+
+ /** The relative weight of the sash, ignored if combo is not used */
+ private int[] fWeight = { 1, 1 };
+
+ /** The filter column label array, or null if filter is not used */
+ private String[] fFilterColumns;
+
+ /** The pack done flag */
+ private boolean fPackDone = false;
+
+ /** The filter label provider, or null if filter is not used */
+ private TreeLabelProvider fFilterLabelProvider;
+
+ // ------------------------------------------------------------------------
+ // Classes
+ // ------------------------------------------------------------------------
+
+ private interface ITimeGraphWrapper {
+
+ void setTimeGraphProvider(TimeGraphPresentationProvider fPresentation);
+
+ TimeGraphViewer getTimeGraphViewer();
+
+ void addSelectionListener(ITimeGraphSelectionListener iTimeGraphSelectionListener);
+
+ ISelectionProvider getSelectionProvider();
+
+ void setFocus();
+
+ boolean isDisposed();
+
+ void refresh();
+
+ void setInput(Object input);
+
+ Object getInput();
+
+ void redraw();
+
+ void update();
+
+ }
+
+ private class TimeGraphViewerWrapper implements ITimeGraphWrapper {
+ private TimeGraphViewer viewer;
+
+ private TimeGraphViewerWrapper(Composite parent, int style) {
+ viewer = new TimeGraphViewer(parent, style);
+ }
+
+ @Override
+ public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
+ viewer.setTimeGraphProvider(timeGraphProvider);
+ }
+
+ @Override
+ public TimeGraphViewer getTimeGraphViewer() {
+ return viewer;
+ }
+
+ @Override
+ public void addSelectionListener(ITimeGraphSelectionListener listener) {
+ viewer.addSelectionListener(listener);
+ }
+
+ @Override
+ public ISelectionProvider getSelectionProvider() {
+ return viewer.getSelectionProvider();
+ }
+
+ @Override
+ public void setFocus() {
+ viewer.setFocus();
+ }
+
+ @Override
+ public boolean isDisposed() {
+ return viewer.getControl().isDisposed();
+ }
+
+ @Override
+ public void setInput(Object input) {
+ viewer.setInput(input);
+ }
+
+ @Override
+ public Object getInput() {
+ return viewer.getInput();
+ }
+
+ @Override
+ public void refresh() {
+ viewer.refresh();
+ }
+
+ @Override
+ public void redraw() {
+ viewer.getControl().redraw();
+ }
+
+ @Override
+ public void update() {
+ viewer.getControl().update();
+ }
+ }
+
+ private class TimeGraphComboWrapper implements ITimeGraphWrapper {
+ private TimeGraphCombo combo;
+
+ private TimeGraphComboWrapper(Composite parent, int style) {
+ combo = new TimeGraphCombo(parent, style, fWeight);
+ }
+
+ @Override
+ public void setTimeGraphProvider(TimeGraphPresentationProvider timeGraphProvider) {
+ combo.setTimeGraphProvider(timeGraphProvider);
+ }
+
+ @Override
+ public TimeGraphViewer getTimeGraphViewer() {
+ return combo.getTimeGraphViewer();
+ }
+
+ @Override
+ public void addSelectionListener(ITimeGraphSelectionListener listener) {
+ combo.addSelectionListener(listener);
+ }
+
+ @Override
+ public ISelectionProvider getSelectionProvider() {
+ return combo.getTreeViewer();
+ }
+
+ @Override
+ public void setFocus() {
+ combo.setFocus();
+ }
+
+ @Override
+ public boolean isDisposed() {
+ return combo.isDisposed();
+ }
+
+ @Override
+ public void setInput(Object input) {
+ combo.setInput(input);
+ }
+
+ @Override
+ public Object getInput() {
+ return combo.getInput();
+ }
+
+ @Override
+ public void refresh() {
+ combo.refresh();
+ }
+
+ @Override
+ public void redraw() {
+ combo.redraw();
+ }
+
+ @Override
+ public void update() {
+ combo.update();
+ }
+
+ TimeGraphCombo getTimeGraphCombo() {
+ return combo;
+ }
+
+ TreeViewer getTreeViewer() {
+ return combo.getTreeViewer();
+ }
+
+ IAction getShowFilterAction() {
+ return combo.getShowFilterAction();
+ }
+ }
+
+ private class TreeContentProvider implements ITreeContentProvider {
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ }
+
+ @Override
+ public ITimeGraphEntry[] getElements(Object inputElement) {
+ if (inputElement != null) {
+ try {
+ return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]);
+ } catch (ClassCastException e) {
+ }
+ }
+ return new ITimeGraphEntry[0];
+ }
+
+ @Override
+ public Object[] getChildren(Object parentElement) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) parentElement;
+ List<? extends ITimeGraphEntry> children = entry.getChildren();
+ return children.toArray(new ITimeGraphEntry[children.size()]);
+ }
+
+ @Override
+ public Object getParent(Object element) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) element;
+ return entry.getParent();
+ }
+
+ @Override
+ public boolean hasChildren(Object element) {
+ ITimeGraphEntry entry = (ITimeGraphEntry) element;
+ return entry.hasChildren();
+ }
+
+ }
+
+ private class TimeGraphContentProvider implements ITimeGraphContentProvider {
+
+ @Override
+ public ITimeGraphEntry[] getElements(Object inputElement) {
+ if (inputElement != null) {
+ try {
+ return ((List<?>) inputElement).toArray(new ITimeGraphEntry[0]);
+ } catch (ClassCastException e) {
+ }
+ }
+ return new ITimeGraphEntry[0];
+ }
+
+ }
+
+ /**
+ * Base class to provide the labels for the tree viewer. Views extending
+ * this class typically need to override the getColumnText method if they
+ * have more than one column to display
+ */
+ protected static class TreeLabelProvider implements ITableLabelProvider, ILabelProvider {
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ TimeGraphEntry entry = (TimeGraphEntry) element;
+ if (columnIndex == 0) {
+ return entry.getName();
+ }
+ return new String();
+ }
+
+ /**
+ * @since 3.2
+ */
+ @Override
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ /**
+ * @since 3.2
+ */
+ @Override
+ public String getText(Object element) {
+ TimeGraphEntry entry = (TimeGraphEntry) element;
+ return entry.getName();
+ }
+
+ }
+
+ private class BuildThread extends Thread {
+ private final ITmfTrace fBuildTrace;
+ private final ITmfTrace fParentTrace;
+ private final IProgressMonitor fMonitor;
+
+ public BuildThread(final ITmfTrace trace, final ITmfTrace parentTrace, final String name) {
+ super(name + " build"); //$NON-NLS-1$
+ fBuildTrace = trace;
+ fParentTrace = parentTrace;
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ buildEventList(fBuildTrace, fParentTrace, fMonitor);
+ synchronized (fBuildThreadMap) {
+ fBuildThreadMap.remove(fBuildTrace);
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ private class ZoomThread extends Thread {
+ private final List<TimeGraphEntry> fZoomEntryList;
+ private final long fZoomStartTime;
+ private final long fZoomEndTime;
+ private final long fResolution;
+ private final IProgressMonitor fMonitor;
+
+ public ZoomThread(List<TimeGraphEntry> entryList, long startTime, long endTime, String name) {
+ super(name + " zoom"); //$NON-NLS-1$
+ fZoomEntryList = entryList;
+ fZoomStartTime = startTime;
+ fZoomEndTime = endTime;
+ fResolution = Math.max(1, (fZoomEndTime - fZoomStartTime) / fDisplayWidth);
+ fMonitor = new NullProgressMonitor();
+ }
+
+ @Override
+ public void run() {
+ if (fZoomEntryList == null) {
+ return;
+ }
+ for (TimeGraphEntry entry : fZoomEntryList) {
+ if (fMonitor.isCanceled()) {
+ return;
+ }
+ zoom(entry, fMonitor);
+ }
+ /* Refresh the arrows when zooming */
+ List<ILinkEvent> events = getLinkList(fZoomStartTime, fZoomEndTime, fResolution, fMonitor);
+ if (events != null) {
+ fTimeGraphWrapper.getTimeGraphViewer().setLinks(events);
+ redraw();
+ }
+ }
+
+ private void zoom(TimeGraphEntry entry, IProgressMonitor monitor) {
+ if (fZoomStartTime <= fStartTime && fZoomEndTime >= fEndTime) {
+ entry.setZoomedEventList(null);
+ } else {
+ List<ITimeEvent> zoomedEventList = getEventList(entry, fZoomStartTime, fZoomEndTime, fResolution, monitor);
+ if (zoomedEventList != null) {
+ entry.setZoomedEventList(zoomedEventList);
+ }
+ }
+ redraw();
+ for (ITimeGraphEntry child : entry.getChildren()) {
+ if (fMonitor.isCanceled()) {
+ return;
+ }
+ if (child instanceof TimeGraphEntry) {
+ zoom((TimeGraphEntry) child, monitor);
+ }
+ }
+ }
+
+ public void cancel() {
+ fMonitor.setCanceled(true);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructs a time graph view that contains either a time graph viewer or
+ * a time graph combo.
+ *
+ * By default, the view uses a time graph viewer. To use a time graph combo,
+ * the subclass constructor must call {@link #setTreeColumns(String[])} and
+ * {@link #setTreeLabelProvider(TreeLabelProvider)}.
+ *
+ * @param id
+ * The id of the view
+ * @param pres
+ * The presentation provider
+ */
+ public AbstractTimeGraphView(String id, TimeGraphPresentationProvider pres) {
+ super(id);
+ fPresentation = pres;
+ fDisplayWidth = Display.getDefault().getBounds().width;
+ }
+
+ // ------------------------------------------------------------------------
+ // Getters and setters
+ // ------------------------------------------------------------------------
+
+ /**
+ * Getter for the time graph combo
+ *
+ * @return The time graph combo, or null if combo is not used
+ */
+ protected TimeGraphCombo getTimeGraphCombo() {
+ if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
+ return ((TimeGraphComboWrapper) fTimeGraphWrapper).getTimeGraphCombo();
+ }
+ return null;
+ }
+
+ /**
+ * Getter for the time graph viewer
+ *
+ * @return The time graph viewer
+ */
+ protected TimeGraphViewer getTimeGraphViewer() {
+ return fTimeGraphWrapper.getTimeGraphViewer();
+ }
+
+ /**
+ * Getter for the presentation provider
+ *
+ * @return The time graph presentation provider
+ * @since 3.0
+ */
+ protected ITimeGraphPresentationProvider2 getPresentationProvider() {
+ return fPresentation;
+ }
+
+ /**
+ * Sets the tree column labels.
+ * This should be called from the constructor.
+ *
+ * @param columns
+ * The array of tree column labels
+ */
+ protected void setTreeColumns(final String[] columns) {
+ fColumns = columns;
+ }
+
+ /**
+ * Sets the tree label provider.
+ * This should be called from the constructor.
+ *
+ * @param tlp
+ * The tree label provider
+ */
+ protected void setTreeLabelProvider(final TreeLabelProvider tlp) {
+ fLabelProvider = tlp;
+ }
+
+ /**
+ * Sets the relative weight of each part of the time graph combo.
+ * This should be called from the constructor.
+ *
+ * @param weights
+ * The array (length 2) of relative weights of each part of the combo
+ */
+ protected void setWeight(final int[] weights) {
+ fWeight = weights;
+ }
+
+ /**
+ * Sets the filter column labels.
+ * This should be called from the constructor.
+ *
+ * @param filterColumns
+ * The array of filter column labels
+ */
+ protected void setFilterColumns(final String[] filterColumns) {
+ fFilterColumns = filterColumns;
+ }
+
+ /**
+ * Sets the filter label provider.
+ * This should be called from the constructor.
+ *
+ * @param labelProvider
+ * The filter label provider
+ *
+ * @since 3.0
+ */
+ protected void setFilterLabelProvider(final TreeLabelProvider labelProvider) {
+ fFilterLabelProvider = labelProvider;
+ }
+
+ /**
+ * Gets the display width
+ *
+ * @return the display width
+ */
+ protected int getDisplayWidth() {
+ return fDisplayWidth;
+ }
+
+ /**
+ * Gets the comparator for the entries
+ *
+ * @return The entry comparator
+ */
+ protected Comparator<ITimeGraphEntry> getEntryComparator() {
+ return fEntryComparator;
+ }
+
+ /**
+ * Sets the comparator class for the entries
+ *
+ * @param comparator
+ * A comparator object
+ */
+ protected void setEntryComparator(final Comparator<ITimeGraphEntry> comparator) {
+ fEntryComparator = comparator;
+ }
+
+ /**
+ * Gets the trace displayed in the view
+ *
+ * @return The trace
+ */
+ protected ITmfTrace getTrace() {
+ return fTrace;
+ }
+
+ /**
+ * Gets the start time
+ *
+ * @return The start time
+ */
+ protected long getStartTime() {
+ return fStartTime;
+ }
+
+ /**
+ * Sets the start time
+ *
+ * @param time
+ * The start time
+ */
+ protected void setStartTime(long time) {
+ fStartTime = time;
+ }
+
+ /**
+ * Gets the end time
+ *
+ * @return The end time
+ */
+ protected long getEndTime() {
+ return fEndTime;
+ }
+
+ /**
+ * Sets the end time
+ *
+ * @param time
+ * The end time
+ */
+ protected void setEndTime(long time) {
+ fEndTime = time;
+ }
+
+ /**
+ * Gets the entry list for a trace
+ *
+ * @param trace
+ * the trace
+ *
+ * @return the entry list map
+ * @since 3.0
+ */
+ protected List<TimeGraphEntry> getEntryList(ITmfTrace trace) {
+ synchronized (fEntryListMap) {
+ return fEntryListMap.get(trace);
+ }
+ }
+
+ /**
+ * Adds a trace entry list to the entry list map
+ *
+ * @param trace
+ * the trace to add
+ * @param list
+ * the list of time graph entries
+ */
+ protected void putEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+ synchronized (fEntryListMap) {
+ fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
+ }
+ }
+
+ /**
+ * Adds a list of entries to a trace's entry list
+ *
+ * @param trace
+ * the trace
+ * @param list
+ * the list of time graph entries to add
+ * @since 3.0
+ */
+ protected void addToEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+ synchronized (fEntryListMap) {
+ List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
+ if (entryList == null) {
+ fEntryListMap.put(trace, new CopyOnWriteArrayList<>(list));
+ } else {
+ entryList.addAll(list);
+ }
+ }
+ }
+
+ /**
+ * Removes a list of entries from a trace's entry list
+ *
+ * @param trace
+ * the trace
+ * @param list
+ * the list of time graph entries to remove
+ * @since 3.0
+ */
+ protected void removeFromEntryList(ITmfTrace trace, List<TimeGraphEntry> list) {
+ synchronized (fEntryListMap) {
+ List<TimeGraphEntry> entryList = fEntryListMap.get(trace);
+ if (entryList != null) {
+ entryList.removeAll(list);
+ }
+ }
+ }
+
+ /**
+ * Text for the "next" button
+ *
+ * @return The "next" button text
+ */
+ protected String getNextText() {
+ return Messages.AbstractTimeGraphtView_NextText;
+ }
+
+ /**
+ * Tooltip for the "next" button
+ *
+ * @return Tooltip for the "next" button
+ */
+ protected String getNextTooltip() {
+ return Messages.AbstractTimeGraphView_NextTooltip;
+ }
+
+ /**
+ * Text for the "Previous" button
+ *
+ * @return The "Previous" button text
+ */
+ protected String getPrevText() {
+ return Messages.AbstractTimeGraphView_PreviousText;
+ }
+
+ /**
+ * Tooltip for the "previous" button
+ *
+ * @return Tooltip for the "previous" button
+ */
+ protected String getPrevTooltip() {
+ return Messages.AbstractTimeGraphView_PreviousTooltip;
+ }
+
+ // ------------------------------------------------------------------------
+ // ViewPart
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite parent) {
+ if (fColumns == null || fLabelProvider == null) {
+ fTimeGraphWrapper = new TimeGraphViewerWrapper(parent, SWT.NONE);
+ TimeGraphViewer viewer = fTimeGraphWrapper.getTimeGraphViewer();
+ viewer.setTimeGraphContentProvider(new TimeGraphContentProvider());
+ } else {
+ TimeGraphComboWrapper wrapper = new TimeGraphComboWrapper(parent, SWT.NONE);
+ fTimeGraphWrapper = wrapper;
+ TimeGraphCombo combo = wrapper.getTimeGraphCombo();
+ combo.setTreeContentProvider(new TreeContentProvider());
+ combo.setTreeLabelProvider(fLabelProvider);
+ combo.setTreeColumns(fColumns);
+ combo.setFilterContentProvider(new TreeContentProvider());
+ combo.setFilterLabelProvider(fFilterLabelProvider);
+ combo.setFilterColumns(fFilterColumns);
+ combo.setTimeGraphContentProvider(new TimeGraphContentProvider());
+ }
+
+ fTimeGraphWrapper.setTimeGraphProvider(fPresentation);
+
+ fTimeGraphWrapper.getTimeGraphViewer().addRangeListener(new ITimeGraphRangeListener() {
+ @Override
+ public void timeRangeUpdated(TimeGraphRangeUpdateEvent event) {
+ final long startTime = event.getStartTime();
+ final long endTime = event.getEndTime();
+ TmfTimeRange range = new TmfTimeRange(new TmfNanoTimestamp(startTime), new TmfNanoTimestamp(endTime));
+ broadcast(new TmfRangeSynchSignal(AbstractTimeGraphView.this, range));
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ startZoomThread(startTime, endTime);
+ }
+ });
+
+ fTimeGraphWrapper.getTimeGraphViewer().addTimeListener(new ITimeGraphTimeListener() {
+ @Override
+ public void timeSelected(TimeGraphTimeEvent event) {
+ TmfNanoTimestamp startTime = new TmfNanoTimestamp(event.getBeginTime());
+ TmfNanoTimestamp endTime = new TmfNanoTimestamp(event.getEndTime());
+ broadcast(new TmfTimeSynchSignal(AbstractTimeGraphView.this, startTime, endTime));
+ }
+ });
+
+ fTimeGraphWrapper.getTimeGraphViewer().setTimeFormat(TimeFormat.CALENDAR);
+
+ IStatusLineManager statusLineManager = getViewSite().getActionBars().getStatusLineManager();
+ fTimeGraphWrapper.getTimeGraphViewer().getTimeGraphControl().setStatusLineManager(statusLineManager);
+
+ // View Action Handling
+ makeActions();
+ contributeToActionBars();
+
+ ITmfTrace trace = getActiveTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+
+ // make selection available to other views
+ getSite().setSelectionProvider(fTimeGraphWrapper.getSelectionProvider());
+ }
+
+ @Override
+ public void setFocus() {
+ fTimeGraphWrapper.setFocus();
+ }
+
+ // ------------------------------------------------------------------------
+ // Signal handlers
+ // ------------------------------------------------------------------------
+
+ /**
+ * Handler for the trace opened signal.
+ *
+ * @param signal
+ * The incoming signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+
+ /**
+ * Handler for the trace selected signal
+ *
+ * @param signal
+ * The incoming signal
+ */
+ @TmfSignalHandler
+ public void traceSelected(final TmfTraceSelectedSignal signal) {
+ if (signal.getTrace() == fTrace) {
+ return;
+ }
+ fTrace = signal.getTrace();
+
+ loadTrace();
+ }
+
+ /**
+ * Trace is closed: clear the data structures and the view
+ *
+ * @param signal
+ * the signal received
+ */
+ @TmfSignalHandler
+ public void traceClosed(final TmfTraceClosedSignal signal) {
+ synchronized (fBuildThreadMap) {
+ for (ITmfTrace trace : getTracesToBuild(signal.getTrace())) {
+ BuildThread buildThread = fBuildThreadMap.remove(trace);
+ if (buildThread != null) {
+ buildThread.cancel();
+ }
+ }
+ }
+ synchronized (fEntryListMap) {
+ fEntryListMap.remove(signal.getTrace());
+ }
+ if (signal.getTrace() == fTrace) {
+ fTrace = null;
+ fStartTime = 0;
+ fEndTime = 0;
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ refresh();
+ }
+ }
+
+ /**
+ * Handler for the time synch signal
+ *
+ * @param signal
+ * The signal that's received
+ */
+ @TmfSignalHandler
+ public void synchToTime(final TmfTimeSynchSignal signal) {
+ if (signal.getSource() == this || fTrace == null) {
+ return;
+ }
+ final long beginTime = signal.getBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphWrapper.isDisposed()) {
+ return;
+ }
+ if (beginTime == endTime) {
+ fTimeGraphWrapper.getTimeGraphViewer().setSelectedTime(beginTime, true);
+ } else {
+ fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(beginTime, endTime);
+ }
+ startZoomThread(fTimeGraphWrapper.getTimeGraphViewer().getTime0(), fTimeGraphWrapper.getTimeGraphViewer().getTime1());
+
+ synchingToTime(beginTime);
+ }
+ });
+ }
+
+ /**
+ * Handler for the range synch signal
+ *
+ * @param signal
+ * The signal that's received
+ */
+ @TmfSignalHandler
+ public void synchToRange(final TmfRangeSynchSignal signal) {
+ if (signal.getSource() == this || fTrace == null) {
+ return;
+ }
+ if (signal.getCurrentRange().getIntersection(fTrace.getTimeRange()) == null) {
+ return;
+ }
+ final long startTime = signal.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ final long endTime = signal.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphWrapper.isDisposed()) {
+ return;
+ }
+ fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+ startZoomThread(startTime, endTime);
+ }
+ });
+ }
+
+ /**
+ * @param signal the format of the timestamps was updated.
+ * @since 2.1
+ */
+ @TmfSignalHandler
+ public void updateTimeFormat( final TmfTimestampFormatUpdateSignal signal){
+ fTimeGraphWrapper.refresh();
+ }
+
+ // ------------------------------------------------------------------------
+ // Internal
+ // ------------------------------------------------------------------------
+
+ private void loadTrace() {
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ rebuild();
+ } else {
+ fStartTime = fTrace.getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ fEndTime = fTrace.getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ refresh();
+ }
+ }
+ }
+
+ /**
+ * Forces a rebuild of the entries list, even if entries already exist for this trace
+ * @since 3.0
+ */
+ protected void rebuild() {
+ setStartTime(Long.MAX_VALUE);
+ setEndTime(Long.MIN_VALUE);
+ synchronized (fBuildThreadMap) {
+ for (ITmfTrace trace : getTracesToBuild(fTrace)) {
+ BuildThread buildThread = new BuildThread(trace, fTrace, getName());
+ fBuildThreadMap.put(trace, buildThread);
+ buildThread.start();
+ }
+ }
+ }
+
+ /**
+ * Method called when synching to a given timestamp. Inheriting classes can
+ * perform actions here to update the view at the given timestamp.
+ *
+ * @param time
+ * The currently selected time
+ */
+ protected void synchingToTime(long time) {
+
+ }
+
+ /**
+ * Return the list of traces whose data or analysis results will be used to
+ * populate the view. By default, if the trace is an experiment, the traces
+ * under it will be returned, otherwise, the trace itself is returned.
+ *
+ * A build thread will be started for each trace returned by this method,
+ * some of which may receive events in live streaming mode.
+ *
+ * @param trace
+ * The trace associated with this view
+ * @return List of traces with data to display
+ * @since 3.0
+ */
+ protected Iterable<ITmfTrace> getTracesToBuild(ITmfTrace trace) {
+ return Arrays.asList(TmfTraceManager.getTraceSet(trace));
+ }
+
+ /**
+ * Build the entries list to show in this time graph
+ *
+ * Called from the BuildThread
+ *
+ * @param trace
+ * The trace being built
+ * @param parentTrace
+ * The parent of the trace set, or the trace itself
+ * @param monitor
+ * The progress monitor object
+ * @since 3.0
+ */
+ protected abstract void buildEventList(ITmfTrace trace, ITmfTrace parentTrace, IProgressMonitor monitor);
+
+ /**
+ * Gets the list of event for an entry in a given timerange
+ *
+ * @param entry
+ * The entry to get events for
+ * @param startTime
+ * Start of the time range
+ * @param endTime
+ * End of the time range
+ * @param resolution
+ * The resolution
+ * @param monitor
+ * The progress monitor object
+ * @return The list of events for the entry
+ */
+ protected abstract @Nullable List<ITimeEvent> getEventList(TimeGraphEntry entry,
+ long startTime, long endTime, long resolution,
+ IProgressMonitor monitor);
+
+ /**
+ * Gets the list of links (displayed as arrows) for a trace in a given
+ * timerange. Default implementation returns an empty list.
+ *
+ * @param startTime
+ * Start of the time range
+ * @param endTime
+ * End of the time range
+ * @param resolution
+ * The resolution
+ * @param monitor
+ * The progress monitor object
+ * @return The list of link events
+ * @since 2.1
+ */
+ protected List<ILinkEvent> getLinkList(long startTime, long endTime,
+ long resolution, IProgressMonitor monitor) {
+ return new ArrayList<>();
+ }
+
+
+ /**
+ * Refresh the display
+ */
+ protected void refresh() {
+ TmfUiRefreshHandler.getInstance().queueUpdate(this, new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphWrapper.isDisposed()) {
+ return;
+ }
+ boolean hasEntries = false;
+ synchronized (fEntryListMap) {
+ fEntryList = fEntryListMap.get(fTrace);
+ if (fEntryList == null) {
+ fEntryList = new CopyOnWriteArrayList<>();
+ } else if (fEntryComparator != null) {
+ List<TimeGraphEntry> list = new ArrayList<>(fEntryList);
+ Collections.sort(list, fEntryComparator);
+ fEntryList.clear();
+ fEntryList.addAll(list);
+ }
+ hasEntries = fEntryList.size() != 0;
+ }
+ if (fEntryList != fTimeGraphWrapper.getInput()) {
+ fTimeGraphWrapper.setInput(fEntryList);
+ } else {
+ fTimeGraphWrapper.refresh();
+ }
+ fTimeGraphWrapper.getTimeGraphViewer().setTimeBounds(fStartTime, fEndTime);
+
+ long selectionBeginTime = fTrace == null ? 0 : fTraceManager.getSelectionBeginTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long selectionEndTime = fTrace == null ? 0 : fTraceManager.getSelectionEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long startTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getStartTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ long endTime = fTrace == null ? 0 : fTraceManager.getCurrentRange().getEndTime().normalize(0, ITmfTimestamp.NANOSECOND_SCALE).getValue();
+ startTime = Math.max(startTime, fStartTime);
+ endTime = Math.min(endTime, fEndTime);
+ fTimeGraphWrapper.getTimeGraphViewer().setSelectionRange(selectionBeginTime, selectionEndTime);
+ fTimeGraphWrapper.getTimeGraphViewer().setStartFinishTime(startTime, endTime);
+
+ if (fTimeGraphWrapper instanceof TimeGraphComboWrapper && !fPackDone) {
+ for (TreeColumn column : ((TimeGraphComboWrapper) fTimeGraphWrapper).getTreeViewer().getTree().getColumns()) {
+ column.pack();
+ }
+ if (hasEntries) {
+ fPackDone = true;
+ }
+ }
+
+ startZoomThread(startTime, endTime);
+ }
+ });
+ }
+
+ /**
+ * Redraw the canvas
+ */
+ protected void redraw() {
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.IDLE) {
+ fRedrawState = State.BUSY;
+ } else {
+ fRedrawState = State.PENDING;
+ return;
+ }
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fTimeGraphWrapper.isDisposed()) {
+ return;
+ }
+ fTimeGraphWrapper.redraw();
+ fTimeGraphWrapper.update();
+ synchronized (fSyncObj) {
+ if (fRedrawState == State.PENDING) {
+ fRedrawState = State.IDLE;
+ redraw();
+ } else {
+ fRedrawState = State.IDLE;
+ }
+ }
+ }
+ });
+ }
+
+ private void startZoomThread(long startTime, long endTime) {
+ if (fZoomThread != null) {
+ fZoomThread.cancel();
+ }
+ fZoomThread = new ZoomThread(fEntryList, startTime, endTime, getName());
+ fZoomThread.start();
+ }
+
+ private void makeActions() {
+ fPreviousResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getPreviousItemAction();
+ fPreviousResourceAction.setText(getPrevText());
+ fPreviousResourceAction.setToolTipText(getPrevTooltip());
+ fNextResourceAction = fTimeGraphWrapper.getTimeGraphViewer().getNextItemAction();
+ fNextResourceAction.setText(getNextText());
+ fNextResourceAction.setToolTipText(getNextTooltip());
+ }
+
+ private void contributeToActionBars() {
+ IActionBars bars = getViewSite().getActionBars();
+ fillLocalToolBar(bars.getToolBarManager());
+ }
+
+ /**
+ * Add actions to local tool bar manager
+ *
+ * @param manager the tool bar manager
+ */
+ protected void fillLocalToolBar(IToolBarManager manager) {
+ if (fTimeGraphWrapper instanceof TimeGraphComboWrapper) {
+ if (fFilterColumns != null && fFilterLabelProvider != null && fFilterColumns.length > 0) {
+ manager.add(((TimeGraphComboWrapper) fTimeGraphWrapper).getShowFilterAction());
+ }
+ }
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getShowLegendAction());
+ manager.add(new Separator());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getResetScaleAction());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getPreviousEventAction());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getNextEventAction());
+ manager.add(fPreviousResourceAction);
+ manager.add(fNextResourceAction);
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomInAction());
+ manager.add(fTimeGraphWrapper.getTimeGraphViewer().getZoomOutAction());
+ manager.add(new Separator());
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/Messages.java
new file mode 100644
index 0000000000..b301d7048f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/Messages.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2013 École Polytechnique de Montréal
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Geneviève Bastien - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.timegraph;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Generic messages for the bar charts
+ *
+ * @since 2.1
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.timegraph.messages"; //$NON-NLS-1$
+
+ public static String AbstractTimeGraphtView_NextText;
+ public static String AbstractTimeGraphView_NextTooltip;
+ public static String AbstractTimeGraphView_PreviousText;
+ public static String AbstractTimeGraphView_PreviousTooltip;
+ public static String TimeGraphPresentationProvider_multipleStates;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/messages.properties
new file mode 100644
index 0000000000..52adaa617b
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/messages.properties
@@ -0,0 +1,16 @@
+###############################################################################
+# Copyright (c) 2014 Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+###############################################################################
+AbstractTimeGraphtView_NextText=Next
+AbstractTimeGraphView_NextTooltip=Next element
+AbstractTimeGraphView_PreviousText=Previous
+AbstractTimeGraphView_PreviousTooltip=Previous element
+TimeGraphPresentationProvider_multipleStates=multiple states
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DiagramToolTip.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DiagramToolTip.java
new file mode 100755
index 0000000000..1301222e9f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DiagramToolTip.java
@@ -0,0 +1,131 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * <p>
+ * This class is used to reproduce the same tooltip behavior on Windows and Linux when the mouse hovers over the
+ * sequence diagram
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class DiagramToolTip {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ private static final int CHARACTERS_PER_COLUMN = 100;
+ private static final int DEFAULT_CURSOR_HEIGHT = 32;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The parent control where the tooltip must be drawn.
+ */
+ private Control fParent = null;
+ /**
+ * The tooltip shell.
+ */
+ private Shell fToolTipShell = null;
+ /**
+ * The text box.
+ */
+ private Text fTextBox = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a new tooltip for the given parent control
+ *
+ * @param parent the parent control.
+ */
+ public DiagramToolTip(Control parent) {
+ fParent = parent;
+ fToolTipShell = new Shell(fParent.getShell(), SWT.MULTI);
+ fToolTipShell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ fTextBox = new Text(fToolTipShell, SWT.WRAP | SWT.MULTI);
+ fTextBox.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Display the tooltip using the given text The tooltip will stay on screen until it is told otherwise
+ *
+ * @param value the text to display
+ */
+ public void showToolTip(String value) {
+ if ((value == null) || (value.equalsIgnoreCase(""))) { //$NON-NLS-1$
+ fToolTipShell.setVisible(false);
+ return;
+ }
+
+ int w = fToolTipShell.getBounds().width;
+ Point hr = Display.getDefault().getCursorLocation();
+ int cursorH = DEFAULT_CURSOR_HEIGHT;
+ for (int i = 0; i < Display.getDefault().getCursorSizes().length; i++) {
+ if (Display.getDefault().getCursorSizes()[i].y < cursorH) {
+ cursorH = Display.getDefault().getCursorSizes()[i].y;
+ }
+ }
+ if (hr.x + w > Display.getDefault().getBounds().width) {
+ int tempX = (hr.x + w) - Display.getDefault().getBounds().width;
+ if (tempX > Display.getDefault().getBounds().width) {
+ hr.x = 0;
+ }
+ hr.x = hr.x - tempX;
+ }
+ fTextBox.setText(value);
+ GC gc = new GC(fTextBox);
+ FontMetrics fm = gc.getFontMetrics();
+ gc.dispose();
+ int width = CHARACTERS_PER_COLUMN * fm.getAverageCharWidth();
+ fTextBox.setSize(fTextBox.computeSize(width, fTextBox.getLineCount() * fTextBox.getLineHeight()));
+ fToolTipShell.setLocation(hr.x, hr.y + cursorH);
+ fToolTipShell.setSize(fTextBox.getSize());
+ fTextBox.setVisible(true);
+ fToolTipShell.setVisible(true);
+ }
+
+ /**
+ * Hide the tooltip
+ */
+ public void hideToolTip() {
+ fToolTipShell.setVisible(false);
+ }
+
+ /**
+ * @return parent control
+ * @since 2.0
+ */
+ protected Control getParent() {
+ return fParent;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DrawableToolTip.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DrawableToolTip.java
new file mode 100755
index 0000000000..d06eb52d69
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/DrawableToolTip.java
@@ -0,0 +1,305 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * <p>
+ * This class is used to reproduce the same tooltip behavior on Windows and Linux when the mouse move hover the time
+ * compression bar used to display elapsed time using a tooltip. The tooltip is composed of 2 parts, the text value and
+ * below, a scale to visually locate the value in a time range (usually the minimum an maximum elapsed time in the whole
+ * diagram)
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class DrawableToolTip implements PaintListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ private static final int HORIZONTAL_MARGIN = 10;
+ private static final int VERTICAL_MARGIN = 10;
+ private static final int TEXT_SCALE_MARGIN = 20;
+ private static final int SCALE_LENGTH = 100;
+ private static final int SHELL_WIDTH = 200;
+ private static final int SHELL_HEIGHT = 50;
+ private static final int NUMBER_STEPS = 10;
+ private static final int BASE_RED_VALUE = 255;
+ private static final int BASE_GREEN_BLUE_VALUE = 225;
+ private static final int COLOR_STEP = 25;
+ private static final int BOUNDS_Y_OFFSET = 26;
+ private static final int RECTANGLE_HEIGHT = 11;
+ private static final int DEFAULT_LINE_WIDTH = 10;
+ private static final int BORDER_LINE_WIDTH = 14;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The tooltip shell
+ */
+ private Shell fToolTipShell = null;
+ /**
+ * The Time range data.
+ */
+ private TmfTimeRange fMinMaxRange;
+ /**
+ * The current time.
+ */
+ private ITmfTimestamp fCurrentValue;
+ /**
+ * The horizontal margin used for drawing.
+ */
+ private static int fHorMargin = HORIZONTAL_MARGIN;
+ /**
+ * The vertical margin used for drawing.
+ */
+ private static int fVertMargin = VERTICAL_MARGIN;
+ /**
+ * The minimum text scale margin.
+ */
+ private static int fTextScaleMargin = TEXT_SCALE_MARGIN;
+ /**
+ * The length of the text scale.
+ */
+ private static int fScaleLength = SCALE_LENGTH;
+ /**
+ * The text to display
+ */
+ private String fMessage;
+ /**
+ * The color array used to represent the 10 time range slices
+ */
+ private Color[] fColors;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Creates a drawable tool tip instance.
+ *
+ * @param parent The parent composite.
+ */
+ public DrawableToolTip(Composite parent) {
+ fToolTipShell = new Shell(parent.getShell(), SWT.ON_TOP);
+ fToolTipShell.setLayout(new RowLayout());
+ fToolTipShell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
+ fToolTipShell.addPaintListener(this);
+ fToolTipShell.setSize(SHELL_WIDTH, SHELL_HEIGHT);
+
+ fColors = new Color[NUMBER_STEPS];
+ int greenBlue = BASE_GREEN_BLUE_VALUE;
+ final int step = COLOR_STEP;
+ for (int i = 0; i < fColors.length; i++) {
+ fColors[i] = new Color(Display.getDefault(), BASE_RED_VALUE, greenBlue, greenBlue);
+ greenBlue -= step;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Returns the message to display.
+ *
+ * @return the message to display.
+ */
+ public String getText() {
+ return fMessage;
+ }
+
+ /**
+ * Returns teh current time to display.
+ *
+ * @return the current time to display
+ */
+ public String getAccessibleText() {
+ return fCurrentValue.toString();
+ }
+
+ /**
+ * Returns the horizontal margin.
+ *
+ * @return the horizontal margin.
+ */
+ protected static int getHorizontalMargin() {
+ return fHorMargin;
+ }
+
+ /**
+ * Sets the horizontal margin.
+ *
+ * @param margin The margin to set.
+ */
+ protected static void setHorizontalMargin(int margin) {
+ fHorMargin = margin;
+ }
+
+ /**
+ * Returns the vertical margin.
+ *
+ * @return the vertical margin.
+ */
+ protected static int getVerticalMargin() {
+ return fVertMargin;
+ }
+
+ /**
+ * Sets the vertical margin.
+ *
+ * @param margin The margin to set.
+ */
+ protected static void setVerticalMargin(int margin) {
+ fVertMargin = margin;
+ }
+
+ /**
+ * Returns the text scale margin.
+ *
+ * @return the text scale margin.
+ */
+ protected static int getTextScaleMargin() {
+ return fTextScaleMargin;
+ }
+
+ /**
+ * Sets the text scale margin.
+ * @param textScaleMargin The margin to set.
+ */
+ protected static void setTestScaleMargin(int textScaleMargin) {
+ fTextScaleMargin = textScaleMargin;
+ }
+
+ /**
+ * Returns the scale length.
+ *
+ * @return the scale length.
+ */
+ protected static int getScaleLength() {
+ return fScaleLength;
+ }
+
+ /**
+ * Sets the scale length.
+ *
+ * @param scaleLength The scale length to set.
+ */
+ protected static void setScaleLength(int scaleLength) {
+ fScaleLength = scaleLength;
+ }
+
+ /**
+ * Display the tooltip using the given time range(min,max) the current value and the time unit The tooltip will stay
+ * on screen until it is told otherwise
+ *
+ * @param value the current in the scale
+ * @param min the scale min
+ * @param max the scale max
+ * @since 2.0
+ */
+ public void showToolTip(ITmfTimestamp value, ITmfTimestamp min, ITmfTimestamp max) {
+ fMinMaxRange = new TmfTimeRange(min, max);
+ fCurrentValue = value;
+
+ int w = fToolTipShell.getBounds().width;
+ int h = fToolTipShell.getBounds().height;
+ Point hr = Display.getDefault().getCursorLocation();
+ fToolTipShell.setBounds(hr.x, hr.y + BOUNDS_Y_OFFSET, w, h);
+ fToolTipShell.setVisible(true);
+ }
+
+ /**
+ * Hide the tooltip.
+ */
+ public void hideToolTip() {
+ fToolTipShell.setVisible(false);
+ }
+
+ /**
+ * Disposes the system resource used by this kind of toolTips (a colors array essentially)
+ */
+ public void dispose() {
+ for (int i = 0; i < fColors.length; i++) {
+ fColors[i].dispose();
+ }
+ }
+
+ @Override
+ public void paintControl(PaintEvent event) {
+ fMessage = Messages.SequenceDiagram_Delta + " " + fCurrentValue.toString(); //$NON-NLS-1$
+ Point size = event.gc.textExtent(fMessage);
+ if (size.x < fScaleLength) {
+ size.x = fScaleLength;
+ }
+ event.gc.drawText(fMessage, fHorMargin, fVertMargin, true);
+ event.gc.drawLine(fHorMargin, fVertMargin + fTextScaleMargin + size.y, fHorMargin + fScaleLength, fVertMargin + fTextScaleMargin + size.y);
+
+ int step = fScaleLength / NUMBER_STEPS;
+
+ ITmfTimestamp minMaxdelta = fMinMaxRange.getEndTime().getDelta(fMinMaxRange.getStartTime());
+ double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
+
+ ITmfTimestamp delta = fCurrentValue.getDelta(fMinMaxRange.getStartTime());
+ long absDelta = Math.abs(delta.getValue());
+
+ int colIndex = 0;
+ if (gr != 0) {
+ colIndex = Math.round((float) (absDelta / gr));
+ if (colIndex > fColors.length) {
+ colIndex = fColors.length;
+ } else if (colIndex <= 1) {
+ colIndex = 1;
+ }
+ } else {
+ colIndex = 1;
+ }
+
+ for (int i = 0; i <= NUMBER_STEPS; i++) {
+ if (i < NUMBER_STEPS) {
+ event.gc.setBackground(fColors[i]);
+ }
+ if ((i < colIndex) && (i < NUMBER_STEPS)) {
+ event.gc.fillRectangle(fHorMargin + i * step, fVertMargin + fTextScaleMargin + size.y - 5, step, RECTANGLE_HEIGHT);
+ }
+ if (i == 0) {
+ event.gc.drawText(Messages.SequenceDiagram_Min, fHorMargin, size.y + 2 * fVertMargin + fTextScaleMargin, true);
+ }
+ if (i == 0) {
+ int len = event.gc.textExtent(Messages.SequenceDiagram_Max).x;
+ event.gc.drawText(Messages.SequenceDiagram_Max, fHorMargin + fScaleLength - len + 1, size.y + 2 * fVertMargin + fTextScaleMargin, true);
+ }
+ int lineWidth = DEFAULT_LINE_WIDTH;
+ if ((i == 0) || (i == NUMBER_STEPS)) {
+ lineWidth = BORDER_LINE_WIDTH;
+ }
+ event.gc.drawLine(fHorMargin + i * step, fVertMargin + fTextScaleMargin + size.y - lineWidth / 2, fHorMargin + i * step, fVertMargin + fTextScaleMargin + size.y + lineWidth / 2);
+ }
+ fToolTipShell.setSize(size.x + 2 * fHorMargin + 2, 2 * size.y + 3 * fVertMargin + fTextScaleMargin);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ITimeCompressionListener.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ITimeCompressionListener.java
new file mode 100755
index 0000000000..e6506c8bdb
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ITimeCompressionListener.java
@@ -0,0 +1,42 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+
+/**
+ * <p>
+ * Listener interface for the time compression bar to notify about dela selection.
+ * </p>
+ *
+ * @author sveyrier
+ * @version 1.0
+ */
+public interface ITimeCompressionListener {
+
+ /**
+ * Notifies listeners about a selected delta.
+ *
+ * @param lifeline
+ * The current lifeline.
+ * @param startEvent
+ * The start event selected.
+ * @param nbEvent
+ * A number of events.
+ * @param color
+ * The current color to use.
+ */
+ void deltaSelected(Lifeline lifeline, int startEvent, int nbEvent, IColor color);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/NGC.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/NGC.java
new file mode 100755
index 0000000000..a686868929
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/NGC.java
@@ -0,0 +1,988 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+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.Display;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IFont;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl.ColorImpl;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * <p>
+ * This class implements the graphical context for the sequence diagram widgets.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class NGC implements IGC {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The graphical context.
+ */
+ private GC fContext;
+ /**
+ * The reference to the sequence diagram view.
+ */
+ private SDWidget fView;
+ /**
+ * A reference to the last used font.
+ */
+ private Font fTempFont = null;
+ /**
+ * The color of the gradient.
+ */
+ private IColor fGradientColor = null;
+ /**
+ * The color of the background.
+ */
+ private IColor fBackground = null;
+ /**
+ * The color of the foreground.
+ */
+ private IColor fForeground = null;
+ /**
+ * The current visible y screen bounds
+ */
+ private int fVisibleY;
+ /**
+ * The current visible x screen bound.
+ */
+ private int fVisibleX;
+ /**
+ * The current yx value (view visible height - visible screen bounds)
+ */
+ private int yx;
+ /**
+ * The current xx value (view visible width - visible screen bounds)
+ */
+ private int xx;
+ /**
+ * <code>true</code> to draw with focus else <code>false</code>.
+ */
+ private boolean fDrawWithFocus = false;
+
+ /**
+ * The static visible screen bounds.
+ */
+ private static int fVisibleScreenBounds = 0;
+
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor.
+ *
+ * @param scrollView A sequence diagram view reference.
+ * @param gc A graphical context.
+ */
+ public NGC(SDWidget scrollView, GC gc) {
+ fContext = gc;
+ fView = scrollView;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void setLineStyle(int style) {
+ fContext.setLineStyle(style);
+ }
+
+ @Override
+ public int getLineStyle() {
+ return fContext.getLineStyle();
+ }
+
+ @Override
+ public int getContentsX() {
+ return Math.round(fView.getContentsX() / fView.getZoomValue());
+ }
+
+ @Override
+ public int getContentsY() {
+ return Math.round(fView.getContentsY() / fView.getZoomValue());
+ }
+
+ @Override
+ public int getVisibleWidth() {
+ return Math.round(fView.getVisibleWidth() / fView.getZoomValue());
+ }
+
+ @Override
+ public int getVisibleHeight() {
+ return Math.round(fView.getVisibleHeight() / fView.getZoomValue());
+ }
+
+ /**
+ * Returns the current visible y screen bounds.
+ *
+ * @return the current visible y screen bounds
+ * @since 2.0
+ */
+ protected int getVisibleY() {
+ return fVisibleY;
+ }
+
+ /**
+ * Sets the current visible y screen bounds.
+ *
+ * @param visibleY
+ * the current visible y screen bounds
+ * @since 2.0
+ */
+ protected void setVisibleY(int visibleY) {
+ fVisibleY = visibleY;
+ }
+
+ /**
+ * Returns the current visible x screen bound.
+ *
+ * @return the current visible x screen bound.
+ * @since 2.0
+ *
+ */
+ protected int getfVisibleX() {
+ return fVisibleX;
+ }
+
+ /**
+ * Sets the current visible x screen bound.
+ *
+ * @param visibleX
+ * the current visible x screen bound.
+ * @since 2.0
+ *
+ */
+ protected void setVisibleX(int visibleX) {
+ fVisibleX = visibleX;
+ }
+
+ /**
+ * Returns current yx value (view visible height - visible screen bounds).
+ *
+ * @return current yx value
+ * @since 2.0
+ */
+ protected int getYx() {
+ return yx;
+ }
+
+ /**
+ * Sets current yx value (view visible height - visible screen bounds).
+ *
+ * @param yx
+ * current yx value
+ * @since 2.0
+ */
+ protected void setYx(int yx) {
+ this.yx = yx;
+ }
+
+ /**
+ * Returns the current xx value (view visible width - visible screen bounds)
+ *
+ * @return the current xx value
+ * @since 2.0
+ */
+ protected int getXx() {
+ return xx;
+ }
+
+ /**
+ * Sets the current xx value (view visible width - visible screen bounds)
+ *
+ * @param xx
+ * the current xx value
+ * @since 2.0
+ */
+ protected void setXx(int xx) {
+ this.xx = xx;
+ }
+
+ @Override
+ public int contentsToViewX(int x) {
+ return fView.contentsToViewX(x);
+ }
+
+ @Override
+ public int contentsToViewY(int y) {
+ return fView.contentsToViewY(y);
+ }
+
+ /**
+ * Get code for drawings at given x and y position.
+ *
+ * @param x The x position
+ * @param y The y position.
+ * @return A code for top, bottom, right and left
+ */
+ protected byte code(int x, int y) {
+ byte c = 0;
+ fVisibleY = fVisibleScreenBounds;
+ fVisibleX = fVisibleScreenBounds;
+ yx = fView.getVisibleHeight() + fVisibleScreenBounds;
+ xx = fView.getVisibleWidth() + fVisibleScreenBounds;
+ if (y > yx) {
+ c |= 0x01; // top
+ } else if (y < fVisibleY) {
+ c |= 0x02; // bottom
+ }
+
+ if (x > xx) {
+ c |= 0x04; // right
+ } else if (x < fVisibleX) {
+ c |= 0x08; // left
+ }
+ return c;
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ int localX1 = x1;
+ int localY1 = y1;
+ int localX2 = x2;
+ int localY2 = y2;
+
+ localX1 = Math.round(localX1 * fView.getZoomValue());
+ localY1 = Math.round(localY1 * fView.getZoomValue());
+ localX2 = Math.round(localX2 * fView.getZoomValue());
+ localY2 = Math.round(localY2 * fView.getZoomValue());
+ localX1 = fView.contentsToViewX(localX1);
+ localY1 = fView.contentsToViewY(localY1);
+ localX2 = fView.contentsToViewX(localX2);
+ localY2 = fView.contentsToViewY(localY2);
+
+ byte code1 = code(localX1, localY1);
+ byte code2 = code(localX2, localY2);
+ byte codex;
+ boolean draw = false;
+ boolean end = false;
+ int x = 0, y = 0;
+
+ do {
+ if (code1 == 0 && code2 == 0) {
+ draw = true;
+ end = true;
+ } else if ((code1 & code2) != 0) {
+ end = true;
+ } else {
+ codex = (code1 != 0) ? code1 : code2;
+ if ((codex & 0x01) != 0) { // top
+ x = localX1 + ((localX2 - localX1) * (yx - localY1)) / (localY2 - localY1);
+ y = yx;
+ } else if ((codex & 0x02) != 0) { // bottom
+ x = localX1 + ((localX2 - localX1) * (fVisibleY - localY1)) / (localY2 - localY1);
+ y = fVisibleY;
+ } else if ((codex & 0x04) != 0) { // right
+ y = localY1 + ((localY2 - localY1) * (xx - localX1)) / (localX2 - localX1);
+ x = xx;
+ } else if ((codex & 0x08) != 0) { // left
+ y = localY1 + ((localY2 - localY1) * (fVisibleX - localX1)) / (localX2 - localX1);
+ x = fVisibleX;
+ }
+
+ if (codex == code1) {
+ localX1 = x;
+ localY1 = y;
+ code1 = code(localX1, localY1);
+ } else {
+ localX2 = x;
+ localY2 = y;
+ code2 = code(localX2, localY2);
+ }
+ }
+ } while (!end);
+
+ if (draw) {
+ fContext.drawLine(localX1, localY1, localX2, localY2);
+ }
+ }
+
+ @Override
+ public void drawRectangle(int x, int y, int width, int height) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ // Workaround to avoid problems for some special cases (not very nice)
+ if (localY != getContentsY()) {
+ localY = Math.round(localY * fView.getZoomValue());
+ localY = fView.contentsToViewY(localY);
+ } else {
+ localY = 0;
+ }
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ localX = fView.contentsToViewX(localX);
+
+ if (localX < -fVisibleScreenBounds) {
+ localWidth = localWidth + localX + fVisibleScreenBounds;
+ localX = -fVisibleScreenBounds;
+ }
+ if (localY < -fVisibleScreenBounds) {
+ localHeight = localHeight + localY + fVisibleScreenBounds;
+ localY = -fVisibleScreenBounds;
+ }
+ if ((localWidth < -fVisibleScreenBounds) && (localX + localWidth < -fVisibleScreenBounds)) {
+ localWidth = -fVisibleScreenBounds;
+ } else if (localWidth + localX > fView.getVisibleWidth() + fVisibleScreenBounds) {
+ localWidth = fView.getVisibleWidth() + fVisibleScreenBounds - localX;
+ }
+ if ((localHeight < -fVisibleScreenBounds) && (localY + localHeight < -fVisibleScreenBounds)) {
+ localHeight = -fVisibleScreenBounds;
+ } else if (localHeight + localY > fView.getVisibleHeight() + fVisibleScreenBounds) {
+ localHeight = fView.getVisibleHeight() + fVisibleScreenBounds - localY;
+ }
+ fContext.drawRectangle(localX, localY, localWidth, localHeight);
+ }
+
+ @Override
+ public void drawFocus(int x, int y, int width, int height) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ IColor bC = getBackground();
+ IColor fC = getForeground();
+
+ if (localWidth < 0) {
+ localX = localX + localWidth;
+ localWidth = -localWidth;
+ }
+
+ if (localHeight < 0) {
+ localY = localY + localHeight;
+ localHeight = -localHeight;
+ }
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+
+ setForeground(SDViewPref.getInstance().getForeGroundColorSelection());
+ setBackground(SDViewPref.getInstance().getBackGroundColorSelection());
+
+ fContext.drawFocus(fView.contentsToViewX(localX - 1), fView.contentsToViewY(localY - 1), localWidth + 3, localHeight + 3);
+
+ setBackground(bC);
+ setForeground(fC);
+ }
+
+ @Override
+ public void fillPolygon(int[] points) {
+ int len = (points.length / 2) * 2;
+ int[] localPoint = new int[len];
+ for (int i = 0; i < len; i++) {
+ localPoint[i] = fView.contentsToViewX(Math.round(points[i] * fView.getZoomValue()));
+ i++;
+ localPoint[i] = fView.contentsToViewY(Math.round(points[i] * fView.getZoomValue()));
+ }
+
+ if (validatePolygonHeight(localPoint) <= 0) {
+ return;
+ }
+
+ fContext.fillPolygon(localPoint);
+ }
+
+ @Override
+ public void drawPolygon(int[] points) {
+ int len = (points.length / 2) * 2;
+ int[] localPoint = new int[len];
+ for (int i = 0; i < len; i++) {
+ localPoint[i] = fView.contentsToViewX(Math.round(points[i] * fView.getZoomValue()));
+ i++;
+ localPoint[i] = fView.contentsToViewY(Math.round(points[i] * fView.getZoomValue()));
+ }
+
+ if (validatePolygonHeight(localPoint) <= 0) {
+ return;
+ }
+
+ fContext.drawPolygon(localPoint);
+ }
+
+ @Override
+ public void fillRectangle(int x, int y, int width, int height) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ // Workaround to avoid problems for some special cases (not very nice)
+ if (localY != getContentsY()) {
+ localY = Math.round(localY * fView.getZoomValue());
+ localY = fView.contentsToViewY(localY) + 1;
+ } else {
+ localY = 1;
+ }
+ localWidth = Math.round(localWidth * fView.getZoomValue()) - 1;
+ localHeight = Math.round(localHeight * fView.getZoomValue()) - 1;
+ localX = fView.contentsToViewX(localX) + 1;
+ if (localX < -fVisibleScreenBounds) {
+ localWidth = localWidth + localX + fVisibleScreenBounds;
+ localX = -fVisibleScreenBounds;
+ }
+ if (localY < -fVisibleScreenBounds) {
+ localHeight = localHeight + localY + fVisibleScreenBounds;
+ localY = -fVisibleScreenBounds;
+ }
+ if ((localWidth < -fVisibleScreenBounds) && (localX + localWidth < -fVisibleScreenBounds)) {
+ localWidth = -fVisibleScreenBounds;
+ } else if (localWidth + localX > fView.getVisibleWidth() + fVisibleScreenBounds) {
+ localWidth = fView.getVisibleWidth() + fVisibleScreenBounds - localX;
+ }
+ if ((localHeight < -fVisibleScreenBounds) && (localY + localHeight < -fVisibleScreenBounds)) {
+ localHeight = -fVisibleScreenBounds;
+ } else if (localHeight + localY > fView.getVisibleHeight() + fVisibleScreenBounds) {
+ localHeight = fView.getVisibleHeight() + fVisibleScreenBounds - localY;
+ }
+ fContext.fillRectangle(localX, localY, localWidth, localHeight);
+ }
+
+ @Override
+ public void fillGradientRectangle(int x, int y, int width, int height, boolean isVertical) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ IColor tempColor = fForeground;
+ setForeground(fGradientColor);
+ localX = fView.contentsToViewX(localX);
+ localY = fView.contentsToViewY(localY);
+
+ if (localX < -fVisibleScreenBounds) {
+ localWidth = localWidth + localX + fVisibleScreenBounds;
+ localX = -fVisibleScreenBounds;
+ }
+ if (localY < -fVisibleScreenBounds) {
+ localHeight = localHeight + localY + fVisibleScreenBounds;
+ localY = -fVisibleScreenBounds;
+ }
+
+ if ((localWidth < -fVisibleScreenBounds) && (localX + localWidth < -fVisibleScreenBounds)) {
+ localWidth = -fVisibleScreenBounds;
+ } else if (localWidth + localX > fView.getVisibleWidth() + fVisibleScreenBounds) {
+ localWidth = fView.getVisibleWidth() + fVisibleScreenBounds - localX;
+ }
+ if ((localHeight < -fVisibleScreenBounds) && (localY + localHeight < -fVisibleScreenBounds)) {
+ localHeight = -fVisibleScreenBounds;
+ } else if (localHeight + localY > fView.getVisibleHeight() + fVisibleScreenBounds) {
+ localHeight = fView.getVisibleHeight() + fVisibleScreenBounds - localY;
+ }
+ if (isVertical) {
+ fContext.fillGradientRectangle(localX, localY, localWidth, localHeight, isVertical);
+ }
+ else {
+ fContext.fillGradientRectangle(localX + localWidth, localY, -localWidth, localHeight + 1, isVertical);
+ }
+ setForeground(tempColor);
+ }
+
+ @Override
+ public int textExtent(String name) {
+ return fContext.textExtent(name).x;
+ }
+
+ @Override
+ public void drawText(String string, int x, int y, boolean isTrans) {
+ int localX = x;
+ int localY = y;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ fContext.drawText(string, fView.contentsToViewX(localX), fView.contentsToViewY(localY), isTrans);
+ if (fDrawWithFocus) {
+ Point r = fContext.textExtent(string);
+ fContext.drawFocus(localX - 1, localY - 1, r.x + 2, r.y + 2);
+ }
+ }
+
+ @Override
+ public void drawText(String string, int x, int y) {
+ int localX = x;
+ int localY = y;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ fContext.drawText(string, fView.contentsToViewX(localX), fView.contentsToViewY(localY), true);
+ if (fDrawWithFocus) {
+ Point r = fContext.textExtent(string);
+ fContext.drawFocus(localX - 1, localY - 1, r.x + 2, r.y + 2);
+ }
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ fContext.fillOval(fView.contentsToViewX(localX), fView.contentsToViewY(localY), localWidth, localHeight);
+ }
+
+ @Override
+ public IColor getBackground() {
+ if ((fBackground != null) && (fBackground.getColor() instanceof Color) && (!((Color) (fBackground.getColor())).isDisposed())) {
+ return fBackground;
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ @Override
+ public IColor getForeground() {
+ if ((fForeground != null) && (fForeground.getColor() instanceof Color) && (!((Color) (fForeground.getColor())).isDisposed())) {
+ return fForeground;
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ @Override
+ public void setBackground(IColor color) {
+ if (color == null) {
+ return;
+ }
+ if (color.getColor() instanceof Color) {
+ fContext.setBackground((Color) color.getColor());
+ fBackground = color;
+ }
+ }
+
+ @Override
+ public void setForeground(IColor color) {
+ if (color == null) {
+ return;
+ }
+ if (color.getColor() instanceof Color) {
+ Color c = (Color) color.getColor();
+ if (!c.isDisposed()) {
+ fContext.setForeground(c);
+ fForeground = color;
+ }
+ }
+ }
+
+ @Override
+ public void setGradientColor(IColor color) {
+ if (color == null) {
+ return;
+ }
+ if (color.getColor() instanceof Color) {
+ fGradientColor = color;
+ }
+ }
+
+ @Override
+ public void setLineWidth(int width) {
+ if (fView.isPrinting()) {
+ fContext.setLineWidth(width * 2);
+ }
+ else {
+ fContext.setLineWidth(width);
+ }
+ }
+
+ @Override
+ public int getLineWidth() {
+ return fContext.getLineWidth();
+ }
+
+ /**
+ * Method to draw a text in rectangle. (Linux GTK Workaround)
+ *
+ * @param string The text to draw.
+ * @param x The x position.
+ * @param y The y position.
+ * @param isTransparent true for transparent else false
+ */
+ protected void localDrawText(String string, int x, int y, boolean isTransparent) {
+ Point r = fContext.textExtent(string);
+ if (!isTransparent) {
+ fContext.fillRectangle(x, y, r.x, r.y);
+ }
+ fContext.drawText(string, x, y, isTransparent);
+ if ((fDrawWithFocus) && (string.length() > 1)) {
+ fContext.drawFocus(x - 1, y - 1, r.x + 2, r.y + 2);
+ }
+ }
+
+ @Override
+ public void drawTextTruncatedCentred(String name, int xValue, int yValue, int width, int height, boolean trans) {
+ int localX = xValue;
+ int localY = yValue;
+ int localWidth = width;
+ int localHeight = height;
+
+ Point tx = fContext.textExtent(name);
+ localX = Math.round(localX * fView.getZoomValue());
+ int y = 0;
+ // Workaround to avoid round problems for some special cases (not very nice)
+ if (localY != getContentsY()) {
+ localY = Math.round(localY * fView.getZoomValue());
+ y = fView.contentsToViewY(localY);
+ }
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ int x = fView.contentsToViewX(localX);
+ if (tx.y > localHeight) {
+ return;
+ }
+
+ // Adjust height and y
+ if (y < -fVisibleScreenBounds) {
+ localHeight = localHeight + y + fVisibleScreenBounds;
+ y = -fVisibleScreenBounds;
+ }
+ if ((localHeight < -fVisibleScreenBounds) && (y + localHeight < -fVisibleScreenBounds)) {
+ localHeight = -fVisibleScreenBounds;
+ } else if (localHeight + y > fView.getVisibleHeight() + fVisibleScreenBounds) {
+ localHeight = fView.getVisibleHeight() + fVisibleScreenBounds - y;
+ }
+
+ if (tx.x <= localWidth) {
+ localDrawText(name, x + 1 + (localWidth - tx.x) / 2, y + 1 + (localHeight - tx.y) / 2, trans);
+ } else {
+ String nameToDisplay = name;
+ for (int i = name.length() - 1; i >= 0 && fContext.textExtent(nameToDisplay).x >= localWidth; i--) {
+ nameToDisplay = name.substring(0, i);
+ }
+ int dotCount = 0;
+ for (int i = 1; i <= 3 && nameToDisplay.length() - i > 0; i++) {
+ dotCount++;
+ }
+ nameToDisplay = nameToDisplay.substring(0, nameToDisplay.length() - dotCount);
+ StringBuffer buf = new StringBuffer(nameToDisplay);
+ for (int i = 0; i < dotCount; i++) {
+ buf.append("."); //$NON-NLS-1$
+ }
+ nameToDisplay = buf.toString();
+ localDrawText(nameToDisplay, x + 1 + (localWidth - fContext.textExtent(nameToDisplay).x) / 2, y + 1 + (localHeight - fContext.textExtent(nameToDisplay).y) / 2, trans);
+ }
+ }
+
+ @Override
+ public void drawTextTruncated(String name, int xValue, int yValue, int width, int height, boolean trans) {
+ int localX = xValue;
+ int localY = yValue;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ int x = fView.contentsToViewX(localX);
+ int y = fView.contentsToViewY(localY);
+ if (fContext.textExtent(name).x <= localWidth) {
+ localDrawText(name, x + 1, y + 1 + localHeight, trans);
+ } else {
+ String nameToDisplay = name;
+ for (int i = name.length() - 1; i >= 0 && fContext.textExtent(nameToDisplay).x >= localWidth; i--) {
+ nameToDisplay = name.substring(0, i);
+ }
+ int dotCount = 0;
+ for (int i = 1; i <= 3 && nameToDisplay.length() - i > 0; i++) {
+ dotCount++;
+ }
+ nameToDisplay = nameToDisplay.substring(0, nameToDisplay.length() - dotCount);
+
+ StringBuffer buf = new StringBuffer(nameToDisplay);
+
+ for (int i = 0; i < dotCount; i++) {
+ buf.append("."); //$NON-NLS-1$
+ }
+ nameToDisplay = buf.toString();
+ localDrawText(nameToDisplay, x + 1, y + 1 + localHeight, trans);
+ }
+ }
+
+ @Override
+ public void drawImage(IImage image, int xValue, int yValue, int maxWith, int maxHeight) {
+ int localX = xValue;
+ int localY = yValue;
+
+ Image img = null;
+ if (image != null && image.getImage() instanceof Image) {
+ img = (Image) image.getImage();
+ } else {
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ int x = fView.contentsToViewX(localX);
+ int y = fView.contentsToViewY(localY);
+ float tempZoom = fView.getZoomValue();
+ int width = Math.round(maxWith * tempZoom);
+ int height = Math.round(maxHeight * tempZoom);
+ fContext.setBackground(fView.getDisplay().getSystemColor(SWT.COLOR_RED));
+ fContext.fillRectangle(x, y, width, height);
+ return;
+ }
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ int x = fView.contentsToViewX(localX);
+ int y = fView.contentsToViewY(localY);
+ Rectangle b = ((Image) image.getImage()).getBounds();
+ int width = b.width;
+ int height = b.height;
+ if (width > maxWith) {
+ width = maxWith;
+ }
+ if (height > maxHeight) {
+ height = maxHeight;
+ }
+ float tempZoom = fView.getZoomValue();
+ width = Math.round(width * tempZoom);
+ height = Math.round(height * tempZoom);
+
+ if (fView.isPrinting() && width > 0 && height > 0) {
+ Image dbuffer = new Image(fView.getDisplay(), width, height);
+ GC tempgc = new GC(dbuffer);
+ tempgc.drawImage(img, 0, 0, b.width, b.height, 0, 0, width, height);
+ Image dbuffer2 = new Image(fView.getDisplay(), dbuffer.getImageData());
+ fContext.drawImage(dbuffer2, x, y);
+ tempgc.dispose();
+ dbuffer.dispose();
+ dbuffer2.dispose();
+ } else {
+ fContext.drawImage(img, 0, 0, b.width, b.height, x, y, width, height);
+ }
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int startAngle, int endAngle) {
+ int localX = x;
+ int localY = y;
+ int localWidth = width;
+ int localHeight = height;
+
+ localX = Math.round(localX * fView.getZoomValue());
+ localY = Math.round(localY * fView.getZoomValue());
+ localWidth = Math.round(localWidth * fView.getZoomValue());
+ localHeight = Math.round(localHeight * fView.getZoomValue());
+ if (localWidth == 0 || localHeight == 0 || endAngle == 0) {
+ return;
+ }
+ fContext.drawArc(fView.contentsToViewX(localX), fView.contentsToViewY(localY), localWidth, localHeight, startAngle, endAngle);
+ }
+
+ @Override
+ public void setFont(IFont font) {
+ if (font.getFont() != null && ((Font) font.getFont()).getFontData().length > 0) {
+ FontData fontData = ((Font) font.getFont()).getFontData()[0];
+ if (SDViewPref.getInstance().fontLinked() || fView.isPrinting()) {
+ int h = Math.round(fontData.getHeight() * fView.getZoomValue());
+ if (h > 0) {
+ fontData.setHeight(h);
+ }
+ }
+ if (fTempFont != null) {
+ fTempFont.dispose();
+ }
+ fTempFont = new Font(Display.getCurrent(), fontData);
+ fContext.setFont(fTempFont);
+ }
+ }
+
+ @Override
+ public int getFontHeight(IFont font) {
+ if (font.getFont() != null && (font.getFont() instanceof Font) && ((Font) font.getFont()).getFontData().length > 0) {
+ Font toRestore = fContext.getFont();
+ fContext.setFont((Font) font.getFont());
+ int height = fContext.textExtent("lp").y;//$NON-NLS-1$
+ fContext.setFont(toRestore);
+ return height;
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the current font height.
+ *
+ * @return the current font height.
+ */
+ protected int getCurrentFontHeight() {
+ return fContext.textExtent("lp").y; //$NON-NLS-1$
+ }
+
+ @Override
+ public int getFontWidth(IFont font) {
+ if ((font.getFont() != null) && (font.getFont() instanceof Font)) {
+ Font toRestore = fContext.getFont();
+ fContext.setFont((Font) font.getFont());
+ int width = fContext.getFontMetrics().getAverageCharWidth();
+ fContext.setFont(toRestore);
+ return width;
+ }
+ return 0;
+ }
+
+ /**
+ * Disposes all created resources.
+ */
+ public void dispose() {
+ if (fTempFont != null) {
+ fTempFont.dispose();
+ }
+ fTempFont = null;
+ if (fContext != null) {
+ fContext.dispose();
+ }
+ fContext = null;
+ }
+
+ @Override
+ public float getZoom() {
+ if (fView != null) {
+ return fView.getZoomValue();
+ }
+ return 1;
+ }
+
+ @Override
+ public int getLineDotStyle() {
+ return SWT.LINE_DOT;
+ }
+
+ @Override
+ public int getLineDashStyle() {
+ return SWT.LINE_DASH;
+ }
+
+ @Override
+ public int getLineSolidStyle() {
+ return SWT.LINE_SOLID;
+ }
+
+ @Override
+ public IColor createColor(int r, int g, int b) {
+ return new ColorImpl(Display.getDefault(), r, g, b);
+ }
+
+ @Override
+ public void setDrawTextWithFocusStyle(boolean focus) {
+ fDrawWithFocus = focus;
+ }
+
+ /**
+ * Returns the screen bounds.
+ *
+ * @return the screen bounds.
+ */
+ protected static int getVscreenBounds() {
+ return fVisibleScreenBounds;
+ }
+
+ /**
+ * Sets the visible screen bounds.
+ *
+ * @param vBounds the screen bounds.
+ */
+ protected static void setVscreenBounds(int vBounds) {
+ fVisibleScreenBounds = vBounds;
+ }
+
+ /**
+ * Returns the graphical context.
+ *
+ * @return the graphical context
+ * @since 2.0
+ */
+ protected GC getGc() {
+ return fContext;
+ }
+
+ /**
+ * Returns the SD widget.
+ *
+ * @return the SD widget
+ * @since 2.0
+ */
+ protected SDWidget getSDWidget() {
+ return fView;
+ }
+
+ /**
+ * Returns the gradient color.
+ *
+ * @return the gradient color
+ * @since 2.0
+ */
+ protected IColor setGradientColor() {
+ return fGradientColor;
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Validates the polygon height
+ *
+ * @param localPoint array of points
+ * @return height
+ */
+ private int validatePolygonHeight(int[] localPoint) {
+ int i = 1;
+ int max = 0;
+ int min = Integer.MAX_VALUE;
+ while (i < localPoint.length) {
+ max = Math.abs(localPoint[i]) > Math.abs(max) ? localPoint[i] : max;
+ min = Math.abs(localPoint[i]) < Math.abs(min) ? localPoint[i] : min;
+ i+=2;
+ }
+ int height = max - min;
+ if (min < -fVisibleScreenBounds) {
+ height = height + min + fVisibleScreenBounds;
+ min = -fVisibleScreenBounds;
+ }
+ if ((height < -fVisibleScreenBounds) && (min + height < -fVisibleScreenBounds)) {
+ height = -fVisibleScreenBounds;
+ } else if (height + min > fView.getVisibleHeight() + fVisibleScreenBounds) {
+ height = fView.getVisibleHeight() + fVisibleScreenBounds - min;
+ }
+ return height;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDView.java
new file mode 100644
index 0000000000..8bfed0365e
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDView.java
@@ -0,0 +1,1181 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.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.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BaseMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Frame;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessageReturn;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.ConfigureMinMax;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.FirstPage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.KeyBindingsManager;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.LastPage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.MoveToMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.NextPage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.OpenSDFiltersDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.OpenSDFindDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.OpenSDPagesDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.PrevPage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.Print;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.ShowNodeEnd;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.ShowNodeStart;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.Zoom;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.Zoom.ZoomType;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.IExtendedFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.IExtendedFindProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDAdvancedPagingProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDCollapseProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDExtendedActionBarProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFindProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDGraphNodeSupporter;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDPagingProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDPropertiesProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.load.IUml2SDLoader;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.load.LoadersManager;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionFactory;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.views.properties.IPropertySheetPage;
+
+/**
+ * <p>
+ * This class is a generic sequence diagram view implementation.
+ * </p>
+
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDView extends ViewPart {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Name of menu separator for view modes
+ * @since 2.0
+ */
+ public static final String UML2SD_VIEW_MODES_SEPARATOR = "UML2SD_VIEW_MODES"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for working set
+ * @since 2.0
+ */
+ public static final String UML2SD_WORKING_SET_SEPARATOR = "UML2SD_WORKING_SET"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for sorting
+ * @since 2.0
+ */
+ public static final String UML2SD_SORTING_SEPARATOR = "UML2SD_SORTING"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for filtering
+ * @since 2.0
+ */
+ public static final String UML2SD_FILTERING_SEPARATOR = "UML2SD_FILTERING"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for view layout
+ * @since 2.0
+ */
+ public static final String UML2SD_VIEW_LAYOUT_SEPARATOR = "UML2SD_VIEW_LAYOUT"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for link editor
+ * @since 2.0
+ */
+ public static final String UML2SD_LINK_EDITOR_SEPARATOR = "UML2SD_LINK_EDITOR"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for other commands
+ * @since 2.0
+ */
+ public static final String UML2SD_OTHER_COMMANDS_SEPARATOR = "UML2SD_OTHER_COMMANDS"; //$NON-NLS-1$
+ /**
+ * Name of menu separator for other plug-in commands
+ * @since 2.0
+ */
+ public static final String UML2SD_OTHER_PLUGINS_COMMANDS_SEPARATOR = "UML2SD_OTHER_PLUGINS_COMMANDS"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The sequence diagram widget.
+ */
+ private SDWidget fSdWidget = null;
+ /**
+ * The time compression bar.
+ */
+ private TimeCompressionBar fTimeCompressionBar = null;
+ /**
+ * The sequence diagram find provider implementation.
+ */
+ private ISDFindProvider fSdFindProvider = null;
+ /**
+ * The sequence diagram paging provider implementation.
+ */
+ private ISDPagingProvider fSdPagingProvider = null;
+ /**
+ * The sequence diagram filter provider implementation.
+ */
+ private ISDFilterProvider fSdFilterProvider = null;
+ /**
+ * The extended sequence diagram filter provider implementation.
+ */
+ private IExtendedFilterProvider fSdExFilterProvider = null;
+ /**
+ * The extended sequence diagram find provider implementation.
+ */
+ private IExtendedFindProvider fSdExFindProvider = null;
+ /**
+ * The extended sequence diagram action bar provider implementation.
+ */
+ private ISDExtendedActionBarProvider fSdExtendedActionBarProvider = null;
+ /**
+ * The sequence diagram property provider implementation.
+ */
+ private ISDPropertiesProvider fSdPropertiesProvider = null;
+ /**
+ * Button for executing the next page action.
+ */
+ private NextPage fNextPageButton = null;
+ /**
+ * Button for executing the previous page action.
+ */
+ private PrevPage fPrevPageButton = null;
+ /**
+ * Button for executing the first page page action.
+ */
+ private FirstPage fFirstPageButton = null;
+ /**
+ * Button for executing the last page action.
+ */
+ private LastPage fLastPageButton = null;
+ /**
+ * The menu manager reference.
+ */
+ private MenuManager fMenuMgr = null;
+ /**
+ * Flag to indicate whether view needs initialization or not.
+ */
+ private boolean fNeedInit = true;
+ /**
+ * WaitCursor is the cursor to be displayed when long tasks are running
+ */
+ private Cursor fWaitCursor;
+
+ private Zoom fResetZoomAction;
+ private Zoom fNoZoomAction;
+ private Zoom fZoomInAction;
+ private Zoom fZoomOutAction;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void createPartControl(Composite c) {
+ Composite parent = new Composite(c, SWT.NONE);
+ GridLayout parentLayout = new GridLayout();
+ parentLayout.numColumns = 2;
+ parentLayout.marginWidth = 0;
+ parentLayout.marginHeight = 0;
+ parent.setLayout(parentLayout);
+
+ GridData timeLayoutdata = new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ timeLayoutdata.widthHint = 10;
+ GridData seqDiagLayoutData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ fTimeCompressionBar = new TimeCompressionBar(parent, SWT.NONE);
+ fTimeCompressionBar.setLayoutData(timeLayoutdata);
+ fSdWidget = new SDWidget(parent, SWT.NONE);
+ fSdWidget.setLayoutData(seqDiagLayoutData);
+ fSdWidget.setSite(this);
+ fSdWidget.setTimeBar(fTimeCompressionBar);
+
+ // Add this view to the key bindings manager
+ KeyBindingsManager.getInstance().add(this.getSite().getId());
+
+ createCoolbarContent();
+
+ hookContextMenu();
+
+ fTimeCompressionBar.setVisible(false);
+ parent.layout(true);
+
+ Print print = new Print(this);
+ getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.PRINT.getId(), print);
+
+ fNeedInit = restoreLoader();
+ }
+
+ /**
+ * Load a blank page that is supposed to explain that a kind of interaction must be chosen.
+ */
+ protected void loadBlank() {
+ IUml2SDLoader loader = new BlankUml2SdLoader();
+ loader.setViewer(this);
+ setContentDescription(loader.getTitleString());
+ }
+
+ @Override
+ public void setFocus() {
+ if (fSdWidget != null) {
+ // update actions for key bindings
+ KeyBindingsManager.getInstance().setSdView(this);
+ fSdWidget.setFocus();
+ }
+ if (isViewReady() && fNeedInit) {
+ fNeedInit = restoreLoader();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ KeyBindingsManager.getInstance().remove(this.getSite().getId());
+ disposeZoomActions();
+ super.dispose();
+ }
+
+ private void disposeZoomActions() {
+ if (fResetZoomAction != null) {
+ fResetZoomAction.dispose();
+ }
+ if (fNoZoomAction != null) {
+ fNoZoomAction.dispose();
+ }
+ if (fZoomInAction != null) {
+ fZoomInAction.dispose();
+ }
+ if (fZoomOutAction != null) {
+ fZoomOutAction.dispose();
+ }
+ }
+
+ /**
+ * Returns the SD widget.
+ *
+ * @return The SD widget.
+ */
+ public SDWidget getSDWidget() {
+ return fSdWidget;
+ }
+
+ /**
+ * Set the find provider for the opened sequence diagram viewer<br>
+ * If the provider is not set, the find menu item will not be available in the viewer<br>
+ * A find provider is called back when the user perform a find action<br>
+ * The find provider is responsible to move the sequence diagram to the GraphNode which match the
+ * find criteria as well as to highlight the GraphNode
+ *
+ * @param provider the search provider
+ */
+ public void setSDFindProvider(ISDFindProvider provider) {
+ fSdFindProvider = provider;
+ fSdExFindProvider = null;
+ createCoolbarContent();
+ if (provider != null) {
+ KeyBindingsManager.getInstance().setFindEnabled(true);
+ }
+ else {
+ KeyBindingsManager.getInstance().setFindEnabled(false);
+ }
+ }
+
+ /**
+ * Set the find provider for the opened sequence diagram viewer<br>
+ * If the provider is not set, the find menu item will not be available in
+ * the viewer<br>
+ * A find provider is called back when the user perform a find action<br>
+ * If the extended find provider is set, it replaces the regular find
+ * provider (sdFindProvider).<br>
+ *
+ * @param provider
+ * The provider to set
+ */
+ public void setExtendedFindProvider(IExtendedFindProvider provider) {
+ fSdExFindProvider = provider;
+ fSdFindProvider = null;
+ createCoolbarContent();
+ if (provider != null) {
+ KeyBindingsManager.getInstance().setFindEnabled(true);
+ }
+ else {
+ KeyBindingsManager.getInstance().setFindEnabled(false);
+ }
+ }
+
+ /**
+ * Returns the extended find provider
+ *
+ * @return extended find provider.
+ */
+ public IExtendedFindProvider getExtendedFindProvider() {
+ return fSdExFindProvider;
+ }
+
+ /**
+ * Resets all providers.
+ */
+ public void resetProviders() {
+ KeyBindingsManager.getInstance().setFindEnabled(false);
+ fSdFindProvider = null;
+ fSdExFindProvider = null;
+ fSdFilterProvider = null;
+ fSdExFilterProvider = null;
+ fSdPagingProvider = null;
+ fSdExtendedActionBarProvider = null;
+ fSdPropertiesProvider = null;
+ if ((fSdWidget != null) && (!fSdWidget.isDisposed())) {
+ fSdWidget.setCollapseProvider(null);
+ }
+ }
+
+ /**
+ * Set the filter provider for the opened sequence diagram viewer<br>
+ * If the provider is not set, the filter menu item will not be available in the viewer<br>
+ * A filter provider is called back when the user perform a filter action<br>
+ *
+ * @param provider the filter provider
+ */
+ public void setSDFilterProvider(ISDFilterProvider provider) {
+ fSdFilterProvider = provider;
+ // Both systems can be used now, commenting out next statement
+ createCoolbarContent();
+ }
+
+ /**
+ * Sets the extended filter provider for the opened sequence diagram viewer.
+ *
+ * @param provider
+ * The provider to set
+ */
+ public void setExtendedFilterProvider(IExtendedFilterProvider provider) {
+ fSdExFilterProvider = provider;
+ // Both systems can be used now, commenting out next statement
+ createCoolbarContent();
+ }
+
+ /**
+ * Returns the extended find provider.
+ *
+ * @return The extended find provider.
+ */
+ public IExtendedFilterProvider getExtendedFilterProvider() {
+ return fSdExFilterProvider;
+ }
+
+ /**
+ * Register the given provider to support Drag and Drop collapsing. This provider is
+ * responsible of updating the Frame.
+ *
+ * @param provider - the provider to register
+ */
+ public void setCollapsingProvider(ISDCollapseProvider provider) {
+ if ((fSdWidget != null) && (!fSdWidget.isDisposed())) {
+ fSdWidget.setCollapseProvider(provider);
+ }
+ }
+
+ /**
+ * Set the page provider for the opened sequence diagram viewer<br>
+ * If the sequence diagram provided (see setFrame) need to be split in many parts, a paging provider must be
+ * provided in order to handle page change requested by the user<br>
+ * Set a page provider will create the next and previous page buttons in the viewer coolBar
+ *
+ * @param provider the paging provider
+ */
+ public void setSDPagingProvider(ISDPagingProvider provider) {
+ fSdPagingProvider = provider;
+ createCoolbarContent();
+ }
+
+ /**
+ * Returns the current page provider for the view
+ *
+ * @return the paging provider
+ */
+ public ISDPagingProvider getSDPagingProvider() {
+ return fSdPagingProvider;
+ }
+
+ /**
+ * Returns the current find provider for the view
+ *
+ * @return the find provider
+ */
+ public ISDFindProvider getSDFindProvider() {
+ return fSdFindProvider;
+ }
+
+ /**
+ * Returns the current filter provider for the view
+ *
+ * @return the filter provider
+ */
+ public ISDFilterProvider getSDFilterProvider() {
+ return fSdFilterProvider;
+ }
+
+ /**
+ * Set the extended action bar provider for the opened sequence diagram viewer<br>
+ * This allow to add programmatically actions in the coolbar and/or in the drop-down menu
+ *
+ * @param provider the search provider
+ */
+ public void setSDExtendedActionBarProvider(ISDExtendedActionBarProvider provider) {
+ fSdExtendedActionBarProvider = provider;
+ createCoolbarContent();
+ }
+
+ /**
+ * Returns the current extended action bar provider for the view
+ *
+ * @return the extended action bar provider
+ */
+ public ISDExtendedActionBarProvider getSDExtendedActionBarProvider() {
+ return fSdExtendedActionBarProvider;
+ }
+
+ /**
+ * Set the properties view provider for the opened sequence diagram viewer
+ *
+ * @param provider the properties provider
+ */
+ public void setSDPropertiesProvider(ISDPropertiesProvider provider) {
+ fSdPropertiesProvider = provider;
+ }
+
+ /**
+ * Returns the current extended action bar provider for the view.
+ *
+ * @return the extended action bar provider
+ */
+ public ISDPropertiesProvider getSDPropertiesProvider() {
+ return fSdPropertiesProvider;
+ }
+
+ /**
+ * Sets the sdWidget.
+ *
+ * @param sdWidget
+ * A sdWidget to set
+ * @since 2.0
+ */
+ protected void setSDWidget(SDWidget sdWidget) {
+ fSdWidget = sdWidget;
+ }
+
+ /**
+ * Sets the time compression bar.
+ *
+ * @param timeCompressionbar
+ * A sdWidget to set
+ * @since 2.0
+ */
+ protected void setTimeBar(TimeCompressionBar timeCompressionbar) {
+ fTimeCompressionBar = timeCompressionbar;
+ }
+
+ /**
+ * Sets the initialization flag.
+ *
+ * @param needInit
+ * flag value to set
+ * @since 2.0
+ */
+ protected void setNeedInit(boolean needInit) {
+ fNeedInit = needInit;
+ }
+
+ /**
+ * Creates the basic sequence diagram menu
+ */
+ protected void hookContextMenu() {
+ fMenuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
+ fMenuMgr.setRemoveAllWhenShown(true);
+ fMenuMgr.addMenuListener(new IMenuListener() {
+ @Override
+ public void menuAboutToShow(IMenuManager manager) {
+ fillContextMenu(manager);
+ }
+ });
+ Menu menu = fMenuMgr.createContextMenu(fSdWidget.getViewControl());
+ fSdWidget.getViewControl().setMenu(menu);
+ getSite().registerContextMenu(fMenuMgr, fSdWidget.getSelectionProvider());
+ }
+
+ /**
+ * Returns the context menu manager
+ *
+ * @return the menu manager
+ */
+ public MenuManager getMenuManager() {
+ return fMenuMgr;
+ }
+
+ /**
+ * Fills the basic sequence diagram menu and define the dynamic menu item insertion point
+ *
+ * @param manager the menu manager
+ */
+ protected void fillContextMenu(IMenuManager manager) {
+ manager.add(new Separator("Additions")); //$NON-NLS-1$
+ if (getSDWidget() != null && getSDWidget().getCurrentGraphNode() != null) {
+ ISelectionProvider selProvider = fSdWidget.getSelectionProvider();
+ ISelection sel = selProvider.getSelection();
+ int nbMessage = 0;
+ Iterator<?> it = ((StructuredSelection) sel).iterator();
+ while (it.hasNext()) {
+ Object node = it.next();
+ if (node instanceof BaseMessage) {
+ nbMessage++;
+ }
+ }
+ if (nbMessage != 1) {
+ return;
+ }
+ GraphNode node = getSDWidget().getCurrentGraphNode();
+ if ((node instanceof SyncMessageReturn) && (((SyncMessageReturn) node).getMessage() != null)) {
+ Action goToMessage = new MoveToMessage(this);
+ goToMessage.setText(Messages.SequenceDiagram_GoToMessage);
+ manager.add(goToMessage);
+ }
+ if ((node instanceof SyncMessage) && (((SyncMessage) node).getMessageReturn() != null)) {
+ Action goToMessage = new MoveToMessage(this);
+ goToMessage.setText(Messages.SequenceDiagram_GoToMessageReturn);
+ manager.add(goToMessage);
+ }
+ }
+ manager.add(new Separator("MultiSelectAdditions")); //$NON-NLS-1$
+ }
+
+ /**
+ * Enables/Disables an action with given name.
+ *
+ * @param actionName The action name
+ * @param state true or false
+ */
+ public void setEnableAction(String actionName, boolean state) {
+ IActionBars bar = getViewSite().getActionBars();
+ if (bar != null) {
+ IContributionItem item = bar.getMenuManager().find(actionName);
+ if ((item != null) && (item instanceof ActionContributionItem)) {
+ IAction action = ((ActionContributionItem) item).getAction();
+ if (action != null) {
+ action.setEnabled(state);
+ }
+ item.setVisible(state);
+ bar.updateActionBars();
+ }
+ }
+ }
+
+ /**
+ * Creates the coolBar icon depending on the actions supported by the Sequence Diagram provider<br>
+ * - Navigation buttons are displayed if ISDPovider.HasPaging return true<br>
+ * - Navigation buttons are enabled depending on the value return by ISDPovider.HasNext and HasPrev<br>
+ *
+ * @see ISDGraphNodeSupporter Action support definition
+ * @see SDView#setSDFilterProvider(ISDFilterProvider)
+ * @see SDView#setSDFindProvider(ISDFindProvider)
+ * @see SDView#setSDPagingProvider(ISDPagingProvider)
+ */
+ protected void createCoolbarContent() {
+ IActionBars bar = getViewSite().getActionBars();
+
+ bar.getMenuManager().removeAll();
+ bar.getToolBarManager().removeAll();
+ disposeZoomActions();
+
+ createMenuGroup();
+
+ fResetZoomAction = new Zoom(this, ZoomType.ZOOM_RESET);
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fResetZoomAction);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fResetZoomAction);
+
+ fNoZoomAction = new Zoom(this, ZoomType.ZOOM_NONE);
+ fNoZoomAction.setChecked(true);
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fNoZoomAction);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fNoZoomAction);
+
+ fZoomInAction = new Zoom(this, ZoomType.ZOOM_IN);
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fZoomInAction);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fZoomInAction);
+
+ fZoomOutAction = new Zoom(this, ZoomType.ZOOM_OUT);
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fZoomOutAction);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fZoomOutAction);
+
+ MenuManager navigation = new MenuManager(Messages.SequenceDiagram_Navigation);
+
+ ShowNodeStart showNodeStart = new ShowNodeStart(this);
+ showNodeStart.setText(Messages.SequenceDiagram_ShowNodeStart);
+
+ showNodeStart.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeStart");//$NON-NLS-1$
+ showNodeStart.setActionDefinitionId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeStart");//$NON-NLS-1$
+ navigation.add(showNodeStart);
+
+ ShowNodeEnd showNodeEnd = new ShowNodeEnd(this);
+ showNodeEnd.setText(Messages.SequenceDiagram_ShowNodeEnd);
+
+ showNodeEnd.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeEnd");//$NON-NLS-1$
+ showNodeEnd.setActionDefinitionId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeEnd");//$NON-NLS-1$
+ navigation.add(showNodeEnd);
+
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, navigation);
+
+ ConfigureMinMax minMax = new ConfigureMinMax(this);
+ minMax.setText(Messages.SequenceDiagram_ConfigureMinMax);
+ minMax.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ConfigureMinMax");//$NON-NLS-1$
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, minMax);
+
+ if ((fSdWidget.getFrame() != null) && (fSdWidget.getFrame().hasTimeInfo())) {
+ minMax.setEnabled(true);
+ } else {
+ minMax.setEnabled(false);
+ }
+
+ // Do we need to display a paging item
+ if (fSdPagingProvider != null) {
+ fNextPageButton = new NextPage(this);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fNextPageButton);
+ fNextPageButton.setEnabled(fSdPagingProvider.hasNextPage());
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fNextPageButton);
+
+ fPrevPageButton = new PrevPage(this);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fPrevPageButton);
+ fPrevPageButton.setEnabled(fSdPagingProvider.hasPrevPage());
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fPrevPageButton);
+
+ fFirstPageButton = new FirstPage(this);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fFirstPageButton);
+ fFirstPageButton.setEnabled(fSdPagingProvider.hasPrevPage());
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fFirstPageButton);
+
+ fLastPageButton = new LastPage(this);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fLastPageButton);
+ fLastPageButton.setEnabled(fSdPagingProvider.hasNextPage());
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, fLastPageButton);
+ }
+
+ if (fSdExFilterProvider != null) {
+ Action action = fSdExFilterProvider.getFilterAction();
+ if (action != null) {
+ if (action.getId() == null)
+ {
+ action.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.extendedFilter"); //$NON-NLS-1$
+ }
+ if (action.getImageDescriptor() == null) {
+ action.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
+ }
+ if (action.getText() == null || action.getText().length() == 0) {
+ action.setText(Messages.SequenceDiagram_EditFilters);
+ }
+ bar.getMenuManager().prependToGroup(UML2SD_FILTERING_SEPARATOR, action);
+ bar.getToolBarManager().prependToGroup(UML2SD_FILTERING_SEPARATOR, action);
+ }
+ }
+ // Both systems can be used now: commenting out else keyword
+ if (fSdFilterProvider != null) {
+ bar.getMenuManager().appendToGroup(UML2SD_FILTERING_SEPARATOR, new OpenSDFiltersDialog(this, fSdFilterProvider));
+ }
+ if (fSdPagingProvider instanceof ISDAdvancedPagingProvider) {
+ IContributionItem sdPaging = bar.getMenuManager().find(OpenSDPagesDialog.ID);
+ if (sdPaging != null) {
+ bar.getMenuManager().remove(sdPaging);
+ sdPaging = null;
+ }
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, new OpenSDPagesDialog(this, (ISDAdvancedPagingProvider) fSdPagingProvider));
+ updatePagesMenuItem(bar);
+ }
+
+ if (fSdExFindProvider != null) {
+ Action action = fSdExFindProvider.getFindAction();
+ if (action != null) {
+ if (action.getId() == null) {
+ action.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.extendedFind"); //$NON-NLS-1$
+ }
+ if (action.getImageDescriptor() == null) {
+ action.setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SEARCH_SEQ));
+ }
+ if (action.getText() == null) {
+ action.setText(Messages.SequenceDiagram_Find + "..."); //$NON-NLS-1$
+ }
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, action);
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, action);
+ }
+ } else if (fSdFindProvider != null) {
+ bar.getMenuManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, new OpenSDFindDialog(this));
+ bar.getToolBarManager().appendToGroup(UML2SD_OTHER_COMMANDS_SEPARATOR, new OpenSDFindDialog(this));
+ }
+
+ if (fSdExtendedActionBarProvider != null) {
+ fSdExtendedActionBarProvider.supplementCoolbarContent(bar);
+ }
+
+ bar.updateActionBars();
+ }
+
+ /**
+ * Updates the view coolbar buttons state according to the value return by: -
+ * ISDExtendedActionBarProvider.hasNextPage()<br>
+ * - ISDExtendedActionBarProvider.hasPrevPage()<br>
+ *
+ */
+ public void updateCoolBar() {
+ if (fSdPagingProvider != null) {
+ IActionBars bar = getViewSite().getActionBars();
+ if (bar == null) {
+ return;
+ }
+ IToolBarManager barManager = bar.getToolBarManager();
+ if (barManager == null) {
+ return;
+ }
+ IContributionItem nextPage = barManager.find(NextPage.ID);
+ if (nextPage instanceof ActionContributionItem) {
+ IAction nextPageAction = ((ActionContributionItem) nextPage).getAction();
+ if (nextPageAction instanceof NextPage) {
+ ((NextPage) nextPageAction).setEnabled(fSdPagingProvider.hasNextPage());
+ }
+ }
+
+ IContributionItem prevPage = barManager.find(PrevPage.ID);
+ if (prevPage instanceof ActionContributionItem) {
+ IAction prevPageAction = ((ActionContributionItem) prevPage).getAction();
+ if (prevPageAction instanceof PrevPage) {
+ ((PrevPage) prevPageAction).setEnabled(fSdPagingProvider.hasPrevPage());
+ }
+ }
+
+ IContributionItem firstPage = barManager.find(FirstPage.ID);
+ if (firstPage instanceof ActionContributionItem) {
+ IAction firstPageAction = ((ActionContributionItem) firstPage).getAction();
+ if (firstPageAction instanceof FirstPage) {
+ ((FirstPage) firstPageAction).setEnabled(fSdPagingProvider.hasPrevPage());
+ }
+ }
+
+ IContributionItem lastPage = barManager.find(LastPage.ID);
+ if (lastPage instanceof ActionContributionItem) {
+ IAction lastPageAction = ((ActionContributionItem) lastPage).getAction();
+ if (lastPageAction instanceof LastPage) {
+ ((LastPage) lastPageAction).setEnabled(fSdPagingProvider.hasNextPage());
+ }
+ }
+
+ updatePagesMenuItem(bar);
+ }
+ }
+
+ /**
+ * Enables or disables the Pages... menu item, depending on the number of pages
+ *
+ * @param bar the bar containing the action
+ */
+ protected void updatePagesMenuItem(IActionBars bar) {
+ if (fSdPagingProvider instanceof ISDAdvancedPagingProvider) {
+ IMenuManager menuManager = bar.getMenuManager();
+ ActionContributionItem contributionItem = (ActionContributionItem) menuManager.find(OpenSDPagesDialog.ID);
+ IAction openSDPagesDialog = null;
+ if (contributionItem != null) {
+ openSDPagesDialog = contributionItem.getAction();
+ }
+
+ if (openSDPagesDialog instanceof OpenSDPagesDialog) {
+ openSDPagesDialog.setEnabled(((ISDAdvancedPagingProvider) fSdPagingProvider).pagesCount() > 1);
+ }
+ }
+ }
+
+ /**
+ * The frame to render (the sequence diagram)
+ *
+ * @param frame the frame to display
+ */
+ public void setFrame(Frame frame) {
+ setFrame(frame, true);
+ }
+
+ /**
+ * The frame to render (the sequence diagram)
+ *
+ * @param frame the frame to display
+ * @param resetPosition boolean Flag whether to reset the position or not.
+ */
+ protected void setFrame(Frame frame, boolean resetPosition) {
+ if (getSDWidget() == null) {
+ return;
+ }
+
+ if (frame == null) {
+ loadBlank();
+ return;
+ }
+
+ IUml2SDLoader loader = LoadersManager.getInstance().getCurrentLoader(getViewSite().getId(), this);
+ if (loader == null) {
+ return;
+ }
+
+ if (loader.getTitleString() != null) {
+ setContentDescription(loader.getTitleString());
+ }
+
+ getSDWidget().setFrame(frame, resetPosition);
+
+ if (fTimeCompressionBar != null) {
+ fTimeCompressionBar.setFrame(frame);
+ }
+ updateCoolBar();
+ if (fTimeCompressionBar != null) {
+ if (!frame.hasTimeInfo()) {
+ Composite parent = fTimeCompressionBar.getParent();
+ fTimeCompressionBar.setVisible(false);
+ parent.layout(true);
+ } else {
+ Composite parent = fTimeCompressionBar.getParent();
+ fTimeCompressionBar.setVisible(true);
+ parent.layout(true);
+ }
+ }
+ IContributionItem shortKeysMenu = getViewSite().getActionBars().getMenuManager().find("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers");//$NON-NLS-1$
+ MenuManager shortKeys = (MenuManager) shortKeysMenu;
+ if (shortKeys != null) {
+ IContributionItem[] items = shortKeys.getItems();
+ for (int i = 0; i < items.length; i++) {
+ if (items[i] instanceof ActionContributionItem) {
+ IAction action = ((ActionContributionItem) items[i]).getAction();
+ if (action != null) {
+ action.setEnabled(true);
+ }
+ }
+ }
+ }
+ createCoolbarContent();
+ }
+
+ /**
+ * Activate or deactivate the short key command given in parameter (see plugin.xml)
+ *
+ * @param id the command id defined in the plugin.xml
+ * @param value the state value
+ */
+ public void setEnableCommand(String id, boolean value) {
+ IContributionItem shortKeysMenu = getViewSite().getActionBars().getMenuManager().find("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers");//$NON-NLS-1$
+ MenuManager shortKeys = (MenuManager) shortKeysMenu;
+ if (shortKeys == null) {
+ return;
+ }
+ IContributionItem item = shortKeys.find(id);
+ if ((item != null) && (item instanceof ActionContributionItem)) {
+ IAction action = ((ActionContributionItem) item).getAction();
+ if (action != null) {
+ action.setEnabled(value);
+ }
+ }
+ }
+
+ /**
+ * Set the frame from an other thread than the one executing the main loop
+ *
+ * @param frame The frame to set (and display)
+ */
+ public void setFrameSync(final Frame frame) {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+ getSDWidget().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (getSDWidget() == null || getSDWidget().isDisposed() ||
+ ((fTimeCompressionBar != null) && fTimeCompressionBar.isDisposed())) {
+ return;
+ }
+ setFrame(frame);
+ }
+ });
+
+ }
+
+ /**
+ * Ensure an object is visible from an other thread than the one executing the main loop
+ *
+ * @param sm The node to make visible in view
+ */
+ public void ensureVisibleSync(final GraphNode sm) {
+ getSDWidget().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+ getSDWidget().ensureVisible(sm);
+ }
+ });
+ }
+
+ /**
+ * Set the frame and ensure an object is visible from an other thread than the one executing the main loop
+ *
+ * @param sm The node to make visible in view
+ * @param frame Frame The frame to set
+ */
+ public void setFrameAndEnsureVisibleSync(final Frame frame, final GraphNode sm) {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+ getSDWidget().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+ setFrameAndEnsureVisible(frame, sm);
+ }
+ });
+ }
+
+ /**
+ * Set the frame and ensure an object is visible
+ *
+ * @param sm The node to make visible in view
+ * @param frame Frame The frame to set
+ */
+ public void setFrameAndEnsureVisible(Frame frame, GraphNode sm) {
+ getSDWidget().clearSelection();
+ setFrame(frame, false);
+ getSDWidget().ensureVisible(sm);
+ }
+
+ /**
+ * Set the frame and ensure an object is visible from an other thread than the one executing the main loop
+ *
+ * @param frame The frame to set.
+ * @param x The x coordinate to make visible.
+ * @param y The y coordinate to make visible.
+ */
+ public void setFrameAndEnsureVisibleSync(final Frame frame, final int x, final int y) {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+
+ getSDWidget().getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ setFrameAndEnsureVisible(frame, x, y);
+ }
+ });
+ }
+
+ /**
+ * Set the frame and ensure an object is visible
+ *
+ * @param frame The frame to set.
+ * @param x The x coordinate to make visible.
+ * @param y The y coordinate to make visible.
+ */
+ public void setFrameAndEnsureVisible(Frame frame, int x, int y) {
+ getSDWidget().clearSelection();
+ setFrame(frame, false);
+ getSDWidget().ensureVisible(x, y);
+ getSDWidget().redraw();
+ }
+
+ /**
+ * Toggle between default and wait cursors from an other thread than the one executing the main loop
+ *
+ * @param wait <code>true</code> for wait cursor else <code>false</code> for default cursor.
+ */
+ public void toggleWaitCursorAsync(final boolean wait) {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+
+ getSDWidget().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (getSDWidget() == null || getSDWidget().isDisposed()) {
+ return;
+ }
+ if (wait) {
+ if (fWaitCursor != null && !fWaitCursor.isDisposed()) {
+ fWaitCursor.dispose();
+ }
+ fWaitCursor = new Cursor(getSDWidget().getDisplay(), SWT.CURSOR_WAIT);
+ getSDWidget().setCursor(fWaitCursor);
+ getSDWidget().getDisplay().update();
+ } else {
+ if (fWaitCursor != null && !fWaitCursor.isDisposed()) {
+ fWaitCursor.dispose();
+ }
+ fWaitCursor = null;
+ getSDWidget().setCursor(null);
+ getSDWidget().getDisplay().update();
+ }
+ }
+ });
+ }
+
+ /**
+ * Return the time compression bar widget
+ *
+ * @return the time compression bar
+ */
+ public TimeCompressionBar getTimeCompressionBar() {
+ return fTimeCompressionBar;
+ }
+
+ /**
+ * Returns the current Frame (the sequence diagram container)
+ *
+ * @return the current frame
+ */
+ public Frame getFrame() {
+ if (getSDWidget() != null) {
+ return getSDWidget().getFrame();
+ }
+ return null;
+ }
+
+ /**
+ * Gets the initialization flag.
+ * @return the value of the initialization flag.
+ * @since 2.0
+ */
+ protected boolean isNeedInit() {
+ return fNeedInit;
+ }
+
+ /**
+ * Restores the loader for the view based on the view ID.
+ *
+ * @return boolean <code>true</code> if initialization is needed else <code>false</code>.
+ */
+ protected boolean restoreLoader() {
+ String id = getViewSite().getId();
+ if (id == null) {
+ return true;
+ }
+ IUml2SDLoader loader = LoadersManager.getInstance().getCurrentLoader(id, this);
+ if ((loader != null)) {
+ loader.setViewer(this);
+ return false;
+ }
+ loadBlank();
+ return true;
+ }
+
+ /**
+ * Checks if current view is ready to be used.
+ *
+ * @return boolean <code>true</code> if view is ready else <code>false</code>.
+ */
+ protected boolean isViewReady() {
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ if (page == null) {
+ return false;
+ }
+
+ IViewReference[] ref = page.getViewReferences();
+ for (int i = 0; i < ref.length; i++) {
+ if (ref[i].getView(false) == this) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates the menu group.
+ */
+ protected void createMenuGroup() {
+ IActionBars bar = getViewSite().getActionBars();
+ if (bar == null) {
+ return;
+ }
+ bar.getToolBarManager().add(new Separator(UML2SD_VIEW_MODES_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_WORKING_SET_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_SORTING_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_FILTERING_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_VIEW_LAYOUT_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_LINK_EDITOR_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_OTHER_COMMANDS_SEPARATOR));
+ bar.getToolBarManager().add(new Separator(UML2SD_OTHER_PLUGINS_COMMANDS_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_VIEW_MODES_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_WORKING_SET_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_SORTING_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_FILTERING_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_VIEW_LAYOUT_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_LINK_EDITOR_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_OTHER_COMMANDS_SEPARATOR));
+ bar.getMenuManager().add(new Separator(UML2SD_OTHER_PLUGINS_COMMANDS_SEPARATOR));
+ }
+
+ @Override
+ public Object getAdapter(Class adapter) {
+ Object obj = super.getAdapter(adapter);
+ if (fSdPropertiesProvider != null && adapter.equals(IPropertySheetPage.class)) {
+ return fSdPropertiesProvider.getPropertySheetEntry();
+ }
+
+ return obj;
+ }
+
+ /**
+ * Loader for a blank sequence diagram.
+ *
+ * @version 1.0
+ */
+ public static class BlankUml2SdLoader implements IUml2SDLoader {
+ @Override
+ public void setViewer(SDView viewer) {
+ // Nothing to do
+ Frame f = new Frame();
+ f.setName(""); //$NON-NLS-1$
+ viewer.setFrame(f);
+ }
+
+ @Override
+ public String getTitleString() {
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public void dispose() {
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidget.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidget.java
new file mode 100755
index 0000000000..089ebc0e49
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidget.java
@@ -0,0 +1,2066 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.jface.contexts.IContextIds;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.ACC;
+import org.eclipse.swt.accessibility.Accessible;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleControlAdapter;
+import org.eclipse.swt.accessibility.AccessibleControlEvent;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.printing.Printer;
+import org.eclipse.swt.printing.PrinterData;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Caret;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.MenuItem;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BaseMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BasicExecutionOccurrence;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Frame;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.ITimeRange;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Metrics;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.SDPrintDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.SDPrintDialogUI;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDCollapseProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.load.LoadersManager;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.contexts.IContextService;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * <p>
+ * This class implements sequence diagram widget used in the sequence diagram view.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDWidget extends ScrollView implements SelectionListener,
+ IPropertyChangeListener, DisposeListener, ITimeCompressionListener {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The frame to display in the sequence diagram widget.
+ */
+ private Frame fFrame;
+ /**
+ * The overview image to display.
+ */
+ private Image fOverView = null;
+ /**
+ * The zoom in menu item.
+ */
+ private MenuItem fZoomIn = null;
+ /**
+ * The zoom out menu item.
+ */
+ private MenuItem fZoomOut = null;
+ /**
+ * The sequence diagram selection provider.
+ */
+ private SDWidgetSelectionProvider fSelProvider = null;
+ /**
+ * The current zoom value.
+ */
+ private float fZoomValue = 1;
+ /**
+ * The current zoomInMode (true for zoom in).
+ */
+ private boolean fZoomInMode = false;
+ /**
+ * The current zoomOutMode (true for zoom out).
+ */
+ private boolean fZoomOutMode = false;
+ /**
+ * The current list of selected graph nodes.
+ */
+ private List<GraphNode> fSelectedNodeList = null;
+ /**
+ * Flag whether ctrl button is selected or not.
+ */
+ private boolean fCtrlSelection = false;
+ /**
+ * A reference to the view site.
+ */
+ private ViewPart fSite = null;
+ /**
+ * The current graph node (the last selected one).
+ */
+ private GraphNode fCurrentGraphNode = null;
+ /**
+ * The first graph node in list (multiple selection).
+ */
+ private GraphNode fListStart = null;
+ /**
+ * The previous graph node (multiple selection).
+ */
+ private List<GraphNode> fPrevList = null;
+ /**
+ * The time compression bar.
+ */
+ private TimeCompressionBar fTimeBar = null;
+ /**
+ * The current diagram tool tip.
+ */
+ private DiagramToolTip fToolTip = null;
+ /**
+ * The accessible object reference of view control.
+ */
+ private Accessible fAccessible = null;
+ /**
+ * The current node for the tooltip to display.
+ */
+ private GraphNode fToolTipNode;
+ /**
+ * The life line to drag and drop.
+ */
+ private Lifeline fDragAndDrop = null;
+ /**
+ * The number of focused widgets.
+ */
+ private int fFocusedWidget = -1;
+ /**
+ * The printer zoom.
+ */
+ private float fPrinterZoom = 0;
+ /**
+ * Y coordinate for printer.
+ */
+ private int fPrinterY = 0;
+ /**
+ * X coordinate for printer.
+ */
+ private int fPrinterX = 0;
+ /**
+ * Flag whether drag and drop is enabled or not.
+ */
+ private boolean fIsDragAndDrop = false;
+ /**
+ * The x coordinate for drag.
+ */
+ private int fDragX = 0;
+ /**
+ * The y coordinate for drag.
+ */
+ private int fDragY = 0;
+ /**
+ * The reorder mode.
+ */
+ private boolean fReorderMode = false;
+ /**
+ * The collapse caret image.
+ */
+ private Image fCollapaseCaretImg = null;
+ /**
+ * The arrow up caret image.
+ */
+ private Image fArrowUpCaretImg = null;
+ /**
+ * The current caret image.
+ */
+ private Image fCurrentCaretImage = null;
+ /**
+ * A sequence diagramm collapse provider (for collapsing graph nodes)
+ */
+ private ISDCollapseProvider fCollapseProvider = null;
+ /**
+ * The insertion caret.
+ */
+ private Caret fInsertionCartet = null;
+ /**
+ * The reorder list when in reorder mode.
+ */
+ private List<Lifeline[]> fReorderList = null;
+ /**
+ * Flag to specify whether in printing mode or not.
+ */
+ private boolean fIsPrinting = false;
+ /**
+ * A printer reference.
+ */
+ private Printer fPrinter = null;
+ /**
+ * Flag whether shift was selected or not.
+ */
+ private boolean fShiftSelection = false;
+ /**
+ * The scroll tooltip.
+ */
+ private DiagramToolTip fScrollToolTip = null;
+ /**
+ * Timer for auto_scroll feature
+ */
+ private AutoScroll fLocalAutoScroll = null;
+ /**
+ * TimerTask for auto_scroll feature !=null when auto scroll is running
+ */
+ private Timer fLocalAutoScrollTimer = null;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor for SDWidget.
+ * @param c The parent composite
+ * @param s The style
+ */
+ public SDWidget(Composite c, int s) {
+ super(c, s | SWT.NO_BACKGROUND, true);
+ setOverviewEnabled(true);
+ fSelectedNodeList = new ArrayList<>();
+ fSelProvider = new SDWidgetSelectionProvider();
+ SDViewPref.getInstance().addPropertyChangeListener(this);
+ fToolTip = new DiagramToolTip(getViewControl());
+ super.addDisposeListener(this);
+
+ fScrollToolTip = new DiagramToolTip(c);
+ getVerticalBar().addListener(SWT.MouseUp, new Listener() {
+
+ @Override
+ public void handleEvent(Event event) {
+ fScrollToolTip.hideToolTip();
+ }
+
+ });
+ fAccessible = getViewControl().getAccessible();
+
+ fAccessible.addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ // Case toolTip
+ if (e.childID == 0) {
+ if (fToolTipNode != null) {
+ if (fToolTipNode instanceof Lifeline) {
+ Lifeline lifeline = (Lifeline) fToolTipNode;
+ e.result = lifeline.getToolTipText();
+ } else {
+ e.result = fToolTipNode.getName() + getPostfixForTooltip(true);
+ }
+ }
+ } else {
+ if (getFocusNode() != null) {
+ if (getFocusNode() instanceof Lifeline) {
+ e.result = MessageFormat.format(Messages.SequenceDiagram_LifelineNode, new Object[] { String.valueOf(getFocusNode().getName()) });
+ }
+ if (getFocusNode() instanceof BaseMessage) {
+ BaseMessage mes = (BaseMessage) getFocusNode();
+ if ((mes.getStartLifeline() != null) && (mes.getEndLifeline() != null)) {
+ e.result = MessageFormat.format(
+ Messages.SequenceDiagram_MessageNode,
+ new Object[] { String.valueOf(mes.getName()), String.valueOf(mes.getStartLifeline().getName()), Integer.valueOf(mes.getStartOccurrence()), String.valueOf(mes.getEndLifeline().getName()),
+ Integer.valueOf(mes.getEndOccurrence()) });
+ } else if ((mes.getStartLifeline() == null) && (mes.getEndLifeline() != null)) {
+ e.result = MessageFormat.format(Messages.SequenceDiagram_FoundMessageNode, new Object[] { String.valueOf(mes.getName()), String.valueOf(mes.getEndLifeline().getName()), Integer.valueOf(mes.getEndOccurrence()) });
+ } else if ((mes.getStartLifeline() != null) && (mes.getEndLifeline() == null)) {
+ e.result = MessageFormat.format(Messages.SequenceDiagram_LostMessageNode, new Object[] { String.valueOf(mes.getName()), String.valueOf(mes.getStartLifeline().getName()), Integer.valueOf(mes.getStartOccurrence()) });
+ }
+ } else if (getFocusNode() instanceof BasicExecutionOccurrence) {
+ BasicExecutionOccurrence exec = (BasicExecutionOccurrence) getFocusNode();
+ e.result = MessageFormat.format(Messages.SequenceDiagram_ExecutionOccurrenceWithParams,
+ new Object[] { String.valueOf(exec.getName()), String.valueOf(exec.getLifeline().getName()), Integer.valueOf(exec.getStartOccurrence()), Integer.valueOf(exec.getEndOccurrence()) });
+ }
+
+ }
+ }
+ }
+ });
+
+ fAccessible.addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getFocus(AccessibleControlEvent e) {
+ if (fFocusedWidget == -1) {
+ e.childID = ACC.CHILDID_SELF;
+ } else {
+ e.childID = fFocusedWidget;
+ }
+ }
+
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ switch (e.childID) {
+ case ACC.CHILDID_SELF:
+ e.detail = ACC.ROLE_CLIENT_AREA;
+ break;
+ case 0:
+ e.detail = ACC.ROLE_TOOLTIP;
+ break;
+ case 1:
+ e.detail = ACC.ROLE_LABEL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void getState(AccessibleControlEvent e) {
+ e.detail = ACC.STATE_FOCUSABLE;
+ if (e.childID == ACC.CHILDID_SELF) {
+ e.detail |= ACC.STATE_FOCUSED;
+ } else {
+ e.detail |= ACC.STATE_SELECTABLE;
+ if (e.childID == fFocusedWidget) {
+ e.detail |= ACC.STATE_FOCUSED | ACC.STATE_SELECTED | ACC.STATE_CHECKED;
+ }
+ }
+ }
+ });
+
+ fInsertionCartet = new Caret((Canvas) getViewControl(), SWT.NONE);
+ fInsertionCartet.setVisible(false);
+
+ fCollapaseCaretImg = Activator.getDefault().getImageFromPath(ITmfImageConstants.IMG_UI_ARROW_COLLAPSE_OBJ);
+ fArrowUpCaretImg = Activator.getDefault().getImageFromPath(ITmfImageConstants.IMG_UI_ARROW_UP_OBJ);
+
+ fReorderList = new ArrayList<>();
+ getViewControl().addTraverseListener(new LocalTraverseListener());
+
+ addTraverseListener(new LocalTraverseListener());
+
+ getViewControl().addFocusListener(new FocusListener() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ SDViewPref.getInstance().setNoFocusSelection(false);
+ fCtrlSelection = false;
+ fShiftSelection = false;
+ redraw();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ SDViewPref.getInstance().setNoFocusSelection(true);
+ redraw();
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Sets the time compression bar.
+ *
+ * @param bar The time compression bar to set
+ */
+ public void setTimeBar(TimeCompressionBar bar) {
+ if (bar != null) {
+ fTimeBar = bar;
+ fTimeBar.addTimeCompressionListener(this);
+ }
+ }
+
+ /**
+ * Resize the contents to insure the frame fit into the view
+ *
+ * @param frame the frame which will be drawn in the view
+ */
+ public void resizeContents(Frame frame) {
+ int width = Math.round((frame.getWidth() + 2 * Metrics.FRAME_H_MARGIN) * fZoomValue);
+ int height = Math.round((frame.getHeight() + 2 * Metrics.FRAME_V_MARGIN) * fZoomValue);
+ resizeContents(width, height);
+ }
+
+ /**
+ * The frame to render (the sequence diagram)
+ *
+ * @param theFrame the frame to display
+ * @param resetPosition boolean
+ */
+ public void setFrame(Frame theFrame, boolean resetPosition) {
+ fReorderList.clear();
+ fSelectedNodeList.clear();
+ fSelProvider.setSelection(new StructuredSelection());
+ fFrame = theFrame;
+ if (resetPosition) {
+ setContentsPos(0, 0);
+ resizeContents(fFrame);
+ redraw();
+ }
+ // prepare the old overview to be reused
+ if (fOverView != null) {
+ fOverView.dispose();
+ }
+ fOverView = null;
+ resizeContents(fFrame);
+ }
+
+ /**
+ * Returns the current Frame (the sequence diagram container)
+ *
+ * @return the frame
+ */
+ public Frame getFrame() {
+ return fFrame;
+ }
+
+ /**
+ * Returns the selection provider for the current sequence diagram
+ *
+ * @return the selection provider
+ */
+ public ISelectionProvider getSelectionProvider() {
+ return fSelProvider;
+ }
+
+ /**
+ * Returns a list of selected graph nodes.
+ *
+ * @return a list of selected graph nodes.
+ */
+ public List<GraphNode> getSelection() {
+ return fSelectedNodeList;
+ }
+
+ /**
+ * Adds a graph node to the selected nodes list.
+ *
+ * @param node A graph node
+ */
+ public void addSelection(GraphNode node) {
+ if (node == null) {
+ return;
+ }
+ fSelectedNodeList.add(node);
+ node.setSelected(true);
+ fCurrentGraphNode = node;
+ StructuredSelection selection = new StructuredSelection(fSelectedNodeList);
+ fSelProvider.setSelection(selection);
+ }
+
+ /**
+ * Adds a list of node to the selected nodes list.
+ *
+ * @param list of graph nodes
+ */
+ public void addSelection(List<GraphNode> list) {
+ for (int i = 0; i < list.size(); i++) {
+ if (!fSelectedNodeList.contains(list.get(i))) {
+ fSelectedNodeList.add(list.get(i));
+ list.get(i).setSelected(true);
+ }
+ }
+ StructuredSelection selection = new StructuredSelection(fSelectedNodeList);
+ fSelProvider.setSelection(selection);
+ }
+
+ /**
+ * Removes a node from the selected nodes list.
+ *
+ * @param node to remove
+ */
+ public void removeSelection(GraphNode node) {
+ fSelectedNodeList.remove(node);
+ node.setSelected(false);
+ node.setFocused(false);
+ StructuredSelection selection = new StructuredSelection(fSelectedNodeList);
+ fSelProvider.setSelection(selection);
+ }
+
+ /**
+ * Removes a list of graph nodes from the selected nodes list.
+ *
+ * @param list of nodes to remove.
+ */
+ public void removeSelection(List<GraphNode> list) {
+ fSelectedNodeList.removeAll(list);
+ for (int i = 0; i < list.size(); i++) {
+ list.get(i).setSelected(false);
+ list.get(i).setFocused(false);
+ }
+ StructuredSelection selection = new StructuredSelection(fSelectedNodeList);
+ fSelProvider.setSelection(selection);
+ }
+
+ /**
+ * Clear the list of GraphNodes which must be drawn selected.
+ */
+ public void clearSelection() {
+ for (int i = 0; i < fSelectedNodeList.size(); i++) {
+ fSelectedNodeList.get(i).setSelected(false);
+ fSelectedNodeList.get(i).setFocused(false);
+ }
+ fCurrentGraphNode = null;
+ fSelectedNodeList.clear();
+ fSelProvider.setSelection(new StructuredSelection());
+ }
+
+ /**
+ * Sets view part.
+ *
+ * @param viewSite The view part to set
+ */
+ public void setSite(ViewPart viewSite) {
+ fSite = viewSite;
+ fSite.getSite().setSelectionProvider(fSelProvider);
+ IContextService service = (IContextService) fSite.getSite().getWorkbenchWindow().getService(IContextService.class);
+ service.activateContext("org.eclipse.linuxtools.tmf.ui.view.uml2sd.context"); //$NON-NLS-1$
+ service.activateContext(IContextIds.CONTEXT_ID_WINDOW);
+ }
+
+ /**
+ * Returns the GraphNode overView the mouse if any
+ *
+ * @return the current graph node
+ * */
+ public GraphNode getMouseOverNode() {
+ return fCurrentGraphNode;
+ }
+
+ /**
+ * Sets the zoom in mode.
+ *
+ * @param value
+ * The mode value to set.
+ */
+ public void setZoomInMode(boolean value) {
+ if (value) {
+ setZoomOutMode(false);
+ }
+ fZoomInMode = value;
+ }
+
+ /**
+ * Sets the zoom out mode.
+ *
+ * @param value
+ * The mode value to set.
+ */
+ public void setZoomOutMode(boolean value) {
+ if (value) {
+ setZoomInMode(false);
+ }
+ fZoomOutMode = value;
+ }
+
+ /**
+ * Sets the current zoom value.
+ *
+ * @param zoomValue
+ * The current zoom value
+ * @since 2.0
+ */
+ public void setZoomValue(float zoomValue) {
+ fZoomValue = zoomValue;
+ }
+
+ /**
+ * Moves the Sequence diagram to ensure the given node is visible and draw it selected
+ *
+ * @param node the GraphNode to move to
+ */
+ public void moveTo(GraphNode node) {
+ if (node == null) {
+ return;
+ }
+ clearSelection();
+ addSelection(node);
+ ensureVisible(node);
+ }
+
+ /**
+ * Moves the Sequence diagram to ensure the given node is visible
+ *
+ * @param node the GraphNode to move to
+ */
+ public void ensureVisible(GraphNode node) {
+ if (node == null) {
+ return;
+ }
+ int x = Math.round(node.getX() * fZoomValue);
+ int y = Math.round(node.getY() * fZoomValue);
+ int width = Math.round(node.getWidth() * fZoomValue);
+ int height = Math.round(node.getHeight() * fZoomValue);
+ if ((node instanceof BaseMessage) && (height == 0)) {
+ int header = Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN * 2 + Metrics.getLifelineHeaderFontHeigth();
+ height = -Math.round((Metrics.getMessagesSpacing() + header) * fZoomValue);
+ y = y + Math.round(Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT * fZoomValue);
+ }
+ if (node instanceof BasicExecutionOccurrence) {
+ width = 1;
+ height = 1;
+ }
+ if (node instanceof Lifeline) {
+ y = getContentsY();
+ height = getVisibleHeight();
+ }
+ ensureVisible(x, y, width, height, SWT.CENTER, true);
+ redraw();
+ }
+
+ /**
+ * Returns the current zoom factor.
+ * @return the current zoom factor.
+ */
+ public float getZoomFactor() {
+ return fZoomValue;
+ }
+
+ /**
+ * Returns teh printer reference.
+ *
+ * @return the printer reference
+ */
+ public Printer getPrinter() {
+ return fPrinter;
+ }
+
+ /**
+ * Returns whether the widget is used for printing or not.
+ *
+ * @return whether the widget is used for printing or not
+ */
+ public boolean isPrinting() {
+ return fIsPrinting;
+ }
+
+ /**
+ * Returns the current graph node.
+ *
+ * @return the current graph node
+ * @since 2.0
+ */
+ public GraphNode getCurrentGraphNode() {
+ return fCurrentGraphNode;
+ }
+
+ /**
+ * Returns the current zoom value.
+ *
+ * @return the current zoom value
+ * @since 2.0
+ */
+ public float getZoomValue() {
+ return fZoomValue;
+ }
+
+ /**
+ * Gets the zoom in mode.
+ *
+ * @return the mode value to set.
+ * @since 2.0
+ */
+ public boolean getZoomInMode() {
+ return fZoomInMode;
+ }
+
+
+ /**
+ * Gets the zoom out mode.
+ *
+ * @return the mode value to set.
+ * @since 2.0
+ */
+ public boolean getZoomOutMode() {
+ return fZoomOutMode;
+ }
+
+ /**
+ * Returns if ctrl selection
+ * @return true if ctrl selection else false
+ * @since 2.0
+ */
+ public boolean isCtrlSelection() {
+ return fCtrlSelection;
+ }
+
+ /**
+ * Returns if shift selection
+ * @return true if shift Selection else false
+ * @since 2.0
+ */
+ public boolean isShiftSelection() {
+ return fCtrlSelection;
+ }
+
+ /**
+ * Gets the overview image.
+ *
+ * @param rect Rectangle to include overview.
+ * @return the overview image
+ */
+ public Image getOverview(Rectangle rect) {
+ float oldzoom = fZoomValue;
+ if ((fOverView != null) && ((rect.width != fOverView.getBounds().width) || (rect.height != fOverView.getBounds().height))) {
+ fOverView.dispose();
+ fOverView = null;
+ }
+ if (fOverView == null) {
+ int backX = getContentsX();
+ int backY = getContentsY();
+ setContentsPos(0, 0);
+ fOverView = new Image(getDisplay(), rect.width, rect.height);
+ GC gcim = new GC(fOverView);
+ NGC context = new NGC(this, gcim);
+ context.setBackground(SDViewPref.getInstance().getBackGroundColor(ISDPreferences.PREF_FRAME));
+ fFrame.draw(context);
+ setContentsPos(backX, backY);
+ gcim.dispose();
+ context.dispose();
+ }
+ fZoomValue = oldzoom;
+ return fOverView;
+ }
+
+ /**
+ * Resets the zoom factor.
+ */
+ public void resetZoomFactor() {
+ int currentX = Math.round(getContentsX() / fZoomValue);
+ int currentY = Math.round(getContentsY() / fZoomValue);
+ fZoomValue = 1;
+ if (fTimeBar != null && !fTimeBar.isDisposed()) {
+ fTimeBar.setZoom(fZoomValue);
+ }
+ redraw();
+ update();
+ setContentsPos(currentX, currentY);
+ }
+
+ /**
+ * Enable or disable the lifeline reodering using Drag and Drop
+ *
+ * @param mode - true to enable false otherwise
+ */
+ public void setReorderMode(boolean mode) {
+ fReorderMode = mode;
+ }
+
+ /**
+ * Return the lifelines reorder sequence (using Drag and Drop) if the the reorder mode is turn on. Each ArryList
+ * element is of type Lifeline[2] with Lifeline[0] inserted before Lifeline[1] in the diagram
+ *
+ * @return - the re-odered sequence
+ */
+ public List<Lifeline[]> getLifelineReoderList() {
+ return fReorderList;
+ }
+
+ /**
+ * Sets the focus on given graph node (current node).
+ *
+ * @param node
+ * The graph node to focus on.
+ */
+ public void setFocus(GraphNode node) {
+ if (node == null) {
+ return;
+ }
+ if (fCurrentGraphNode != null) {
+ fCurrentGraphNode.setFocused(false);
+ }
+ fCurrentGraphNode = node;
+ node.setFocused(true);
+ ensureVisible(node);
+ setFocus(0);
+ }
+
+ /**
+ * Returns the graph node focused on.
+ *
+ * @return the current graph node
+ */
+ public GraphNode getFocusNode() {
+ return fCurrentGraphNode;
+ }
+
+ /**
+ * Method to traverse right.
+ */
+ public void traverseRight() {
+ Object selectedNode = getFocusNode();
+ if (selectedNode == null) {
+ traverseLeft();
+ }
+ GraphNode node = null;
+ if ((selectedNode instanceof BaseMessage) && (((BaseMessage) selectedNode).getEndLifeline() != null)) {
+ node = fFrame.getCalledMessage((BaseMessage) selectedNode);
+ }
+ if (selectedNode instanceof BasicExecutionOccurrence) {
+ selectedNode = ((BasicExecutionOccurrence) selectedNode).getLifeline();
+ }
+ if ((node == null) && (selectedNode instanceof Lifeline)) {
+ for (int i = 0; i < fFrame.lifeLinesCount(); i++) {
+ if ((selectedNode == fFrame.getLifeline(i)) && (i < fFrame.lifeLinesCount() - 1)) {
+ node = fFrame.getLifeline(i + 1);
+ break;
+ }
+ }
+ }
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to traverse left.
+ */
+ public void traverseLeft() {
+ Object selectedNode = getFocusNode();
+ GraphNode node = null;
+ if ((selectedNode instanceof BaseMessage) && (((BaseMessage) selectedNode).getStartLifeline() != null)) {
+ node = fFrame.getCallerMessage((BaseMessage) selectedNode);
+ }
+ if (selectedNode instanceof BasicExecutionOccurrence) {
+ selectedNode = ((BasicExecutionOccurrence) selectedNode).getLifeline();
+ }
+ if (node == null) {
+ if ((selectedNode instanceof BaseMessage) && (((BaseMessage) selectedNode).getEndLifeline() != null)) {
+ selectedNode = ((BaseMessage) selectedNode).getEndLifeline();
+ }
+ for (int i = 0; i < fFrame.lifeLinesCount(); i++) {
+ if ((selectedNode == fFrame.getLifeline(i)) && (i > 0)) {
+ node = fFrame.getLifeline(i - 1);
+ break;
+ }
+ }
+ if ((fFrame.lifeLinesCount() > 0) && (node == null)) {
+ node = fFrame.getLifeline(0);
+ }
+ }
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to traverse up.
+ */
+ public void traverseUp() {
+ Object selectedNode = getFocusNode();
+ if (selectedNode == null) {
+ traverseLeft();
+ }
+ GraphNode node = null;
+ if (selectedNode instanceof BaseMessage) {
+ node = fFrame.getPrevLifelineMessage(((BaseMessage) selectedNode).getStartLifeline(), (BaseMessage) selectedNode);
+ } else if (selectedNode instanceof Lifeline) {
+ node = fFrame.getPrevLifelineMessage((Lifeline) selectedNode, null);
+ if (!(node instanceof Lifeline)) {
+ node = null;
+ }
+ } else if (selectedNode instanceof BasicExecutionOccurrence) {
+ node = fFrame.getPrevExecOccurrence((BasicExecutionOccurrence) selectedNode);
+ if (node == null) {
+ node = ((BasicExecutionOccurrence) selectedNode).getLifeline();
+ }
+ }
+ if ((node == null) && (selectedNode instanceof BaseMessage) && (((BaseMessage) selectedNode).getStartLifeline() != null)) {
+ node = ((BaseMessage) selectedNode).getStartLifeline();
+ }
+
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to traverse down.
+ */
+ public void traverseDown() {
+ Object selectedNode = getFocusNode();
+ if (selectedNode == null) {
+ traverseLeft();
+ }
+ GraphNode node;
+ if (selectedNode instanceof BaseMessage) {
+ node = fFrame.getNextLifelineMessage(((BaseMessage) selectedNode).getStartLifeline(), (BaseMessage) selectedNode);
+ } else if (selectedNode instanceof Lifeline) {
+ node = fFrame.getFirstExecution((Lifeline) selectedNode);
+ } else if (selectedNode instanceof BasicExecutionOccurrence) {
+ node = fFrame.getNextExecOccurrence((BasicExecutionOccurrence) selectedNode);
+ } else {
+ return;
+ }
+
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to traverse home.
+ */
+ public void traverseHome() {
+ Object selectedNode = getFocusNode();
+ if (selectedNode == null) {
+ traverseLeft();
+ }
+ GraphNode node = null;
+
+ if (selectedNode instanceof BaseMessage) {
+ if (((BaseMessage) selectedNode).getStartLifeline() != null) {
+ node = fFrame.getNextLifelineMessage(((BaseMessage) selectedNode).getStartLifeline(), null);
+ } else {
+ node = fFrame.getNextLifelineMessage(((BaseMessage) selectedNode).getEndLifeline(), null);
+ }
+ } else if (selectedNode instanceof Lifeline) {
+ node = fFrame.getNextLifelineMessage((Lifeline) selectedNode, null);
+ } else if (selectedNode instanceof BasicExecutionOccurrence) {
+ node = fFrame.getFirstExecution(((BasicExecutionOccurrence) selectedNode).getLifeline());
+ } else {
+ if (fFrame.lifeLinesCount() > 0) {
+ Lifeline lifeline = fFrame.getLifeline(0);
+ node = fFrame.getNextLifelineMessage(lifeline, null);
+ }
+ }
+
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to traverse to the end.
+ */
+ public void traverseEnd() {
+ Object selectedNode = getFocusNode();
+ if (selectedNode == null) {
+ traverseLeft();
+ }
+ GraphNode node;
+ if (selectedNode instanceof BaseMessage) {
+ node = fFrame.getPrevLifelineMessage(((BaseMessage) selectedNode).getStartLifeline(), null);
+ } else if (selectedNode instanceof Lifeline) {
+ node = fFrame.getPrevLifelineMessage((Lifeline) selectedNode, null);
+ } else if (selectedNode instanceof BasicExecutionOccurrence) {
+ node = fFrame.getLastExecOccurrence(((BasicExecutionOccurrence) selectedNode).getLifeline());
+ } else {
+ if (fFrame.lifeLinesCount() > 0) {
+ Lifeline lifeline = fFrame.getLifeline(0);
+ node = fFrame.getPrevLifelineMessage(lifeline, null);
+ } else {
+ return;
+ }
+ }
+
+ if (node != null) {
+ setFocus(node);
+ redraw();
+ }
+ }
+
+ /**
+ * Method to print UI.
+ *
+ * @param sdPrintDialog the sequence diagram printer dialog.
+ */
+ public void printUI(SDPrintDialogUI sdPrintDialog) {
+ PrinterData data = sdPrintDialog.getPrinterData();
+
+ if ((data == null) || (fFrame == null)) {
+ return;
+ }
+
+ fPrinter = new Printer(data);
+
+ String jobName = MessageFormat.format(Messages.SequenceDiagram_plus, new Object[] { String.valueOf(fSite.getContentDescription()), String.valueOf(fFrame.getName()) });
+ fPrinter.startJob(jobName);
+
+ GC gc = new GC(fPrinter);
+
+ float lastZoom = fZoomValue;
+
+ Rectangle area = getClientArea();
+ GC gcim = null;
+
+ gcim = gc;
+ NGC context = new NGC(this, gcim);
+
+ // Set the metrics to use for lifeline text and message text
+ // using the Graphical Context
+ Metrics.setLifelineFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE)));
+ Metrics.setLifelineFontWidth(context.getFontWidth(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE)));
+ Metrics.setLifelineWidth(SDViewPref.getInstance().getLifelineWidth());
+ Metrics.setFrameFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_FRAME_NAME)));
+ Metrics.setLifelineHeaderFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE_HEADER)));
+
+ int syncMessFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_SYNC_MESS));
+ int syncMessRetFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_SYNC_MESS_RET));
+ int asyncMessFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_ASYNC_MESS));
+ int asyncMessRetFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_ASYNC_MESS_RET));
+
+ int messageFontHeight = 0;
+ if (syncMessFontH > syncMessRetFontH) {
+ messageFontHeight = syncMessFontH;
+ } else {
+ messageFontHeight = syncMessRetFontH;
+ }
+ if (messageFontHeight < asyncMessFontH) {
+ messageFontHeight = asyncMessFontH;
+ }
+ if (messageFontHeight < asyncMessRetFontH) {
+ messageFontHeight = asyncMessRetFontH;
+ }
+ Metrics.setMessageFontHeight(messageFontHeight);
+ context.setFont(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE));
+
+ int width = Math.round((fFrame.getWidth() + 2 * Metrics.FRAME_H_MARGIN) * fZoomValue);
+ int height = Math.round((fFrame.getHeight() + 2 * Metrics.FRAME_V_MARGIN) * fZoomValue);
+ if (width < area.width) {
+ width = area.width;
+ }
+ if (height < area.height) {
+ height = area.height;
+ }
+ resizeContents(width, height);
+
+ context.setBackground(SDViewPref.getInstance().getBackGroundColor(ISDPreferences.PREF_FRAME));
+ context.fillRectangle(0, 0, getContentsWidth(), Metrics.FRAME_V_MARGIN);
+ context.fillRectangle(0, 0, fFrame.getX(), getContentsHeight());
+ context.fillRectangle(fFrame.getX() + fFrame.getWidth() + 1, 0, getContentsWidth() - (fFrame.getX() + fFrame.getWidth() + 1), getContentsHeight());
+ context.fillRectangle(0, fFrame.getY() + fFrame.getHeight() + 1, getContentsWidth(), getContentsHeight() - (fFrame.getY() + fFrame.getHeight() + 1));
+ gcim.setLineWidth(1);
+
+ fPrinter.startPage();
+ fZoomValue = lastZoom;
+
+ int restoreX = getContentsX();
+ int restoreY = getContentsY();
+
+ float zh = sdPrintDialog.getStepY() * sdPrintDialog.getZoomFactor();
+ float zw = sdPrintDialog.getStepX() * sdPrintDialog.getZoomFactor();
+
+ float zoomValueH = fPrinter.getClientArea().height / zh;
+ float zoomValueW = fPrinter.getClientArea().width / zw;
+ if (zoomValueH > zoomValueW) {
+ fPrinterZoom = zoomValueH;
+ } else {
+ fPrinterZoom = zoomValueW;
+ }
+
+ if (sdPrintDialog.printSelection()) {
+ int[] pagesList = sdPrintDialog.getPageList();
+
+ for (int pageIndex = 0; pageIndex < pagesList.length; pageIndex++) {
+ printPage(pagesList[pageIndex], sdPrintDialog, context);
+ }
+ } else if (sdPrintDialog.printAll()) {
+ for (int pageIndex = 1; pageIndex <= sdPrintDialog.maxNumOfPages(); pageIndex++) {
+ printPage(pageIndex, sdPrintDialog, context);
+ }
+ } else if (sdPrintDialog.printCurrent()) {
+ printPage(getContentsX(), getContentsY(), sdPrintDialog, context, 1);
+ } else if (sdPrintDialog.printRange()) {
+ for (int pageIndex = sdPrintDialog.getFrom(); pageIndex <= sdPrintDialog.maxNumOfPages() && pageIndex <= sdPrintDialog.getTo(); pageIndex++) {
+ printPage(pageIndex, sdPrintDialog, context);
+ }
+ }
+
+ fPrinter.endJob();
+ fIsPrinting = false;
+
+ gc.dispose();
+ context.dispose();
+
+ fZoomValue = lastZoom;
+ fPrinter.dispose();
+ setContentsPos(restoreX, restoreY);
+ }
+
+ /**
+ * Method to print.
+ */
+ public void print() {
+ SDPrintDialog sdPrinter = new SDPrintDialog(this.getShell(), this);
+ try {
+ if (sdPrinter.open() != 0) {
+ return;
+ }
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error creating image", e); //$NON-NLS-1$
+ return;
+ }
+ printUI(sdPrinter.getDialogUI());
+ }
+
+ /**
+ * Method to print a page.
+ *
+ * @param pageNum The page number
+ * @param pd The sequence diagram print dialog
+ * @param context The graphical context
+ */
+ public void printPage(int pageNum, SDPrintDialogUI pd, NGC context) {
+ int j = pageNum / pd.getNbRow();
+ int i = pageNum % pd.getNbRow();
+ if (i != 0) {
+ j++;
+ } else {
+ i = pd.getNbRow();
+ }
+
+ i--;
+ j--;
+
+ i = (int) (i * pd.getStepX());
+ j = (int) (j * pd.getStepY());
+
+ printPage(i, j, pd, context, pageNum);
+
+ fPrinter.endPage();
+ }
+
+ /**
+ * Method to print page ranges.
+ *
+ * @param i
+ * The start page
+ * @param j
+ * The end page
+ * @param pd
+ * The sequence diagram print dialog
+ * @param context
+ * The graphical context
+ * @param pageNum
+ * The current page
+ */
+ public void printPage(int i, int j, SDPrintDialogUI pd, NGC context, int pageNum) {
+ fIsPrinting = false;
+ int pageNumFontZoom = fPrinter.getClientArea().height / getVisibleHeight();
+ fPrinterX = i;
+ fPrinterY = j;
+ setContentsPos(i, j);
+ update();
+ fIsPrinting = true;
+ float lastZoom = fZoomValue;
+ fZoomValue = fPrinterZoom * lastZoom;
+
+ fFrame.draw(context);
+
+ fZoomValue = pageNumFontZoom;
+ context.setFont(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE));
+ String currentPageNum = String.valueOf(pageNum);
+ int ii = context.textExtent(currentPageNum);
+ int jj = context.getCurrentFontHeight();
+ fZoomValue = fPrinterZoom * lastZoom;
+ context.drawText(currentPageNum, Math.round(fPrinterX + getVisibleWidth() / fPrinterZoom - ii / fPrinterZoom), Math.round(fPrinterY + getVisibleHeight() / fPrinterZoom - jj / fPrinterZoom), false);
+ fIsPrinting = false;
+ fZoomValue = lastZoom;
+ }
+
+ /**
+ * Sets the collapse provider.
+ *
+ * @param provider The collapse provider to set
+ */
+ protected void setCollapseProvider(ISDCollapseProvider provider) {
+ fCollapseProvider = provider;
+ }
+
+
+ /**
+ * Checks for focus of children.
+ *
+ * @param children Control to check
+ * @return true if child is on focus else false
+ */
+ protected boolean checkFocusOnChilds(Control children) {
+ if (children instanceof Composite) {
+ Control[] child = ((Composite) children).getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ return true;
+ }
+ checkFocusOnChilds(child[i]);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * A post action for a tooltip (before displaying).
+ *
+ * @param accessible true if accessible else false
+ * @return the tooltip text.
+ */
+ protected String getPostfixForTooltip(boolean accessible) {
+ StringBuffer postfix = new StringBuffer();
+ // Determine if the tooltip must show the time difference between the current mouse position and
+ // the last selected graphNode
+ if ((fCurrentGraphNode != null) &&
+ (fCurrentGraphNode instanceof ITimeRange) &&
+ (fToolTipNode instanceof ITimeRange) &&
+ (fCurrentGraphNode != fToolTipNode) &&
+ ((ITimeRange) fToolTipNode).hasTimeInfo() &&
+ ((ITimeRange) fCurrentGraphNode).hasTimeInfo()) {
+ postfix.append(" -> "); //$NON-NLS-1$
+ postfix.append(fCurrentGraphNode.getName());
+ postfix.append("\n"); //$NON-NLS-1$
+ postfix.append(Messages.SequenceDiagram_Delta);
+ postfix.append(" "); //$NON-NLS-1$
+
+ //double delta = ((ITimeRange)toolTipNode).getLastTime()-((ITimeRange)currentGraphNode).getLastTime();
+ ITmfTimestamp firstTime = ((ITimeRange) fCurrentGraphNode).getEndTime();
+ ITmfTimestamp lastTime = ((ITimeRange) fToolTipNode).getEndTime();
+ ITmfTimestamp delta = lastTime.getDelta(firstTime);
+ postfix.append(delta.toString());
+
+ } else {
+ if ((fToolTipNode instanceof ITimeRange) && ((ITimeRange) fToolTipNode).hasTimeInfo()) {
+ postfix.append("\n"); //$NON-NLS-1$
+ ITmfTimestamp firstTime = ((ITimeRange) fToolTipNode).getStartTime();
+ ITmfTimestamp lastTime = ((ITimeRange) fToolTipNode).getEndTime();
+
+ if (firstTime != null) {
+ if (lastTime != null && firstTime.compareTo(lastTime, true) != 0) {
+ postfix.append("start: "); //$NON-NLS-1$
+ postfix.append(firstTime.toString());
+ postfix.append("\n"); //$NON-NLS-1$
+ postfix.append("end: "); //$NON-NLS-1$
+ postfix.append(lastTime.toString());
+ postfix.append("\n"); //$NON-NLS-1$
+ } else {
+ postfix.append(firstTime.toString());
+ }
+ }
+ else if (lastTime != null) {
+ postfix.append(lastTime.toString());
+ }
+ }
+ }
+ return postfix.toString();
+ }
+
+ /**
+ * Sets a new focused widget.
+ *
+ * @param newFocusShape A new focus shape.
+ */
+ protected void setFocus(int newFocusShape) {
+ fFocusedWidget = newFocusShape;
+ if (fFocusedWidget == -1) {
+ getViewControl().getAccessible().setFocus(ACC.CHILDID_SELF);
+ } else {
+ getViewControl().getAccessible().setFocus(fFocusedWidget);
+ }
+ }
+
+ /**
+ * Highlight the given GraphNode<br>
+ * The GraphNode is then displayed using the system default selection color
+ *
+ * @param node the GraphNode to highlight
+ */
+ protected void performSelection(GraphNode node) {
+ if ((fCtrlSelection) || (fShiftSelection)) {
+ if (node != null) {
+ if (fSelectedNodeList.contains(node)) {
+ removeSelection(node);
+ } else {
+ addSelection(node);
+ }
+ } else {
+ return;
+ }
+ } else {
+ clearSelection();
+ if (node != null) {
+ addSelection(node);
+ }
+ }
+ }
+
+ /**
+ * Returns a draw buffer image.
+ *
+ * @return a Image containing the draw buffer.
+ */
+ protected Image getDrawBuffer() {
+
+ update();
+ Rectangle area = getClientArea();
+ Image dbuffer = new Image(getDisplay(), area.width, area.height);
+ GC gcim = new GC(dbuffer);
+ NGC context = new NGC(this, gcim);
+
+ // Set the metrics to use for lifeline text and message text
+ // using the Graphical Context
+ Metrics.setLifelineFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE)));
+ Metrics.setLifelineFontWidth(context.getFontWidth(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE)));
+ Metrics.setLifelineWidth(SDViewPref.getInstance().getLifelineWidth());
+ Metrics.setFrameFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_FRAME_NAME)));
+ Metrics.setLifelineHeaderFontHeight(context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE_HEADER)));
+
+ int syncMessFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_SYNC_MESS));
+ int syncMessRetFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_SYNC_MESS_RET));
+ int asyncMessFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_ASYNC_MESS));
+ int asyncMessRetFontH = context.getFontHeight(SDViewPref.getInstance().getFont(ISDPreferences.PREF_ASYNC_MESS_RET));
+
+ int messageFontHeight = 0;
+ if (syncMessFontH > syncMessRetFontH) {
+ messageFontHeight = syncMessFontH;
+ } else {
+ messageFontHeight = syncMessRetFontH;
+ }
+ if (messageFontHeight < asyncMessFontH) {
+ messageFontHeight = asyncMessFontH;
+ }
+ if (messageFontHeight < asyncMessRetFontH) {
+ messageFontHeight = asyncMessRetFontH;
+ }
+ Metrics.setMessageFontHeight(messageFontHeight);
+ context.setFont(SDViewPref.getInstance().getFont(ISDPreferences.PREF_LIFELINE));
+
+ int width = (int) ((fFrame.getWidth() + 2 * Metrics.FRAME_H_MARGIN) * fZoomValue);
+ int height = (int) ((fFrame.getHeight() + 2 * Metrics.FRAME_V_MARGIN) * fZoomValue);
+
+ resizeContents(width, height);
+
+ context.setBackground(SDViewPref.getInstance().getBackGroundColor(ISDPreferences.PREF_FRAME));
+ context.fillRectangle(0, 0, getContentsWidth(), Metrics.FRAME_V_MARGIN);
+ context.fillRectangle(0, 0, fFrame.getX(), getContentsHeight());
+ context.fillRectangle(fFrame.getX() + fFrame.getWidth() + 1, 0, getContentsWidth() - (fFrame.getX() + fFrame.getWidth() + 1), getContentsHeight());
+ context.fillRectangle(0, fFrame.getY() + fFrame.getHeight() + 1, getContentsWidth(), getContentsHeight() - (fFrame.getY() + fFrame.getHeight() + 1));
+ gcim.setLineWidth(1);
+
+ fFrame.draw(context);
+ if (fDragAndDrop != null) {
+ Lifeline node = fDragAndDrop;
+ boolean isSelected = fDragAndDrop.isSelected();
+ boolean hasFocus = fDragAndDrop.hasFocus();
+ node.setSelected(false);
+ node.setFocused(false);
+ node.draw(context, fDragX, fDragY);
+ node.setSelected(isSelected);
+ node.setFocused(hasFocus);
+ }
+ gcim.dispose();
+ context.dispose();
+ return dbuffer;
+ }
+
+ @Override
+ protected void keyPressedEvent(KeyEvent event) {
+ if (!(isFocusControl() || getViewControl().isFocusControl())) {
+ Control[] child = getParent().getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if ((child[i].isFocusControl())&& (!(child[i] instanceof ScrollView))) {
+ getViewControl().setFocus();
+ break;
+ }
+ }
+ }
+ setFocus(-1);
+
+ if (event.keyCode == SWT.CTRL) {
+ fCtrlSelection = true;
+ }
+ if (event.keyCode == SWT.SHIFT) {
+ fShiftSelection = true;
+ fPrevList = new ArrayList<>();
+ fPrevList.addAll(getSelection());
+ }
+
+ GraphNode prevNode = getFocusNode();
+
+ if (event.keyCode == SWT.ARROW_RIGHT) {
+ traverseRight();
+ }
+
+ if (event.keyCode == SWT.ARROW_LEFT) {
+ traverseLeft();
+ }
+
+ if (event.keyCode == SWT.ARROW_DOWN) {
+ traverseDown();
+ }
+
+ if (event.keyCode == SWT.ARROW_UP) {
+ traverseUp();
+ }
+
+ if (event.keyCode == SWT.HOME) {
+ traverseHome();
+ }
+
+ if (event.keyCode == SWT.END) {
+ traverseEnd();
+ }
+
+ if ((!fShiftSelection) && (!fCtrlSelection)) {
+ fListStart = fCurrentGraphNode;
+ }
+
+ if (event.character == ' ') {
+ performSelection(fCurrentGraphNode);
+ if (!fShiftSelection) {
+ fListStart = fCurrentGraphNode;
+ }
+ }
+
+ if ((fShiftSelection) && (prevNode != getFocusNode())) {
+ clearSelection();
+ addSelection(fPrevList);
+ addSelection(fFrame.getNodeList(fListStart, getFocusNode()));
+ if (getFocusNode() instanceof Lifeline) {
+ ensureVisible(getFocusNode().getX(), getFocusNode().getY(), getFocusNode().getWidth(), getFocusNode().getHeight(), SWT.CENTER | SWT.VERTICAL, true);
+ } else {
+ ensureVisible(getFocusNode());
+ }
+ } else if ((!fCtrlSelection) && (!fShiftSelection)) {
+
+ clearSelection();
+ if (getFocusNode() != null) {
+ addSelection(getFocusNode());
+
+ if (getFocusNode() instanceof Lifeline) {
+ ensureVisible(getFocusNode().getX(), getFocusNode().getY(), getFocusNode().getWidth(), getFocusNode().getHeight(), SWT.CENTER | SWT.VERTICAL, true);
+ } else {
+ ensureVisible(getFocusNode());
+ }
+ }
+ }
+
+ if (fCurrentGraphNode != null) {
+ fCurrentGraphNode.setFocused(true);
+ }
+ redraw();
+
+ if ((event.character == ' ') && ((fZoomInMode) || (fZoomOutMode))) {
+ int cx = Math.round((getContentsX() + getVisibleWidth() / 2) / fZoomValue);
+ int cy = Math.round((getContentsY() + getVisibleHeight() / 2) / fZoomValue);
+ if (fZoomInMode) {
+ if (fZoomValue < 64) {
+ fZoomValue = fZoomValue * (float) 1.25;
+ }
+ } else {
+ fZoomValue = fZoomValue / (float) 1.25;
+ }
+ int x = Math.round(cx * fZoomValue - getVisibleWidth() / (float) 2);
+ int y = Math.round(cy * fZoomValue - getVisibleHeight() / (float) 2);
+ setContentsPos(x, y);
+ if (fTimeBar != null) {
+ fTimeBar.setZoom(fZoomValue);
+ }
+ // redraw also resize the scrollView content
+ redraw();
+ }
+ }
+
+ @Override
+ protected void keyReleasedEvent(KeyEvent event) {
+ setFocus(-1);
+ if (event.keyCode == SWT.CTRL) {
+ fCtrlSelection = false;
+ }
+ if (event.keyCode == SWT.SHIFT) {
+ fShiftSelection = false;
+ }
+ super.keyReleasedEvent(event);
+ setFocus(1);
+ }
+
+ @Override
+ public boolean isFocusControl() {
+ Control[] child = getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ return true;
+ }
+ checkFocusOnChilds(child[i]);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean setContentsPos(int x, int y) {
+ int localX = x;
+ int localY = y;
+
+ if (localX < 0) {
+ localX = 0;
+ }
+ if (localY < 0) {
+ localY = 0;
+ }
+ if (fFrame == null) {
+ return false;
+ }
+ if (localX + getVisibleWidth() > getContentsWidth()) {
+ localX = getContentsWidth() - getVisibleWidth();
+ }
+ if (localY + getVisibleHeight() > getContentsHeight()) {
+ localY = getContentsHeight() - getVisibleHeight();
+ }
+ int x1 = Math.round(localX / fZoomValue);
+ int y2 = Math.round(localY / fZoomValue);
+ int width = Math.round(getVisibleWidth() / fZoomValue);
+ int height = Math.round(getVisibleHeight() / fZoomValue);
+ fFrame.updateIndex(x1, y2, width, height);
+
+ if (fInsertionCartet != null && fInsertionCartet.isVisible()) {
+ fInsertionCartet.setVisible(false);
+ }
+
+ return super.setContentsPos(localX, localY);
+ }
+
+ @Override
+ protected void contentsMouseHover(MouseEvent event) {
+ GraphNode graphNode = null;
+ if (fFrame != null) {
+ int x = Math.round(event.x / fZoomValue);
+ int y = Math.round(event.y / fZoomValue);
+ graphNode = fFrame.getNodeAt(x, y);
+ if ((graphNode != null) && (SDViewPref.getInstance().tooltipEnabled())) {
+ fToolTipNode = graphNode;
+ String postfix = getPostfixForTooltip(true);
+ if (graphNode instanceof Lifeline) {
+ Lifeline lifeline = (Lifeline) graphNode;
+ fToolTip.showToolTip(lifeline.getToolTipText() + postfix);
+ setFocus(0);
+ } else {
+ fToolTip.showToolTip(graphNode.getName() + postfix);
+ setFocus(0);
+ }
+ } else {
+ fToolTip.hideToolTip();
+ }
+ }
+ }
+
+ @Override
+ protected void contentsMouseMoveEvent(MouseEvent e) {
+ fScrollToolTip.hideToolTip();
+ fToolTip.hideToolTip();
+ if (!(isFocusControl() || getViewControl().isFocusControl())) {
+ Control[] child = getParent().getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if ((child[i].isFocusControl()) && (!(child[i] instanceof ScrollView))) {
+ getViewControl().setFocus();
+ break;
+ }
+ }
+ }
+ setFocus(-1);
+
+ if (((e.stateMask & SWT.BUTTON_MASK) != 0) && ((fDragAndDrop != null) || fIsDragAndDrop) && (fReorderMode || fCollapseProvider != null)) {
+ fIsDragAndDrop = false;
+ if (fCurrentGraphNode instanceof Lifeline) {
+ fDragAndDrop = (Lifeline) fCurrentGraphNode;
+ }
+ if (fDragAndDrop != null) {
+ int dx = 0;
+ int dy = 0;
+ if (e.x > getContentsX() + getVisibleWidth()) {
+ dx = e.x - (getContentsX() + getVisibleWidth());
+ } else if (e.x < getContentsX()) {
+ dx = -getContentsX() + e.x;
+ }
+ if (e.y > getContentsY() + getVisibleHeight()) {
+ dy = e.y - (getContentsY() + getVisibleHeight());
+ } else if (e.y < getContentsY()) {
+ dy = -getContentsY() + e.y;
+ }
+ fDragX = e.x;
+ fDragY = e.y;
+ if (dx != 0 || dy != 0) {
+ if (fLocalAutoScroll == null) {
+ if (fLocalAutoScrollTimer == null) {
+ fLocalAutoScrollTimer = new Timer(true);
+ }
+ fLocalAutoScroll = new AutoScroll(this, dx, dy);
+ fLocalAutoScrollTimer.schedule(fLocalAutoScroll, 0, 75);
+ } else {
+ fLocalAutoScroll.fDeltaX = dx;
+ fLocalAutoScroll.fDeltaY = dy;
+ }
+ } else if (fLocalAutoScroll != null) {
+ fLocalAutoScroll.cancel();
+ fLocalAutoScroll = null;
+ }
+ fDragX = Math.round(e.x / fZoomValue);
+ fDragY = Math.round(e.y / fZoomValue);
+ redraw();
+ Lifeline node = fFrame.getCloserLifeline(fDragX);
+ if ((node != null) && (node != fDragAndDrop)) {
+ int y = 0;
+ int y1 = 0;
+ int height = Metrics.getLifelineHeaderFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
+ int hMargin = Metrics.LIFELINE_VT_MAGIN / 4;
+ int x = node.getX();
+ int width = node.getWidth();
+ if (fFrame.getVisibleAreaY() < node.getY() + node.getHeight() - height - hMargin) {
+ y = contentsToViewY(Math.round((node.getY() + node.getHeight()) * fZoomValue));
+ } else {
+ y = Math.round(height * fZoomValue);
+ }
+
+ if (fFrame.getVisibleAreaY() < contentsToViewY(node.getY() - hMargin)) {
+ y1 = contentsToViewY(Math.round((node.getY() - hMargin) * fZoomValue));
+ } else {
+ y1 = Math.round(height * fZoomValue);
+ }
+
+ int rx = Math.round(x * fZoomValue);
+
+ fInsertionCartet.setVisible(true);
+ if ((fInsertionCartet.getImage() != null) && (!fInsertionCartet.getImage().isDisposed())) {
+ fInsertionCartet.getImage().dispose();
+ }
+ if (rx <= e.x && Math.round(rx + (width * fZoomValue)) >= e.x) {
+ if (fCollapseProvider != null) {
+ ImageData data = fCollapaseCaretImg.getImageData();
+ data = data.scaledTo(Math.round(fCollapaseCaretImg.getBounds().width * fZoomValue), Math.round(fCollapaseCaretImg.getBounds().height * fZoomValue));
+ fCurrentCaretImage = new Image(Display.getCurrent(), data);
+ fInsertionCartet.setImage(fCurrentCaretImage);
+ fInsertionCartet.setLocation(contentsToViewX(rx + Math.round((width / (float) 2) * fZoomValue)) - fCurrentCaretImage.getBounds().width / 2, y);
+ }
+ } else if (fReorderMode) {
+ if (rx > e.x) {
+ if (node.getIndex() > 1 && fFrame.getLifeline(node.getIndex() - 2) == fDragAndDrop) {
+ return;
+ }
+ ImageData data = fArrowUpCaretImg.getImageData();
+ data = data.scaledTo(Math.round(fArrowUpCaretImg.getBounds().width * fZoomValue), Math.round(fArrowUpCaretImg.getBounds().height * fZoomValue));
+ fCurrentCaretImage = new Image(Display.getCurrent(), data);
+ fInsertionCartet.setImage(fCurrentCaretImage);
+ fInsertionCartet.setLocation(contentsToViewX(Math.round((x - Metrics.LIFELINE_SPACING / 2) * fZoomValue)) - fCurrentCaretImage.getBounds().width / 2, y1);
+ } else {
+ if (node.getIndex() < fFrame.lifeLinesCount() && fFrame.getLifeline(node.getIndex()) == fDragAndDrop) {
+ return;
+ }
+ ImageData data = fArrowUpCaretImg.getImageData();
+ data = data.scaledTo(Math.round(fArrowUpCaretImg.getBounds().width * fZoomValue), Math.round(fArrowUpCaretImg.getBounds().height * fZoomValue));
+ fCurrentCaretImage = new Image(Display.getCurrent(), data);
+ fInsertionCartet.setImage(fCurrentCaretImage);
+ fInsertionCartet.setLocation(contentsToViewX(Math.round((x + width + Metrics.LIFELINE_SPACING / 2) * fZoomValue)) - fCurrentCaretImage.getBounds().width / 2 + 1, y1);
+ }
+ }
+ } else {
+ fInsertionCartet.setVisible(false);
+ }
+ }
+ } else {
+ super.contentsMouseMoveEvent(e);
+ }
+ }
+
+ @Override
+ protected void contentsMouseUpEvent(MouseEvent event) {
+ // Just in case the diagram highlight a time compression region
+ // this region need to be released when clicking everywhere
+ fInsertionCartet.setVisible(false);
+ if (fDragAndDrop != null) {
+ if ((fOverView != null) && (!fOverView.isDisposed())) {
+ fOverView.dispose();
+ }
+ fOverView = null;
+ Lifeline node = fFrame.getCloserLifeline(fDragX);
+ if (node != null) {
+ int rx = Math.round(node.getX() * fZoomValue);
+ if (rx <= event.x && Math.round(rx + (node.getWidth() * fZoomValue)) >= event.x) {
+ if ((fCollapseProvider != null) && (fDragAndDrop != node)) {
+ fCollapseProvider.collapseTwoLifelines(fDragAndDrop, node);
+ }
+ } else if (rx < event.x) {
+ fFrame.insertLifelineAfter(fDragAndDrop, node);
+ if (node.getIndex() < fFrame.lifeLinesCount()) {
+ Lifeline temp[] = { fDragAndDrop, fFrame.getLifeline(node.getIndex()) };
+ fReorderList.add(temp);
+ } else {
+ Lifeline temp[] = { fDragAndDrop, null };
+ fReorderList.add(temp);
+ }
+ } else {
+ fFrame.insertLifelineBefore(fDragAndDrop, node);
+ Lifeline temp[] = { fDragAndDrop, node };
+ fReorderList.add(temp);
+ }
+ }
+ }
+ fDragAndDrop = null;
+ redraw();
+ if (fFrame == null) {
+ return;
+ }
+ fFrame.resetTimeCompression();
+
+ // reset auto scroll if it's engaged
+ if (fLocalAutoScroll != null) {
+ fLocalAutoScroll.cancel();
+ fLocalAutoScroll = null;
+ }
+ super.contentsMouseUpEvent(event);
+ }
+
+ @Override
+ protected void contentsMouseDownEvent(MouseEvent event) {
+ if (fCurrentGraphNode != null) {
+ fCurrentGraphNode.setFocused(false);
+ }
+
+ // Just in case the diagram highlight a time compression region
+ // this region need to be released when clicking everywhere
+ if (fFrame == null) {
+ return;
+ }
+
+ fFrame.resetTimeCompression();
+
+ if ((event.stateMask & SWT.CTRL) != 0) {
+ fCtrlSelection = true;
+ } else {
+ fCtrlSelection = false;
+ }
+
+ if (((fZoomInMode) || (fZoomOutMode)) && (event.button == 1)) {
+ int cx = Math.round(event.x / fZoomValue);
+ int cy = Math.round(event.y / fZoomValue);
+ if (fZoomInMode) {
+ if (fZoomValue < 64) {
+ fZoomValue = fZoomValue * (float) 1.25;
+ }
+ } else {
+ fZoomValue = fZoomValue / (float) 1.25;
+ }
+ int x = Math.round(cx * fZoomValue - getVisibleWidth() / (float) 2);
+ int y = Math.round(cy * fZoomValue - getVisibleHeight() / (float) 2);
+ setContentsPos(x, y);
+ if (fTimeBar != null) {
+ fTimeBar.setZoom(fZoomValue);
+ }
+ // redraw also resize the scrollView content
+ redraw();
+ } else {
+ GraphNode node = null;
+ int x = Math.round(event.x / fZoomValue);
+ int y = Math.round(event.y / fZoomValue);
+ node = fFrame.getNodeAt(x, y);
+
+ if ((event.button == 1) || ((node != null) && !node.isSelected())) {
+ if (!fShiftSelection) {
+ fListStart = node;
+ }
+ if (fShiftSelection) {
+ clearSelection();
+ addSelection(fFrame.getNodeList(fListStart, node));
+ } else {
+ performSelection(node);
+ }
+ fCurrentGraphNode = node;
+ if (node != null) {
+ node.setFocused(true);
+ }
+ }
+ redraw();
+ }
+ if (fDragAndDrop == null) {
+ super.contentsMouseDownEvent(event);
+ }
+ fIsDragAndDrop = (event.button == 1);
+
+ }
+
+ /**
+ * TimerTask for auto scroll feature.
+ */
+ protected static class AutoScroll extends TimerTask {
+ /**
+ * Field delta x.
+ */
+ public int fDeltaX;
+ /**
+ * Field delta y.
+ */
+ public int fDeltaY;
+ /**
+ * Field sequence diagram reference.
+ */
+ public SDWidget fSdWidget;
+
+ /**
+ * Constructor for AutoScroll.
+ * @param sv sequence diagram widget reference
+ * @param dx delta x
+ * @param dy delta y
+ */
+ public AutoScroll(SDWidget sv, int dx, int dy) {
+ fSdWidget = sv;
+ fDeltaX = dx;
+ fDeltaY = dy;
+ }
+
+ @Override
+ public void run() {
+ Display display = Display.getDefault();
+ if ((display == null) || (display.isDisposed())) {
+ return;
+ }
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (fSdWidget.isDisposed()) {
+ return;
+ }
+ fSdWidget.fDragX += fDeltaX;
+ fSdWidget.fDragY += fDeltaY;
+ fSdWidget.scrollBy(fDeltaX, fDeltaY);
+ }
+ });
+ }
+ }
+
+ @Override
+ protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
+ if (fFrame == null) {
+ gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ gc.fillRectangle(0, 0, getVisibleWidth(), getVisibleHeight());
+ gc.dispose();
+ return;
+ }
+ SDViewPref.getInstance();
+
+ Rectangle area = getClientArea();
+ Image dbuffer = getDrawBuffer();
+ int height = Math.round((fFrame.getHeight() + 2 * Metrics.FRAME_V_MARGIN) * fZoomValue);
+
+ try {
+ gc.drawImage(dbuffer, 0, 0, area.width, area.height, 0, 0, area.width, area.height);
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error drawin content", e); //$NON-NLS-1$
+ }
+ dbuffer.dispose();
+ setHScrollBarIncrement(Math.round(SDViewPref.getInstance().getLifelineWidth() / (float) 2 * fZoomValue));
+ setVScrollBarIncrement(Math.round(Metrics.getMessagesSpacing() * fZoomValue));
+ if ((fTimeBar != null) && (fFrame.hasTimeInfo())) {
+ fTimeBar.resizeContents(9, height + getHorizontalBarHeight());
+ fTimeBar.setContentsPos(getContentsX(), getContentsY());
+ fTimeBar.redraw();
+ fTimeBar.update();
+ }
+ float xRatio = getContentsWidth() / (float) getVisibleWidth();
+ float yRatio = getContentsHeight() / (float) getVisibleHeight();
+ if (yRatio > xRatio) {
+ setOverviewSize((int) (getVisibleHeight() * 0.75));
+ } else {
+ setOverviewSize((int) (getVisibleWidth() * 0.75));
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent event) {
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ if (event.widget == fZoomIn) {
+ fZoomValue = fZoomValue * 2;
+ } else if (event.widget == fZoomOut) {
+ fZoomValue = fZoomValue / 2;
+ }
+ redraw();
+ }
+
+ /**
+ * Called when property changed occurs in the preference page. "PREFOK" is
+ * fired when the user press the ok or apply button
+ */
+ @Override
+ public void propertyChange(PropertyChangeEvent e) {
+ if (fFrame != null && !isDisposed()) {
+ fFrame.resetTimeCompression();
+ }
+ if (e.getProperty().equals("PREFOK")) //$NON-NLS-1$
+ {
+ // Prepare the overview to be reused for the new
+ // settings (especially the colors)
+ if (fOverView != null) {
+ fOverView.dispose();
+ }
+ fOverView = null;
+ redraw();
+ }
+ }
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ if (fOverView != null) {
+ fOverView.dispose();
+ }
+ super.removeDisposeListener(this);
+ if ((fCurrentCaretImage != null) && (!fCurrentCaretImage.isDisposed())) {
+ fCurrentCaretImage.dispose();
+ }
+ if ((fArrowUpCaretImg != null) && (!fArrowUpCaretImg.isDisposed())) {
+ fArrowUpCaretImg.dispose();
+ }
+ if ((fCollapaseCaretImg != null) && (!fCollapaseCaretImg.isDisposed())) {
+ fCollapaseCaretImg.dispose();
+ }
+ SDViewPref.getInstance().removePropertyChangeListener(this);
+ LoadersManager lm = LoadersManager.getInstance();
+ if (fSite instanceof SDView) {
+ ((SDView) fSite).resetProviders();
+ if (lm != null) {
+ lm.resetLoader(((SDView) fSite).getViewSite().getId());
+ }
+ }
+ }
+
+ @Override
+ protected void drawOverview(GC gc, Rectangle r) {
+ float oldzoom = fZoomValue;
+ if (getContentsWidth() > getContentsHeight()) {
+ fZoomValue = (float) r.width / (float) getContentsWidth() * oldzoom;
+ } else {
+ fZoomValue = (float) r.height / (float) getContentsHeight() * oldzoom;
+ }
+ if ((fOverView != null) && ((r.width != fOverView.getBounds().width) || (r.height != fOverView.getBounds().height))) {
+ fOverView.dispose();
+ fOverView = null;
+ }
+ if (fOverView == null) {
+ int backX = getContentsX();
+ int backY = getContentsY();
+ setContentsPos(0, 0);
+ fOverView = new Image(getDisplay(), r.width, r.height);
+ GC gcim = new GC(fOverView);
+ NGC context = new NGC(this, gcim);
+ context.setBackground(SDViewPref.getInstance().getBackGroundColor(ISDPreferences.PREF_FRAME));
+ fFrame.draw(context);
+ setContentsPos(backX, backY);
+ gcim.dispose();
+ context.dispose();
+ }
+ if ((fOverView != null) && (r.width == fOverView.getBounds().width) && (r.height == fOverView.getBounds().height)) {
+ gc.drawImage(fOverView, 0, 0, r.width, r.height, 0, 0, r.width, r.height);
+ }
+
+ fZoomValue = oldzoom;
+
+ super.drawOverview(gc, r);
+ }
+
+ @Override
+ public void deltaSelected(Lifeline lifeline, int startEvent, int nbEvent, IColor color) {
+ fFrame.highlightTimeCompression(lifeline, startEvent, nbEvent, color);
+ ensureVisible(lifeline);
+ int y1 = lifeline.getY() + lifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * startEvent;
+ int y2 = lifeline.getY() + lifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * (startEvent + nbEvent);
+ ensureVisible(lifeline.getX(), y1 - (Metrics.getLifelineHeaderFontHeigth() + +2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN), lifeline.getWidth(), y2 - y1 + 3, SWT.CENTER | SWT.VERTICAL, true);
+ redraw();
+ update();
+ }
+
+ @Override
+ public int getVisibleWidth() {
+ if (fIsPrinting) {
+ return fPrinter.getClientArea().width;
+ }
+ return super.getVisibleWidth();
+ }
+
+ @Override
+ public int getVisibleHeight() {
+ if (fIsPrinting) {
+ return fPrinter.getClientArea().height;
+ }
+ return super.getVisibleHeight();
+ }
+
+ @Override
+ public int contentsToViewX(int x) {
+ if (fIsPrinting) {
+ int v = Math.round(fPrinterX * fPrinterZoom);
+ return x - v;
+ }
+ return x - getContentsX();
+ }
+
+ @Override
+ public int contentsToViewY(int y) {
+ if (fIsPrinting) {
+ int v = Math.round(fPrinterY * fPrinterZoom);
+ return y - v;
+ }
+ return y - getContentsY();
+ }
+
+ @Override
+ public int getContentsX() {
+ if (fIsPrinting) {
+ return Math.round(fPrinterX * fPrinterZoom);
+ }
+ return super.getContentsX();
+ }
+
+ @Override
+ public int getContentsY() {
+ if (fIsPrinting) {
+ return Math.round(fPrinterY * fPrinterZoom);
+ }
+ return super.getContentsY();
+ }
+
+ /**
+ * Traverse Listener implementation.
+ */
+ protected static class LocalTraverseListener implements TraverseListener {
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
+ e.doit = true;
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidgetSelectionProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidgetSelectionProvider.java
new file mode 100755
index 0000000000..4dd0c8d011
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/SDWidgetSelectionProvider.java
@@ -0,0 +1,88 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+
+/**
+ * <p>
+ * Informs all registered listeners of graph node selection change in the Frame.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDWidgetSelectionProvider implements ISelectionProvider {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The listener list
+ */
+ private List<ISelectionChangedListener> fListenerList = null;
+
+ /**
+ * The current selection
+ */
+ private ISelection fCurrentSelection = null;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ */
+ protected SDWidgetSelectionProvider() {
+ fListenerList = new ArrayList<>();
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void addSelectionChangedListener(ISelectionChangedListener listener) {
+ if (!fListenerList.contains(listener)) {
+ fListenerList.add(listener);
+ }
+ }
+
+ @Override
+ public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+ fListenerList.remove(listener);
+ }
+
+ @Override
+ public void setSelection(ISelection selection) {
+ fCurrentSelection = selection;
+ for (int i = 0; i < fListenerList.size(); i++) {
+ ISelectionChangedListener list = fListenerList.get(i);
+ list.selectionChanged(new SelectionChangedEvent(this, fCurrentSelection));
+ }
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return fCurrentSelection;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ScrollView.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ScrollView.java
new file mode 100755
index 0000000000..bf199965b2
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/ScrollView.java
@@ -0,0 +1,2067 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+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.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TypedEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Scrollable;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * ScrollView widget provides a scrolling area with on-demand scroll bars.
+ * Overview scrollable panel can be used (@see setOverviewEnabled()).
+ *
+ * @author Eric Miravete
+ * @version 1.0
+ */
+public class ScrollView extends Composite {
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Scroll bar mode AUTO
+ */
+ public static final int AUTO = 0;
+ /**
+ * Scroll bar mode ALWAYS_ON
+ */
+ public static final int ALWAYS_ON = 1;
+ /**
+ * Scroll bar mode ALWAYS_OFF
+ */
+ public static final int ALWAYS_OFF = 2;
+ /**
+ * Bit mask for visible vertical scroll bar
+ */
+ public static final int VBAR = 0x01;
+ /**
+ * Bit mask for visible horizontal scroll bar
+ */
+ public static final int HBAR = 0x02;
+
+ private static final int DEFAULT_H_SCROLL_INCREMENT = 10;
+ private static final int DEFAULT_V_SCROLL_INCREMENT = 10;
+ private static final int DEFAULT_AUTO_SCROLL_PERIOD = 75;
+ private static final int DEFAULT_OVERVIEW_SIZE = 100;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * Value of the contents height property.
+ */
+ private int fContentsHeight = 0;
+ /**
+ * Value of the contents width property.
+ */
+ private int fContentsWidth = 0;
+ /**
+ * Value of the contents x coordinate property
+ */
+ private int fContentsX = 0;
+ /**
+ * Value of the contents y coordinate property
+ */
+ private int fContentsY = 0;
+ /**
+ * Scroll bar mode of horizontal scroll bar.
+ */
+ private int fHorScrollbarMode = AUTO;
+ /**
+ * Scroll bar mode of vertical scroll bar.
+ */
+ private int fVertScrollbarMode = AUTO;
+ /**
+ * Increment for the horizontal scroll bar.
+ */
+ private int fHorScrollbarIncrement = DEFAULT_H_SCROLL_INCREMENT;
+ /**
+ * Increment for the vertical scroll bar.
+ */
+ private int fVertScrollbarIncrement = DEFAULT_V_SCROLL_INCREMENT;
+ /**
+ * Flag whether auto scroll is enabled or not.
+ */
+ private boolean fAutoScrollEnabled = true;
+ /**
+ * Value of the auto scroll period.
+ */
+ private int fAutoScrollPeriod = DEFAULT_AUTO_SCROLL_PERIOD;
+ /**
+ * The local paint listener reference.
+ */
+ private PaintListener fLocalPaintListener = null;
+ /**
+ * The local mouse move listener reference.
+ */
+ private MouseMoveListener fLocalMouseMoveListener = null;
+ /**
+ * The local mouse listener reference.
+ */
+ private MouseListener fLocalMouseListener = null;
+ /**
+ * The local control listener reference.
+ */
+ private ControlListener fLocalControlListener = null;
+ /**
+ * The local key listener reference.
+ */
+ private KeyListener fLocalKeyListener = null;
+ // Canvas for vertical/horizontal Scroll Bar only ... because new ScrollBar() does works.
+ /**
+ * Canvas for horizontal scroll bar.
+ */
+ private Canvas fHorScrollBar;
+ /**
+ * Canvas for vertical scroll bar.
+ */
+ private Canvas fVertScrollBar;
+ /**
+ * Canvas for the view control.
+ */
+ private Canvas fViewControl;
+ /**
+ * Control used in the bottom right corner @see setCornerControl() and @see setOverviewEnabled(true)
+ */
+ private Control fCornerControl;
+ /**
+ * Size of overview widget.
+ */
+ private int fOverviewSize = DEFAULT_OVERVIEW_SIZE; // default size for overview
+ /**
+ * Timer for auto_scroll feature
+ */
+ private AutoScroll fAutoScroll = null;
+ /**
+ * TimerTask for auto_scroll feature !=null when auto scroll is running
+ */
+ private Timer fAutoScrollTimer = null;
+ /**
+ * where mouse down appear on contents area (x coordinate)
+ */
+ private int fMouseDownX = -1;
+ /**
+ * where mouse down appear on contents area (y coordinate)
+ */
+ private int fMousDownY = -1;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
+ * using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
+ *
+ * @param c The parent composite
+ * @param style The SWT style bits @see SWT
+ */
+ public ScrollView(Composite c, int style) {
+ this(c, style, true);
+ }
+
+ /**
+ * Create a ScrollView, child of composite c. Both scroll bar have the mode AUTO. Auto scroll feature is enabled
+ * using a delay of 250ms. Overview feature is not enabled by default (use setOverviewEnabled()).
+ *
+ * @param c The parent composite.
+ * @param style The SWT style bits @see SWT
+ * @param mouseWheel Flag to force scrollView to handles mouse wheel
+ */
+ public ScrollView(Composite c, int style, boolean mouseWheel) {
+ super(c, SWT.NONE);
+
+ fHorScrollBar = new Canvas(this, SWT.H_SCROLL);
+ if (mouseWheel) {
+ // force scroll bar to get mouse wheel, those scrollbar will be hidden
+ fViewControl = new Canvas(this, style | SWT.H_SCROLL | SWT.V_SCROLL);
+ } else {
+ fViewControl = new Canvas(this, style);
+ }
+ fViewControl.setBackground(getBackground());
+ // hide scroll bar as their are replaced by fHorScrollBar and fVertScrollBar.
+ if (mouseWheel) {
+ fViewControl.getVerticalBar().setVisible(false);
+ fViewControl.getHorizontalBar().setVisible(false);
+ }
+ fVertScrollBar = new Canvas(this, SWT.V_SCROLL);
+
+ setLayout(new SVLayout());
+
+ fLocalPaintListener = new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent event) {
+ // use clipping, to reduce cost of paint.
+ Rectangle r = event.gc.getClipping();
+ int cx = viewToContentsX(r.x);
+ int cy = viewToContentsY(r.y);
+ drawContents(event.gc, cx, cy, r.width, r.height);
+ }
+ };
+ fViewControl.addPaintListener(fLocalPaintListener);
+
+ fLocalMouseMoveListener = new MouseMoveListener() {
+ @Override
+ public void mouseMove(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseMoveEvent(e);
+ e.x = ox;
+ e.y = oy;
+ }
+ };
+
+ fViewControl.addMouseMoveListener(fLocalMouseMoveListener);
+
+ MouseTrackListener localMouseTrackListener = new MouseTrackListener() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseEnter(e);
+ e.x = ox;
+ e.y = oy;
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseHover(e);
+ e.x = ox;
+ e.y = oy;
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseExit(e);
+ e.x = ox;
+ e.y = oy;
+ }
+
+ };
+
+ fViewControl.addMouseTrackListener(localMouseTrackListener);
+
+ fLocalMouseListener = new MouseListener() {
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseDoubleClickEvent(e);
+ e.x = ox;
+ e.y = oy;
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ fMouseDownX = e.x;
+ e.y = viewToContentsY(e.y);
+ fMousDownY = e.y;
+ contentsMouseDownEvent(e);
+ e.x = ox;
+ e.y = oy;
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ int ox = e.x, oy = e.y;
+ e.x = viewToContentsX(e.x);
+ e.y = viewToContentsY(e.y);
+ contentsMouseUpEvent(e);
+ e.x = ox;
+ e.y = oy;
+ // here because class extending me can catch mouse Up and want to scroll...
+ fMouseDownX = -1;
+ fMousDownY = -1;
+ }
+ };
+ fViewControl.addMouseListener(fLocalMouseListener);
+
+ fLocalKeyListener = new KeyListener() {
+ @Override
+ public void keyPressed(KeyEvent e) {
+ keyPressedEvent(e);
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ keyReleasedEvent(e);
+ }
+ };
+
+ fViewControl.addKeyListener(fLocalKeyListener);
+
+ getVerticalBar().addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ setContentsPos(fContentsX, getVerticalBar().getSelection());
+ // need to change "hidden" vertical bar value ?
+ // force focus on fViewControl so we got future mouse wheel's scroll events
+ if (!fViewControl.isFocusControl()) {
+ fViewControl.setFocus();
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
+ if (fViewControl.getVerticalBar() != null) {
+ // add fViewControl hidden scrollbar listener to get mouse wheel ...
+ fViewControl.getVerticalBar().addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ScrollBar b = fViewControl.getVerticalBar();
+ setContentsPos(fContentsX, b.getSelection());
+ // change "real" vertical bar selection too
+ getVerticalBar().setSelection(b.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ }
+ getHorizontalBar().addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ setContentsPos(getHorizontalBar().getSelection(), fContentsY);
+ // need to change "real" horizontal bar too ?
+ // force focus on fViewControl so we got future mouse wheel's scroll events
+ if (!fViewControl.isFocusControl()) {
+ fViewControl.setFocus();
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ if (fViewControl.getHorizontalBar() != null) {
+ fViewControl.getHorizontalBar().addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ ScrollBar b = fViewControl.getHorizontalBar();
+ setContentsPos(b.getSelection(), fContentsY);
+ // change "real" vertical bar selection too
+ getHorizontalBar().setSelection(b.getSelection());
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public boolean setFocus() {
+ return fViewControl.forceFocus();
+ }
+
+ @Override
+ public void setCursor(Cursor cursor) {
+ fViewControl.setCursor(cursor);
+ }
+
+ @Override
+ public void dispose() {
+ if (fAutoScroll != null) {
+ fAutoScroll.cancel();
+ fAutoScroll = null;
+ }
+ if (fViewControl != null) {
+ fViewControl.dispose();
+ }
+ fViewControl = null;
+ if (fVertScrollBar != null) {
+ fVertScrollBar.dispose();
+ }
+ fVertScrollBar = null;
+ if (fHorScrollBar != null) {
+ fHorScrollBar.dispose();
+ }
+ fHorScrollBar = null;
+ if (fCornerControl != null) {
+ Object data = fCornerControl.getData();
+ if (data instanceof Overview) {
+ ((Overview) data).dispose();
+ }
+ fCornerControl.dispose();
+ fCornerControl = null;
+ }
+ super.dispose();
+ }
+
+ @Override
+ public Rectangle getClientArea() {
+ Rectangle area = fViewControl.getClientArea();
+ /* Clamp the size of the returned area to 1x1 minimum */
+ area.width = Math.max(area.width, 1);
+ area.height = Math.max(area.height, 1);
+ return area;
+ }
+
+ @Override
+ public void setBackground(Color c) {
+ super.setBackground(c);
+ fViewControl.setBackground(c);
+ }
+
+ @Override
+ public void setToolTipText(String text) {
+ fViewControl.setToolTipText(text);
+ }
+
+ /**
+ * Draw overview area, @see setOverviewEnabled. By default draw a rectangle corresponding to the visible area of
+ * scroll view. You can redefine this method to draw the contents as drawContents does... ...in an other magnify
+ * factor.
+ *
+ * @param gc GC to used to draw.
+ * @param r Rectangle corresponding to the client area of overview.
+ */
+ protected void drawOverview(GC gc, Rectangle r) {
+ int x = (int) (r.width * fContentsX / (float) fContentsWidth);
+ int y = (int) (r.height * fContentsY / (float) fContentsHeight);
+ int vw = getVisibleWidth();
+ int vh = getVisibleHeight();
+ int w = r.width - 1;
+ if (fContentsWidth > vw) {
+ w = (int) (r.width * vw / (float) fContentsWidth);
+ }
+ int h = r.height - 1;
+ if (fContentsHeight > vh) {
+ h = (int) (r.height * vh / (float) fContentsHeight);
+ }
+
+ gc.setForeground(getForeground());
+ // too small rectangle ?
+ if (w < 5 || h < 5) {
+ // use a cross ...
+ gc.drawLine(x, 0, x, r.height);
+ gc.drawLine(0, y, r.width, y);
+ } else {
+ gc.drawRectangle(x, y, w, h);
+ }
+ }
+
+ /**
+ * Remove the local Listener and add the new listener.
+ *
+ * @param nlistener the new listener
+ */
+ public void replaceControlListener(ControlListener nlistener) {
+ if (fLocalControlListener != null) {
+ removeControlListener(fLocalControlListener);
+ fLocalControlListener = null;
+ }
+ addControlListener(nlistener);
+ }
+
+ /**
+ * Remove the local Listener and add the new listener.
+ *
+ * @param nlistener the new listener
+ */
+ public void replaceKeyListener(KeyListener nlistener) {
+ if (fLocalKeyListener != null) {
+ removeKeyListener(fLocalKeyListener);
+ fLocalKeyListener = null;
+ }
+ addKeyListener(nlistener);
+ }
+
+ /**
+ * Remove the local Listener and add the new listener.
+ *
+ * @param nlistener the new listener
+ */
+ public void replaceMouseListener(MouseListener nlistener) {
+ if (fLocalMouseListener != null) {
+ removeMouseListener(fLocalMouseListener);
+ fLocalMouseListener = null;
+ }
+ fViewControl.addMouseListener(nlistener);
+ }
+
+ /**
+ * Remove the local Listener and add the new listener.
+ *
+ * @param nlistener the new listener
+ */
+ public void replaceMouseMoveListener(MouseMoveListener nlistener) {
+ if (fLocalMouseMoveListener != null) {
+ removeMouseMoveListener(fLocalMouseMoveListener);
+ fLocalMouseMoveListener = null;
+ }
+ fViewControl.addMouseMoveListener(nlistener);
+ }
+
+ /**
+ * Remove the local Listener and add the new listener.
+ *
+ * @param nlistener the new listener
+ */
+ public void replacePaintListener(PaintListener nlistener) {
+ if (fLocalPaintListener != null) {
+ removePaintListener(fLocalPaintListener);
+ fLocalPaintListener = null;
+ }
+ fViewControl.addPaintListener(nlistener);
+ }
+
+ /**
+ * Access method for the contentsHeight property.
+ *
+ * @return the current value of the contentsHeight property
+ */
+ public int getContentsHeight() {
+ return fContentsHeight;
+ }
+
+ /**
+ * Access method for the contentsWidth property.
+ *
+ * @return the current value of the contentsWidth property
+ */
+ public int getContentsWidth() {
+ return fContentsWidth;
+ }
+
+ /**
+ * Access method for the contentsX property.
+ *
+ * @return the current value of the contentsX property
+ */
+ public int getContentsX() {
+ return fContentsX;
+ }
+
+ /**
+ * Access method for the contentsY property.
+ *
+ * @return the current value of the contentsY property
+ */
+ public int getContentsY() {
+ return fContentsY;
+ }
+
+ /**
+ * Determines if the dragAutoScroll property is true.
+ *
+ * @return <code>true<code> if the dragAutoScroll property is true
+ */
+ public boolean isDragAutoScroll() {
+ return fAutoScrollEnabled;
+ }
+
+ /**
+ * Sets the value of the dragAutoScroll property.
+ *
+ * @param aDragAutoScroll the new value of the dragAutoScroll property
+ */
+ public void setDragAutoScroll(boolean aDragAutoScroll) {
+ fAutoScrollEnabled = aDragAutoScroll;
+ if (!fAutoScrollEnabled && (fAutoScroll != null)) {
+ fAutoScroll.cancel();
+ fAutoScroll = null;
+ }
+ }
+
+ /**
+ * Change delay (in millisec) used for auto scroll feature.
+ *
+ * @param period new period between to auto scroll
+ */
+ public void setDragAutoScrollPeriod(int period) {
+ fAutoScrollPeriod = Math.max(0, period);
+ }
+
+ /**
+ * Return auto scroll period.
+ *
+ * @return The period
+ */
+ public int getDragAutoScrollPeriod() {
+ return fAutoScrollPeriod;
+ }
+
+ /**
+ * Access method for the hScrollBarMode property.
+ *
+ * @return the current value of the hScrollBarMode property
+ */
+ public int getHScrollBarMode() {
+ return fHorScrollbarMode;
+ }
+
+ /**
+ * Sets the value of the hScrollBarMode property.
+ *
+ * @param aHScrollBarMode the new value of the hScrollBarMode property
+ */
+ public void setHScrollBarMode(int aHScrollBarMode) {
+ fHorScrollbarMode = aHScrollBarMode;
+ }
+
+ /**
+ * Access method for the vScrollBarMode property.
+ *
+ * @return the current value of the vScrollBarMode property
+ */
+ public int getVScrollBarMode() {
+ return fVertScrollbarMode;
+ }
+
+ /**
+ * Sets the value of the vScrollBarMode property.
+ *
+ * @param aVScrollBarMode the new value of the vScrollBarMode property
+ */
+ public void setVScrollBarMode(int aVScrollBarMode) {
+ fVertScrollbarMode = aVScrollBarMode;
+ }
+
+ /**
+ * Return horizontal scroll bar increment, default:1
+ *
+ * @return The increment
+ */
+ public int getHScrollBarIncrement() {
+ return fHorScrollbarIncrement;
+ }
+
+ /**
+ * Return vertical scroll bar increment, default:1
+ *
+ * @return The increment
+ */
+ public int getVScrollBarIncrement() {
+ return fVertScrollbarIncrement;
+ }
+
+ /**
+ * Change horizontal scroll bar increment, minimum:1. Page increment is
+ * always set to visible width.
+ *
+ * @param inc
+ * Increment value to set
+ */
+ public void setHScrollBarIncrement(int inc) {
+ fHorScrollbarIncrement = Math.max(1, inc);
+ }
+
+ /**
+ * Change vertical scroll bar increment, minimum:1. Page increment is always
+ * set to visible height.
+ *
+ * @param inc
+ * Increment value to set
+ */
+ public void setVScrollBarIncrement(int inc) {
+ fVertScrollbarIncrement = Math.max(1, inc);
+ }
+
+ /**
+ * Enable or disable overview feature. Enabling overview, dispose and replace existing corner control by a button.
+ * Clicking in it open overview, move mouse cursor holding button to move scroll view and release button to hide
+ * overview. Tip: hold control and/or shift key while moving mouse when overview is open made fine scroll.
+ *
+ * @param value true to engage overview feature
+ */
+ public void setOverviewEnabled(boolean value) {
+ if (isOverviewEnabled() == value) {
+ return;
+ }
+
+ Control cc = null;
+ if (value) {
+ Button b = new Button(this, SWT.NONE);
+ b.setText("+"); //$NON-NLS-1$
+ Overview ovr = new Overview();
+ ovr.useControl(b);
+ b.setData(ovr);
+ cc = b;
+ b.setToolTipText(Messages.SequenceDiagram_OpenOverviewTooltip);
+ }
+ setCornerControl(cc);
+ }
+
+ /**
+ * Change overview size (at ratio 1:1), default is 100
+ *
+ * @param size
+ * The new size
+ */
+ public void setOverviewSize(int size) {
+ fOverviewSize = Math.abs(size);
+ }
+
+ /**
+ * Returns whether the overview is enabled or not.
+ *
+ * @return true is overview feature is enabled
+ */
+ public boolean isOverviewEnabled() {
+ if (fCornerControl instanceof Button) {
+ Object data = ((Button) fCornerControl).getData();
+ // overview alreay
+ if (data instanceof Overview) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the overview size at ratio 1:1.
+ *
+ * @return current overview size at ratio 1:1
+ */
+ public int getOverviewSize() {
+ return fOverviewSize;
+ }
+
+ /**
+ * Returns control used to display view (might not be this object). Use this control to add/remove listener on the
+ * draw area.
+ *
+ * @return control used to display view (might not be this object).
+ */
+ public Control getViewControl() {
+ return fViewControl;
+ }
+
+ /**
+ * Called when the mouse enter the ScrollView area
+ *
+ * @param e
+ * Mouse event
+ */
+ protected void contentsMouseExit(MouseEvent e) {
+ }
+
+ /**
+ * Called when the mouse enter the ScrollView area after and system defined
+ * time
+ *
+ * @param e
+ * Mouse event
+ */
+ protected void contentsMouseHover(MouseEvent e) {
+ }
+
+ /**
+ * Called when the mouse enter the ScrollView area
+ *
+ * @param e
+ * Mouse event
+ */
+ protected void contentsMouseEnter(MouseEvent e) {
+ }
+
+ /**
+ * Called when user double on contents area.
+ *
+ * @param e
+ * Mouse event
+ */
+ protected void contentsMouseDoubleClickEvent(MouseEvent e) {
+ }
+
+ /**
+ * Called when mouse is on contents area and button is pressed.
+ *
+ * @param e
+ * Mouse event
+ */
+ protected void contentsMouseDownEvent(MouseEvent e) {
+ fMouseDownX = e.x;
+ fMousDownY = e.y;
+ }
+
+ /**
+ * TimerTask for auto scroll feature.
+ */
+ protected static class AutoScroll extends TimerTask {
+
+ /** X delta */
+ private int deltaX;
+
+ /** Y delta */
+ private int deltaY;
+
+ /** ScrollView object */
+ private ScrollView scrollView;
+
+ /**
+ * Constructor.
+ *
+ * @param sv
+ * ScrollView object to use
+ * @param dx
+ * X delta
+ * @param dy
+ * Y delta
+ */
+ public AutoScroll(ScrollView sv, int dx, int dy) {
+ scrollView = sv;
+ deltaX = dx;
+ deltaY = dy;
+ }
+
+ @Override
+ public void run() {
+ final Display display = Display.getDefault();
+ if ((display == null) || display.isDisposed()) {
+ return;
+ }
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!scrollView.isDisposed()) {
+ scrollView.scrollBy(deltaX, deltaY);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Called when mouse is on contents area and mode.
+ *
+ * @param event
+ * Mouse event
+ */
+ protected void contentsMouseMoveEvent(MouseEvent event) {
+ if ((event.stateMask & SWT.BUTTON_MASK) != 0) {
+ if (!fAutoScrollEnabled) {
+ scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
+ return;
+ }
+
+ int sx = 0, sy = 0;
+
+ int vRight = getContentsX() + getVisibleWidth();
+ int vBottom = getContentsY() + getVisibleHeight();
+
+ // auto scroll... ?
+ if (event.x < getContentsX()) {
+ sx = (getContentsX() - event.x);
+ fMouseDownX = getContentsX();
+ } else if (event.x > vRight) {
+ sx = -event.x + vRight;
+ fMouseDownX = vRight;
+ }
+ if (event.y < getContentsY()) {
+ sy = (getContentsY() - event.y);
+ fMousDownY = getContentsY();
+ } else if (event.y > vBottom) {
+ sy = -event.y + vBottom;
+ fMousDownY = vBottom;
+ }
+
+ if (sx != 0 || sy != 0) {
+ // start auto scroll...
+ if (fAutoScroll == null) {
+ if (fAutoScrollTimer == null) {
+ fAutoScrollTimer = new Timer(true);
+ }
+ fAutoScroll = new AutoScroll(this, sx, sy);
+ fAutoScrollTimer.schedule(fAutoScroll, 0, fAutoScrollPeriod);
+ } else {
+ fAutoScroll.deltaX = sx;
+ fAutoScroll.deltaY = sy;
+ }
+ } else {
+ if (fAutoScroll != null) {
+ fAutoScroll.cancel();
+ fAutoScroll = null;
+ }
+
+ scrollBy(-(event.x - fMouseDownX), -(event.y - fMousDownY));
+ }
+ }
+ }
+
+ /**
+ * Called when mouse is on contents area and button is released
+ *
+ * @param event
+ * Mouse event
+ */
+ protected void contentsMouseUpEvent(MouseEvent event) {
+ // reset auto scroll if it's engaged
+ if (fAutoScroll != null) {
+ fAutoScroll.cancel();
+ fAutoScroll = null;
+ }
+ }
+
+ /**
+ * Responsible to draw contents area. At least rectangle clipX must be
+ * redrawn. This rectangle is given in contents coordinates. By default, no
+ * paint is produced.
+ *
+ * @param gc
+ * Graphics context
+ * @param clipx
+ * X clip
+ * @param clipy
+ * Y clip
+ * @param clipw
+ * W clip
+ * @param cliph
+ * H clip
+ */
+ protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
+ }
+
+ /**
+ * Change the size of the contents area.
+ *
+ * @param width new width of the area.
+ * @param height new height of the area.
+ */
+ public void resizeContents(int width, int height) {
+ int localWidth = width;
+ int localHeight = height;
+
+ if (localWidth < 0) {
+ localWidth = 0;
+ }
+ if (localHeight < 0) {
+ localHeight = 0;
+ }
+
+ int oldW = fContentsWidth;
+ int oldH = fContentsHeight;
+
+ if (localWidth == oldW && localHeight == oldH) {
+ return;
+ }
+
+ fContentsWidth = localWidth;
+ fContentsHeight = localHeight;
+
+ if (oldW > localWidth) {
+ int s = localWidth;
+ localWidth = oldW;
+ oldW = s;
+ }
+
+ int visWidth = getVisibleWidth();
+ int visHeight = getVisibleHeight();
+ if (oldW < visWidth) {
+ if (localWidth > visWidth) {
+ localWidth = visWidth;
+ }
+ fViewControl.redraw(getContentsX() + oldW, 0, localWidth - oldW, visHeight, true);
+ }
+
+ if (oldH > localHeight) {
+ int s = localHeight;
+ localHeight = oldH;
+ oldH = s;
+ }
+
+ if (oldH < visHeight) {
+ if (localHeight > visHeight) {
+ localHeight = visHeight;
+ }
+ fViewControl.redraw(0, getContentsY() + oldH, visWidth, localHeight - oldH, true);
+ }
+ if (updateScrollBarVisiblity()) {
+ layout();
+ } else {
+ updateScrollBarsValues();
+ }
+ }
+
+ // redefined for internal use ..
+ @Override
+ public void redraw() {
+ super.redraw();
+ // ..need to redraw this already:
+ fViewControl.redraw();
+ }
+
+ /**
+ * @param delataX The delta in X
+ * @param deltaY the delta in Y
+ */
+ public void scrollBy(int delataX, int deltaY) {
+ setContentsPos(getContentsX() + delataX, getContentsY() + deltaY);
+ }
+
+ /**
+ * Scroll to ensure point(in contents coordinates) is visible.
+ *
+ * @param px Point's x position
+ * @param py Point's y position
+ */
+ public void ensureVisible(int px, int py) {
+ int cx = getContentsX(), cy = getContentsY();
+ int right = getContentsX() + getVisibleWidth();
+ int bottom = getContentsY() + getVisibleHeight();
+ if (px < getContentsX()) {
+ cx = px;
+ } else if (px > right) {
+ cx = px - getVisibleWidth();
+ }
+ if (py < getContentsY()) {
+ cy = py;
+ } else if (py > bottom) {
+ cy = py - getVisibleHeight();
+ }
+ setContentsPos(cx, cy);
+ }
+
+ /**
+ * Make rectangle (x,y,w,h, in contents coordinates) visible. if rectangle cannot be completely visible, use
+ * align flags.
+ *
+ * @param xValue x contents coordinates of rectangle.
+ * @param yValue y contents coordinates of rectangle.
+ * @param width width of rectangle.
+ * @param height height of rectangle.
+ * @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
+ * than visible area. By default CENTER/VERTICAL
+ */
+ public void ensureVisible(int xValue, int yValue, int width, int height, int align) {
+ ensureVisible(xValue, yValue, width, height, align, false);
+ }
+
+ /**
+ * Make rectangle (xValue,yValue,width,height, in contents coordinates) visible. if rectangle cannot be completely visible, use
+ * align flags.
+ *
+ * @param xValue x contents coordinates of rectangle.
+ * @param yValue y contents coordinates of rectangle.
+ * @param width width of rectangle.
+ * @param height height of rectangle.
+ * @param align bit or'ed SWT flag like SWT.LEFT,RIGHT,CENTER,TOP,BOTTOM,VERTICAL used only for bigger rectangle
+ * than visible area. By default CENTER/VERTICAL
+ * @param forceAlign force alignment for rectangle smaller than the visible area
+ */
+ protected void ensureVisible(int xValue, int yValue, int width, int height, int align, boolean forceAlign) {
+
+ int localX = xValue;
+ int localY = yValue;
+ int localWidth = width;
+ int localHeight = height;
+
+ if (localWidth < 0) {
+ localX = localX + localWidth;
+ localWidth = -localWidth;
+ }
+ if (localHeight < 0) {
+ localY = localY + localHeight;
+ localHeight = -localHeight;
+ }
+ int hbar = getHorizontalBarHeight();
+ int vbar = getVerticalBarWidth();
+ int cx = getContentsX();
+ int cy = getContentsY();
+ int right = getContentsX() + getVisibleWidth() - vbar;
+ int bottom = getContentsY() + getVisibleHeight() - hbar;
+ boolean alignH = false, alignV = false;
+
+ if (localX < getContentsX()) {
+ cx = localX;
+ } else if (localX + localWidth > right) {
+ cx = localX - localWidth;
+ }
+ if (localY < getContentsY()) {
+ cy = localY;
+ } else if (localY + localHeight > bottom) {
+ cy = localY - localHeight;
+ }
+
+ if (localWidth > getVisibleWidth()) {
+ alignH = true;
+ }
+ if (localHeight > getVisibleHeight()) {
+ alignV = true;
+ }
+ // compute alignment on visible area horizontally
+ if (alignH || (forceAlign && localX + localWidth > right)) {
+ // use align flags
+ if ((align & SWT.LEFT) != 0) {
+ cx = localX;
+ } else if ((align & SWT.RIGHT) != 0) {
+ cx = right - localWidth;
+ } else { // center
+ cx = localX + (localWidth - getVisibleWidth()) / 2;
+ }
+ }
+ // compute alignment on visible area vertically
+ if (alignV || (forceAlign && localY + localHeight > bottom)) {
+ // use align flags
+ if ((align & SWT.TOP) != 0) {
+ cy = localY;
+ } else if ((align & SWT.BOTTOM) != 0) {
+ cy = bottom - localHeight;
+ } else { // center
+ cy = localY + (localHeight - getVisibleHeight()) / 2;
+ }
+ }
+ setContentsPos(cx, cy);
+ }
+
+ /**
+ * Returns true if point is visible (expressed in contents coordinates).
+ *
+ * @param px Point's x position
+ * @param py Point's y position
+ * @return true if point is visible (expressed in contents coordinates)
+ */
+ public boolean isVisible(int px, int py) {
+ if (px < getContentsX()) {
+ return false;
+ }
+ if (py < getContentsY()) {
+ return false;
+ }
+ if (px > (getContentsX() + getVisibleWidth())) {
+ return false;
+ }
+ if (py > (getContentsY() + getVisibleHeight())) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if rectangle if partially visible.
+ *
+ * @param xValue x contents coordinates of rectangle.
+ * @param yValue y contents coordinates of rectangle.
+ * @param width width of rectangle.
+ * @param height height of rectangle.
+ * @return true if rectangle if partially visible.
+ */
+ public boolean isVisible(int xValue, int yValue, int width, int height) {
+ if (xValue + width < getContentsX()) {
+ return false;
+ }
+ if (yValue + height < getContentsY()) {
+ return false;
+ }
+ int vr = getContentsX() + getVisibleWidth();
+ int vb = getContentsY() + getVisibleHeight();
+ if (xValue > vr) {
+ return false;
+ }
+ if (yValue > vb) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns visible part of rectangle, or null if rectangle is not visible.
+ * Rectangle is expressed in contents coordinates.
+ *
+ * @param xValue
+ * x contents coordinates of rectangle.
+ * @param yValue
+ * y contents coordinates of rectangle.
+ * @param width
+ * width of rectangle.
+ * @param height
+ * height of rectangle.
+ * @return visible part of rectangle, or null if rectangle is not visible.
+ */
+ public Rectangle getVisiblePart(int xValue, int yValue, int width, int height) {
+ if (xValue + width < getContentsX()) {
+ return null;
+ }
+ if (yValue + height < getContentsY()) {
+ return null;
+ }
+ int vr = getContentsX() + getVisibleWidth();
+ int vb = getContentsY() + getVisibleHeight();
+ if (xValue > vr) {
+ return null;
+ }
+ if (yValue > vb) {
+ return null;
+ }
+ int rr = xValue + width, rb = yValue + height;
+ int nl = Math.max(xValue, getContentsX()), nt = Math.max(yValue, getContentsY()), nr = Math.min(rr, vr), nb = Math.min(rb, vb);
+ return new Rectangle(nl, nt, nr - nl, nb - nt);
+ }
+
+ /**
+ * Returns the visible part for given rectangle.
+ *
+ * @param rect A rectangle
+ *
+ * @return gets visible part of rectangle (or <code>null</code>)
+ */
+ public final Rectangle getVisiblePart(Rectangle rect) {
+ if (rect == null) {
+ return null;
+ }
+ return getVisiblePart(rect.x, rect.y, rect.width, rect.height);
+ }
+
+ /**
+ * Change top left position of visible area. Check if the given point is inside contents area.
+ *
+ * @param xValue x contents coordinates of visible area.
+ * @param yValue y contents coordinates of visible area.
+ * @return true if view really moves
+ */
+ public boolean setContentsPos(int xValue, int yValue) {
+ int nx = xValue, ny = yValue;
+ if (getVisibleWidth() >= getContentsWidth()) {
+ nx = 0;
+ } else {
+ if (xValue < 0) {
+ nx = 0;
+ } else if (xValue + getVisibleWidth() > getContentsWidth()) {
+ nx = getContentsWidth() - getVisibleWidth();
+ }
+ }
+ if (getVisibleHeight() >= getContentsHeight()) {
+ ny = 0;
+ } else {
+ if (yValue <= 0) {
+ ny = 0;
+ } else if (yValue + getVisibleHeight() > getContentsHeight()) {
+ ny = getContentsHeight() - getVisibleHeight();
+ }
+ }
+ // no move
+ if (nx == fContentsX && ny == fContentsY) {
+ return false;
+ }
+ fContentsX = nx;
+ fContentsY = ny;
+ updateScrollBarsValues();
+ // ? find smallest area to redraw only them ?
+ fViewControl.redraw();
+ return true;
+ }
+
+ @Override
+ public ScrollBar getVerticalBar() {
+ return fVertScrollBar.getVerticalBar();
+ }
+
+ @Override
+ public ScrollBar getHorizontalBar() {
+ return fHorScrollBar.getHorizontalBar();
+ }
+
+ /**
+ * Compute visibility of vertical/horizontal bar using given width/height and current visibility (i.e. is bar size are already in
+ * for_xxx)
+ * @param forWidth width of foreground
+ * @param forHeight height of foreground
+ * @param currHorVis The current visibility state of horizontal scroll bar
+ * @param currVertvis The current visibility state of vertical scroll bar
+ * @return <code>true</code> if visibility changed else <code>false</code>
+ */
+ public int computeBarVisibility(int forWidth, int forHeight, boolean currHorVis, boolean currVertvis) {
+
+ int localForWidth = forWidth;
+ int vis = 0x00;
+ switch (fVertScrollbarMode) {
+ case ALWAYS_OFF:
+ break;
+ case ALWAYS_ON:
+ vis |= VBAR;
+ break;
+ case AUTO:
+ if (getContentsHeight() > forHeight) {
+ vis = VBAR;
+ // v bar size is already in for_width.
+ if (!currVertvis) {// (curr_vis&0x01)==0)
+ localForWidth -= getVerticalBarWidth();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (fHorScrollbarMode) {
+ case ALWAYS_OFF:
+ break;
+ case ALWAYS_ON:
+ vis |= HBAR;
+ break;
+ case AUTO:
+ if (getContentsWidth() > localForWidth) {
+ vis |= HBAR;
+ // h bar is not in for_height
+ if ((!currHorVis) && (getContentsHeight() > (forHeight - getHorizontalBarHeight()))) {// (curr_vis&0x02)==0 )
+ vis |= VBAR;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return vis;
+ }
+
+ /**
+ * Setup scroll bars visibility.
+ *
+ * @return True if one of visibility changed.
+ */
+ protected boolean updateScrollBarVisiblity() {
+ boolean change = false;
+
+ boolean currVertVis = fVertScrollBar.getVisible();
+ boolean currHorVis = fHorScrollBar.getVisible();
+ int barNewVis = computeBarVisibility(getVisibleWidth(), getVisibleHeight(), currHorVis, currVertVis);
+ boolean newVertVis = (barNewVis & VBAR) != 0;
+ boolean newHorVis = (barNewVis & HBAR) != 0;
+ if (currVertVis ^ newVertVis) { // vertsb_.getVisible() )
+ fVertScrollBar.setVisible(newVertVis);
+ change = true;
+ }
+ if (currHorVis ^ newHorVis) {
+ fHorScrollBar.setVisible(newHorVis);
+ change = true;
+ }
+
+ // update corner control visibility:
+ if (fCornerControl != null && change) {
+ boolean vis = newVertVis || newHorVis;
+ if (vis ^ fCornerControl.getVisible()) {
+ fCornerControl.setVisible(vis);
+ change = true; // but must be already the case
+ }
+ }
+ return change;
+ }
+
+ /**
+ * Setup scroll bar using contents, visible and scroll bar mode properties.
+ */
+ protected void updateScrollBarsValues() {
+ /* update vertical scrollbar */
+ ScrollBar b = getVerticalBar();
+ if (b != null) {
+ b.setMinimum(0);
+ b.setMaximum(getContentsHeight());
+ b.setThumb(getVisibleHeight());
+ b.setPageIncrement(getVisibleHeight());
+ b.setIncrement(fVertScrollbarIncrement);
+ b.setSelection(getContentsY());
+ }
+
+ // update "hidden" vertical bar too
+ b = fViewControl.getVerticalBar();
+ if (b != null) {
+ b.setMinimum(0);
+ b.setMaximum(getContentsHeight());
+ b.setThumb(getVisibleHeight());
+ b.setPageIncrement(getVisibleHeight());
+ b.setIncrement(fVertScrollbarIncrement);
+ b.setSelection(getContentsY());
+ }
+
+ /* update horizontal scrollbar */
+ b = getHorizontalBar();
+ if (b != null) {
+ b.setMinimum(0);
+ b.setMaximum(getContentsWidth());
+ b.setThumb(getVisibleWidth());
+ b.setSelection(getContentsX());
+ b.setPageIncrement(getVisibleWidth());
+ b.setIncrement(fHorScrollbarIncrement);
+ }
+ // update "hidden" horizontal bar too
+ b = fViewControl.getHorizontalBar();
+ if (b != null) {
+ b.setMinimum(0);
+ b.setMaximum(getContentsWidth());
+ b.setThumb(getVisibleWidth());
+ b.setSelection(getContentsX());
+ b.setPageIncrement(getVisibleWidth());
+ b.setIncrement(fHorScrollbarIncrement);
+ }
+ }
+
+ /**
+ * Change the control used in the bottom right corner (between two scrollbar), if control is null reset previous
+ * corner control. This control is visible only if at least one scrollbar is visible. Given control will be disposed
+ * by ScrollView, at dispose() time, at next setCornetControl() call or when calling setOverviewEnabled(). Pay
+ * attention calling this reset overview feature until setOverviewEnabled(true) if called.
+ * @param control The control for the overview
+ */
+ public void setCornerControl(Control control) {
+ if (fCornerControl != null) {
+ fCornerControl.dispose();
+ }
+ fCornerControl = control;
+ if (fCornerControl != null) {
+ ScrollBar vb = getVerticalBar();
+ ScrollBar hb = getHorizontalBar();
+ boolean vis = vb.getVisible() || hb.getVisible();
+ fCornerControl.setVisible(vis);
+ }
+ }
+
+ /**
+ * Transform (x,y) point in widget coordinates to contents coordinates.
+ *
+ * @param x The x widget coordinate.
+ * @param y The y widget coordinate.
+ * @return org.eclipse.swt.graphics.Point with content coordinates.
+ */
+ public final Point viewToContents(int x, int y) {
+ return new Point(viewToContentsX(x), viewToContentsY(y));
+ }
+
+ /**
+ * Transform x in widget coordinates to contents coordinates
+ *
+ * @param x The y widget coordinate.
+ * @return the x content coordinate.
+ */
+ public int viewToContentsX(int x) {
+ return fContentsX + x;
+ }
+
+ /**
+ * Transform y in widget coordinates to contents coordinates
+ *
+ * @param y The y widget coordinate.
+ * @return the y content coordinate.
+ */
+ public int viewToContentsY(int y) {
+ return fContentsY + y;
+ }
+
+ /**
+ * Transform (x,y) point from contents coordinates, to widget coordinates.
+ *
+ * @param x The x content coordinate.
+ * @param y The y content coordinate.
+ * @return coordinates widget area as.
+ */
+ public final Point contentsToView(int x, int y) {
+ return new Point(contentsToViewX(x), contentsToViewY(y));
+ }
+
+ /**
+ * Transform X axis coordinates from contents to widgets.
+ *
+ * @param x contents coordinate to transform.
+ * @return x coordinate in widget area
+ */
+ public int contentsToViewX(int x) {
+ return x - fContentsX;
+ }
+
+ /**
+ * Transform Y axis coordinates from contents to widgets.
+ *
+ * @param y contents coordinate to transform
+ * @return y coordinate in widget area
+ */
+ public int contentsToViewY(int y) {
+ return y - fContentsY;
+ }
+
+ /**
+ * Return the visible height of scroll view, might be > contentsHeight
+ *
+ * @return the visible height of scroll view, might be > contentsHeight()
+ */
+ public int getVisibleHeight() {
+ return fViewControl.getClientArea().height;
+ }
+
+ /**
+ * Return int the visible width of scroll view, might be > contentsWidth().
+ *
+ * @return int the visible width of scroll view, might be > contentsWidth()
+ */
+ public int getVisibleWidth() {
+ return fViewControl.getClientArea().width;
+ }
+
+ /**
+ * Add support for arrow key, scroll the ... scroll view. But you can
+ * redefine this method for your convenience.
+ *
+ * @param event
+ * Keyboard event
+ */
+ protected void keyPressedEvent(KeyEvent event) {
+ switch (event.keyCode) {
+ case SWT.ARROW_UP:
+ scrollBy(0, -getVisibleHeight());
+ break;
+ case SWT.ARROW_DOWN:
+ scrollBy(0, +getVisibleHeight());
+ break;
+ case SWT.ARROW_LEFT:
+ scrollBy(-getVisibleWidth(), 0);
+ break;
+ case SWT.ARROW_RIGHT:
+ scrollBy(+getVisibleWidth(), 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Redefine this method at your convenience
+ *
+ * @param event The key event.
+ */
+ protected void keyReleasedEvent(KeyEvent event) {
+ }
+
+ /**
+ * Returns vertical bar width, even if bar isn't visible.
+ *
+ * @return vertical bar width, even if bar isn't visible
+ */
+ public int getVerticalBarWidth() {
+ // include vertical bar width and trimming of scrollable used
+ int bw = fVertScrollBar.computeTrim(0, 0, 0, 0).width;
+ return bw + 1;
+ }
+
+ /**
+ * Returns horizontal bar height even if bar isn't visible.
+ *
+ * @return horizontal bar height even if bar isn't visible
+ */
+ public int getHorizontalBarHeight() {
+ // include horiz. bar height and trimming of scrollable used
+ int bh = fHorScrollBar.computeTrim(0, 0, 0, 0).height;
+ // +1 because win32 H.bar need 1 pixel canvas size to appear ! (strange no ?)
+ return bh + 1;
+ }
+
+ @Override
+ public Rectangle computeTrim(int x, int y, int w, int h) {
+ Rectangle r = new Rectangle(x, y, w, h);
+ int barVis = computeBarVisibility(w, h, false, false);
+ if ((barVis & VBAR) != 0) {
+ r.width += getVerticalBarWidth();
+ }
+ if ((barVis & HBAR) != 0) {
+ r.height += getHorizontalBarHeight();
+ }
+ return r;
+ }
+
+ /**
+ * Internal layout for ScrollView, handle scrollbars, drawzone and corner control
+ */
+ protected class SVLayout extends Layout {
+
+ private static final int DEFAULT_X = 250;
+ private static final int DEFAULT_Y = 250;
+ private static final int MAX_SEEK = 10;
+ private static final int MIN_SEEK = 0;
+
+ /**
+ * The seek value
+ */
+ private int seek = 0;
+ /**
+ * The do-it-not flag
+ */
+ private boolean dontLayout = false;
+
+ @Override
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ Point p = new Point(DEFAULT_X, DEFAULT_Y);
+ if (fContentsWidth < p.x) {
+ p.x = fContentsWidth;
+ }
+ if (fContentsHeight < p.y) {
+ p.y = fContentsHeight;
+ }
+ return p;
+ }
+
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {
+ if (dontLayout) {
+ return;
+ }
+ seek++;
+ if (seek > MAX_SEEK) {
+ dontLayout = true;
+ }
+
+ Point cs = composite.getSize();
+ int barVis = computeBarVisibility(cs.x, cs.y, false, false);
+ boolean vbVis = (barVis & VBAR) != 0;
+ boolean hbVis = (barVis & HBAR) != 0;
+ fVertScrollBar.setVisible(vbVis);
+ fHorScrollBar.setVisible(hbVis);
+ int vbw = getVerticalBarWidth();
+ int hbh = getHorizontalBarHeight();
+ int wb = vbVis ? vbw : 0;
+ int hb = hbVis ? hbh : 0;
+ int cww = 0, cwh = 0;
+
+ if (fCornerControl != null && (vbVis || hbVis)) { // corner_control_.getVisible())
+ fCornerControl.setVisible(true);
+ cww = vbw;
+ cwh = hbh;
+ if (wb == 0) {
+ wb = vbw;
+ }
+ if (hb == 0) {
+ hb = hbh;
+ }
+ } else if (vbVis && hbVis) {
+ if (fCornerControl != null) {
+ fCornerControl.setVisible(false);
+ }
+ cww = vbw;
+ cwh = hbh;
+ }
+ if (vbVis || hbVis) {
+ updateScrollBarsValues();
+ }
+
+ int vw = cs.x - (vbVis ? vbw : 0);
+ int vh = cs.y - (hbVis ? hbh : 0);
+ int vbx = cs.x - wb;
+ int hby = cs.y - hb;
+
+ fViewControl.setBounds(0, 0, vw, vh);
+
+ if (vbVis) {
+ fVertScrollBar.setBounds(vbx, 0, wb, cs.y - cwh);
+ }
+ if (hbVis) {
+ fHorScrollBar.setBounds(0, hby, cs.x - cww, hb);
+ }
+ if (fCornerControl != null && fCornerControl.getVisible()) {
+ fCornerControl.setBounds(vbx, hby, vbw, hbh);
+ }
+ updateScrollBarsValues();
+
+ seek--;
+ if (seek == MIN_SEEK) {
+ dontLayout = false;
+ }
+ }
+
+ boolean isDontLayout() {
+ return dontLayout;
+ }
+
+ void setSontLayout(boolean dontLayout) {
+ this.dontLayout = dontLayout;
+ }
+ }
+
+ // static must take place here... cursor is created once.
+ private volatile static Cursor fOverviewCursor;
+
+ /** Support for click-and-see overview shell on this ScrollView */
+ protected class Overview {
+
+ private static final int REFRESH_FREQ = 4;
+
+ /**
+ * factor for X from real and overview sizes, for mouse move speed.
+ */
+ private float fOverviewFactorX;
+
+ /**
+ * factor for Y from real and overview sizes, for mouse move speed.
+ */
+ private float fOverviewFactorY;
+ /**
+ * shell use to show overview
+ */
+ private Shell fOverview;
+ /**
+ * save mouse X cursor location for disappear();
+ */
+ private int fSaveCursorX;
+ /**
+ * save mouse Y cursor location for disappear();
+ */
+ private int fSaveCursorY;
+
+ /**
+ * Apply overview support on a control. Replace existing corner_widget
+ *
+ * @param control
+ * The control to use
+ */
+ public void useControl(Control control) {
+ final Point pos = control.getLocation();
+ control.addMouseListener(new MouseListener() {
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseDown(MouseEvent e) {
+ overviewAppear(e.x, e.y);
+ }
+
+ @Override
+ public void mouseUp(MouseEvent e) {
+ overviewDisappear();
+ }
+ });
+
+ control.addFocusListener(new FocusListener() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ if (overviewing()) {
+ overviewDisappear(false);
+ }
+ }
+
+ });
+ control.addKeyListener(new KeyListener() {
+
+ @Override
+ public void keyPressed(KeyEvent event) {
+ if (event.keyCode == 32 && !overviewing()) {
+ overviewAppear(pos.x, pos.y);
+ } else if (event.keyCode == 32) {
+ overviewDisappear();
+ }
+ if (event.keyCode == SWT.ARROW_DOWN) {
+ overviewMove(0, 1, event);
+ }
+
+ if (event.keyCode == SWT.ARROW_UP) {
+ overviewMove(0, -1, event);
+ }
+
+ if (event.keyCode == SWT.ARROW_RIGHT) {
+ overviewMove(1, 0, event);
+ }
+
+ if (event.keyCode == SWT.ARROW_LEFT) {
+ overviewMove(-1, 0, event);
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e) {
+ }
+ });
+ control.addMouseMoveListener(new MouseMoveListener() {
+ private int refReshCount = 0;
+ @Override
+ public void mouseMove(MouseEvent event) {
+ if (overviewing()) {
+ // Slow down the refresh
+ if (refReshCount % REFRESH_FREQ == 0) {
+ overviewMove(event);
+ }
+ refReshCount++;
+ }
+ }
+ });
+ }
+
+ /**
+ * Dispose controls of overview
+ */
+ public void dispose() {
+ if (fOverview != null) {
+ fOverview.dispose();
+ }
+ }
+
+ /**
+ * @return true if overview is currently on screen
+ */
+ protected boolean overviewing() {
+ return (fOverview != null && fOverview.isVisible());
+ }
+
+ /**
+ * Process overview appear
+ *
+ * @param mx
+ * X coordinate
+ * @param my
+ * Y coordinate
+ */
+ protected void overviewAppear(int mx, int my) {
+ if (fOverview == null) {
+ fOverview = new Shell(getShell(), SWT.ON_TOP | SWT.NO_BACKGROUND);
+ fOverview.addPaintListener(new PaintListener() {
+ @Override
+ public void paintControl(PaintEvent e) {
+ drawOverview(e.gc, fOverview.getClientArea());
+ }
+ });
+ }
+ // always the same..
+ fOverview.setForeground(fViewControl.getForeground());
+
+ // get location of shell (in screeen coordinates)
+ Point p = toGlobalCoordinates(fCornerControl, 0, 0);
+ int x = p.x;
+ int y = p.y;
+ int w, h;
+ h = fOverviewSize;
+ w = h;
+ Rectangle scr = getDisplay().getBounds();
+ Point ccs = fCornerControl.getSize();
+ try {
+ if (fContentsWidth > fContentsHeight) {
+ float ratio = fContentsHeight / (float) fContentsWidth;
+ h = (int) (w * ratio);
+ if (h < ccs.y) {
+ h = ccs.y;
+ } else if (h >= scr.height / 2) {
+ h = scr.height / 2;
+ }
+ } else {
+ float ratio = fContentsWidth / (float) fContentsHeight;
+ w = (int) (h * ratio);
+ if (w < ccs.x) {
+ w = ccs.x;
+ } else if (w >= scr.width / 2) {
+ w = scr.width / 2;
+ }
+ }
+ fOverviewFactorX = fContentsWidth / (float) w;
+ fOverviewFactorY = fContentsHeight / (float) h;
+ }
+ // no contents size set ?
+ catch (java.lang.ArithmeticException e) {
+ }
+
+ // try pop-up on button, extending to bottom right,
+ if (x <= 0) {
+ x = 1;
+ }
+ if (y <= 0) {
+ y = 1;
+ }
+ x = x - w + ccs.x;
+ y = y - h + ccs.y;
+ fOverview.setBounds(x, y, w, h);
+ fOverview.setVisible(true);
+ fOverview.redraw();
+ // mouse cursor disappear, so set invisible mouse cursor ...
+ if (fOverviewCursor == null) {
+ RGB rgb[] = { new RGB(0, 0, 0), new RGB(255, 0, 0) };
+ PaletteData palette = new PaletteData(rgb);
+ int s = 1;
+ byte src[] = new byte[s * s];
+ byte msk[] = new byte[s * s];
+ for (int i = 0; i < s * s; ++i) {
+ src[i] = (byte) 0xFF;
+ }
+ ImageData i_src = new ImageData(s, s, 1, palette, 1, src);
+ ImageData i_msk = new ImageData(s, s, 1, palette, 1, msk);
+ fOverviewCursor = new Cursor(null, i_src, i_msk, 0, 0);
+ }
+ fCornerControl.setCursor(fOverviewCursor);
+ // convert to global coordinates
+ p = toGlobalCoordinates(fCornerControl, mx, my);
+ fSaveCursorX = p.x;
+ fSaveCursorY = p.y;
+
+ Rectangle r = fOverview.getClientArea();
+ int cx = (int) (r.width * fContentsX / (float) fContentsWidth);
+ int cy = (int) (r.height * fContentsY / (float) fContentsHeight);
+
+ // cx,cy to display's global coordinates
+ p = toGlobalCoordinates(fOverview.getParent(), cx, cy);
+ }
+
+ /**
+ * Process disappear of overview
+ */
+ protected void overviewDisappear() {
+ overviewDisappear(true);
+ }
+
+ /**
+ * Process disappear of overview
+ * @param restoreCursorLoc A flag to restore cursor location
+ */
+ protected void overviewDisappear(boolean restoreCursorLoc) {
+ if (fOverview == null) {
+ return;
+ }
+ fOverview.setVisible(false);
+ fCornerControl.setCursor(null);
+ if (restoreCursorLoc) {
+ getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
+ }
+ fOverview.dispose();
+ fOverview = null;
+ }
+
+ /**
+ * Process mouse move in overview
+ * @param event The mouse event
+ */
+ protected void overviewMove(MouseEvent event) {
+ Point p = toGlobalCoordinates(fCornerControl, event.x, event.y);
+ int dx = p.x - fSaveCursorX;
+ int dy = p.y - fSaveCursorY;
+ overviewMove(dx, dy, event);
+ }
+
+ /**
+ * Process mouse move event when overviewing
+ *
+ * @param dx The x coordinates delta
+ * @param dy The y coordinates delta
+ * @param event The typed event
+ */
+ protected void overviewMove(int dx, int dy, TypedEvent event) {
+ boolean ctrl = false;
+ boolean shift = false;
+
+ if (event instanceof MouseEvent) {
+ MouseEvent e = (MouseEvent) event;
+ getDisplay().setCursorLocation(fSaveCursorX, fSaveCursorY);
+ ctrl = (e.stateMask & SWT.CONTROL) != 0;
+ shift = (e.stateMask & SWT.SHIFT) != 0;
+ } else if (event instanceof KeyEvent) {
+ KeyEvent e = (KeyEvent) event;
+ ctrl = (e.stateMask & SWT.CONTROL) != 0;
+ shift = (e.stateMask & SWT.SHIFT) != 0;
+ }
+
+ int cx = fContentsX;
+ int cy = fContentsY;
+ float fx = fOverviewFactorX;
+ float fy = fOverviewFactorY;
+
+ if (ctrl && shift) {
+ if ((fx * 0.25f > 1) && (fy * 0.25 > 1)) {
+ fx = fy = 1.0f;
+ } else {
+ fx *= 0.1f;
+ fy *= 0.1f;
+ }
+ } else if (ctrl) {
+ fx *= 0.5f;
+ fy *= 0.5f;
+ } else if (shift) {
+ fx *= 0.5f;
+ fy *= 0.5f;
+ }
+ scrollBy((int) (fx * dx), (int) (fy * dy));
+ if (cx != fContentsX || cy != fContentsY) {
+ fOverview.redraw();
+ fOverview.update(); // draw now !
+ }
+ }
+
+ /**
+ * Convert overview coordinates to global coordinates.
+ *
+ * @param loc
+ * the control reference
+ * @param x
+ * The x coordinate to convert
+ * @param y
+ * The y coordinate to convert
+ * @return The new converted Point
+ */
+ protected Point toGlobalCoordinates(Control loc, int x, int y) {
+ Point p = new Point(x, y);
+ for (Control c = loc; c != null; c = c.getParent()) {
+ // control might have client area with 'decorations'
+ int trimX = 0, trimY = 0;
+ // other kind of widget with trimming ??
+ if (c instanceof Scrollable) {
+ Scrollable s = (Scrollable) c;
+ Rectangle rr = s.getClientArea();
+ Rectangle tr = s.computeTrim(rr.x, rr.y, rr.width, rr.height);
+ trimX = rr.x - tr.x;
+ trimY = rr.y - tr.y;
+ }
+ p.x += c.getLocation().x + trimX;
+ p.y += c.getLocation().y + trimY;
+ }
+ return p;
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/TimeCompressionBar.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/TimeCompressionBar.java
new file mode 100755
index 0000000000..b7e72adecb
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/TimeCompressionBar.java
@@ -0,0 +1,1028 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.accessibility.ACC;
+import org.eclipse.swt.accessibility.Accessible;
+import org.eclipse.swt.accessibility.AccessibleAdapter;
+import org.eclipse.swt.accessibility.AccessibleControlAdapter;
+import org.eclipse.swt.accessibility.AccessibleControlEvent;
+import org.eclipse.swt.accessibility.AccessibleEvent;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessageReturn;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BaseMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.ExecutionOccurrence;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Frame;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.ITimeRange;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Metrics;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SDTimeEvent;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl.ColorImpl;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.TimeEventComparator;
+
+/**
+ * <p>
+ * The time compression bar implementation.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class TimeCompressionBar extends ScrollView implements DisposeListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ private static final int BASE_RED_VALUE = 255;
+ private static final int BASE_GREEN_BLUE_VALUE = 225;
+ private static final int COLOR_STEP = 25;
+ private static final int NUMBER_STEPS = 10;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The listener list
+ */
+ private List<ITimeCompressionListener> fListenerList = null;
+ /**
+ * The current frame displayed.
+ */
+ private Frame fFrame = null;
+ /**
+ * List of time events.
+ */
+ private List<SDTimeEvent> fNodeList = null;
+ /**
+ * The minimum time delta.
+ */
+ private ITmfTimestamp fMinTime = new TmfTimestamp();
+ /**
+ * The maximum time delta.
+ */
+ private ITmfTimestamp fMaxTime = new TmfTimestamp();
+ /**
+ * The current zoom value.
+ */
+ private float fZoomValue = 1;
+ /**
+ * The tooltip to display.
+ */
+ private DrawableToolTip fTooltip = null;
+ /**
+ * Array of colors for displaying wight of time deltas.
+ */
+ private ColorImpl[] fColors;
+ /**
+ * The accessible object reference.
+ */
+ private Accessible fAccessible = null;
+ /**
+ * The focused widget reference.
+ */
+ private int fFocusedWidget = -1;
+ /**
+ * The current lifeline.
+ */
+ private Lifeline fLifeline = null;
+ /**
+ * The current start event value.
+ */
+ private int fLifelineStart = 0;
+ /**
+ * The current number of events.
+ */
+ private int fLifelineNumEvents = 0;
+ /**
+ * The Current color of range to display.
+ */
+ private IColor fLifelineColor = null;
+ /**
+ * The next graph node y coordinate.
+ */
+ private int fNextNodeY = 0;
+ /**
+ * The previous graph node y coordinate.
+ */
+ private int fPrevNodeY = 0;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Standard constructor
+ *
+ * @param parent The parent composite
+ * @param s The style bits
+ */
+ public TimeCompressionBar(Composite parent, int s) {
+ super(parent, s | SWT.NO_BACKGROUND, false);
+ setVScrollBarMode(ScrollView.ALWAYS_OFF);
+ setHScrollBarMode(ScrollView.ALWAYS_OFF);
+ fListenerList = new ArrayList<>();
+ fColors = new ColorImpl[NUMBER_STEPS];
+ int greenBlue = BASE_GREEN_BLUE_VALUE;
+ final int step = COLOR_STEP;
+ for (int i = 0; i < fColors.length; i++) {
+ fColors[i] = new ColorImpl(Display.getDefault(), BASE_RED_VALUE, greenBlue, greenBlue);
+ greenBlue -= step;
+ }
+ super.addDisposeListener(this);
+
+ fAccessible = getViewControl().getAccessible();
+
+ fAccessible.addAccessibleListener(new AccessibleAdapter() {
+ @Override
+ public void getName(AccessibleEvent e) {
+ // Case toolTip
+ if (e.childID == 0) {
+ if (fTooltip != null) {
+ e.result = fTooltip.getAccessibleText();
+ }
+ } else if (e.childID == 1) {
+ createFakeTooltip();
+ e.result = fTooltip.getAccessibleText();
+ }
+ }
+ });
+
+ fAccessible.addAccessibleControlListener(new AccessibleControlAdapter() {
+ @Override
+ public void getFocus(AccessibleControlEvent e) {
+ if (fFocusedWidget == -1) {
+ e.childID = ACC.CHILDID_SELF;
+ }
+ else {
+ e.childID = fFocusedWidget;
+ }
+ }
+
+ @Override
+ public void getRole(AccessibleControlEvent e) {
+ switch (e.childID) {
+ case ACC.CHILDID_SELF:
+ e.detail = ACC.ROLE_CLIENT_AREA;
+ break;
+ case 0:
+ e.detail = ACC.ROLE_TOOLTIP;
+ break;
+ case 1:
+ e.detail = ACC.ROLE_LABEL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void getState(AccessibleControlEvent e) {
+ e.detail = ACC.STATE_FOCUSABLE;
+ if (e.childID == ACC.CHILDID_SELF) {
+ e.detail |= ACC.STATE_FOCUSED;
+ } else {
+ e.detail |= ACC.STATE_SELECTABLE;
+ if (e.childID == fFocusedWidget) {
+ e.detail |= ACC.STATE_FOCUSED | ACC.STATE_SELECTED | ACC.STATE_CHECKED;
+ }
+ }
+ }
+ });
+
+ getViewControl().addTraverseListener(new LocalTraverseListener());
+
+ addTraverseListener(new LocalTraverseListener());
+
+ getViewControl().addFocusListener(new FocusListener() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ redraw();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ redraw();
+ }
+ });
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Sets the focus widget
+ *
+ * @param newFocusShape widget reference to set
+ */
+ void setFocus(int newFocusShape) {
+ fFocusedWidget = newFocusShape;
+ if (fFocusedWidget == -1) {
+ getViewControl().getAccessible().setFocus(ACC.CHILDID_SELF);
+ } else {
+ getViewControl().getAccessible().setFocus(fFocusedWidget);
+ }
+ }
+
+ /**
+ * Sets the current frame.
+ *
+ * @param theFrame The frame to set
+ */
+ public void setFrame(Frame theFrame) {
+ fFrame = theFrame;
+ fMinTime = fFrame.getMinTime();
+ fMaxTime = fFrame.getMaxTime();
+ }
+
+ @Override
+ protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
+ if (fFrame == null) {
+ return;
+ }
+ fNodeList = new ArrayList<>();
+ int messageArraysStep = 1;
+
+ if ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * fZoomValue < Metrics.MESSAGE_SIGNIFICANT_VSPACING + 1) {
+ messageArraysStep = Math.round(Metrics.MESSAGE_SIGNIFICANT_VSPACING + 1 / ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * fZoomValue));
+ }
+
+ int firstVisible = fFrame.getFirstVisibleSyncMessage();
+ if (firstVisible > 0) {
+ firstVisible = firstVisible - 1;
+ }
+ for (int i = firstVisible; i < fFrame.syncMessageCount(); i = i + messageArraysStep) {
+ SyncMessage m = fFrame.getSyncMessage(i);
+ if (m.hasTimeInfo()) {
+ SDTimeEvent t = new SDTimeEvent(m.getStartTime(), m.getEventOccurrence(), m);
+ fNodeList.add(t);
+ if (m.getY() * fZoomValue > getContentsY() + getVisibleHeight()) {
+ break;
+ }
+ }
+ }
+
+ firstVisible = fFrame.getFirstVisibleSyncMessageReturn();
+ if (firstVisible > 0) {
+ firstVisible = firstVisible - 1;
+ }
+ for (int i = firstVisible; i < fFrame.syncMessageReturnCount(); i = i + messageArraysStep) {
+ SyncMessage m = fFrame.getSyncMessageReturn(i);
+ if (m.hasTimeInfo()) {
+ SDTimeEvent t = new SDTimeEvent(m.getStartTime(), m.getEventOccurrence(), m);
+ fNodeList.add(t);
+ if (m.getY() * fZoomValue > getContentsY() + getVisibleHeight()) {
+ break;
+ }
+ }
+ }
+
+ firstVisible = fFrame.getFirstVisibleAsyncMessage();
+ if (firstVisible > 0) {
+ firstVisible = firstVisible - 1;
+ }
+ for (int i = firstVisible; i < fFrame.asyncMessageCount(); i = i + messageArraysStep) {
+ AsyncMessage m = fFrame.getAsyncMessage(i);
+ if (m.hasTimeInfo()) {
+ SDTimeEvent t = new SDTimeEvent(m.getStartTime(), m.getStartOccurrence(), m);
+ fNodeList.add(t);
+ t = new SDTimeEvent(m.getEndTime(), m.getEndOccurrence(), m);
+ fNodeList.add(t);
+ if (m.getY() * fZoomValue > getContentsY() + getVisibleHeight()) {
+ break;
+ }
+ }
+ }
+
+ firstVisible = fFrame.getFirstVisibleAsyncMessageReturn();
+ if (firstVisible > 0) {
+ firstVisible = firstVisible - 1;
+ }
+ for (int i = firstVisible; i < fFrame.asyncMessageReturnCount(); i = i + messageArraysStep) {
+ AsyncMessageReturn m = fFrame.getAsyncMessageReturn(i);
+ if (m.hasTimeInfo()) {
+ SDTimeEvent t = new SDTimeEvent(m.getStartTime(), m.getStartOccurrence(), m);
+ fNodeList.add(t);
+ t = new SDTimeEvent(m.getEndTime(), m.getEndOccurrence(), m);
+ fNodeList.add(t);
+ if (m.getY() * fZoomValue > getContentsY() + getVisibleHeight()) {
+ break;
+ }
+ }
+ }
+
+ List<SDTimeEvent> executionOccurrencesWithTime = fFrame.getExecutionOccurrencesWithTime();
+ if (executionOccurrencesWithTime != null) {
+ fNodeList.addAll(executionOccurrencesWithTime);
+ }
+
+ SDTimeEvent[] temp = fNodeList.toArray(new SDTimeEvent[fNodeList.size()]);
+ Arrays.sort(temp, new TimeEventComparator());
+ fNodeList = Arrays.asList(temp);
+
+ Image dbuffer = new Image(getDisplay(), getClientArea().width, getClientArea().height);
+ GC gcim = new GC(dbuffer);
+
+ for (int i = 0; i < fNodeList.size() - 1; i++) {
+ SDTimeEvent m1 = fNodeList.get(i);
+ SDTimeEvent m2 = fNodeList.get(i + 1);
+
+ if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ fMinTime = fFrame.getMinTime();
+ fMaxTime = fFrame.getMaxTime();
+ ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
+ double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
+
+ ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime()).getDelta(fMinTime);
+ long absDelta = Math.abs(delta.getValue());
+
+ ColorImpl color;
+ if (gr != 0) {
+ int colIndex = Math.round((float) (absDelta / gr));
+ if (colIndex < fColors.length && colIndex > 0) {
+ color = fColors[colIndex - 1];
+ } else if (colIndex <= 0) {
+ color = fColors[0];
+ } else {
+ color = fColors[fColors.length - 1];
+ }
+ } else {
+ color = fColors[0];
+ }
+
+ if (color.getColor() instanceof Color) {
+ gcim.setBackground((Color) color.getColor());
+ }
+ int y1 = ((GraphNode) m1.getGraphNode()).getY();
+ int y2 = ((GraphNode) m2.getGraphNode()).getY();
+ if (m1.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m1.getGraphNode();
+ if (as.getEndTime() == m1.getTime()) {
+ y1 += as.getHeight();
+ }
+ }
+ if (m2.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m2.getGraphNode();
+ if (as.getEndTime() == m2.getTime()) {
+ y2 += as.getHeight();
+ }
+ }
+ if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ if (m1.getEvent() == eo.getEndOccurrence()) {
+ y1 += eo.getHeight();
+ }
+
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+
+ ExecutionOccurrence eo2 = (ExecutionOccurrence) m2.getGraphNode();
+ if (m2.getEvent() == eo2.getEndOccurrence()) {
+ y2 += eo2.getHeight();
+ }
+
+ }
+ }
+ gcim.fillRectangle(contentsToViewX(0), contentsToViewY(Math.round(y1 * fZoomValue)), 10, Math.round((y2 - y1) * fZoomValue) + 1);
+ if (messageArraysStep == 1) {
+ Color backupColor = gcim.getForeground();
+ gcim.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
+ gcim.drawRectangle(contentsToViewX(0), contentsToViewY(Math.round(y1 * fZoomValue)), 9, Math.round((y2 - y1) * fZoomValue));
+ gcim.setForeground(backupColor);
+ }
+ }
+ if (getViewControl().isFocusControl() || isFocusControl()) {
+ gcim.drawFocus(contentsToViewX(0), contentsToViewY(Math.round(fPrevNodeY * fZoomValue)), contentsToViewX(10), Math.round((fNextNodeY - fPrevNodeY) * fZoomValue));
+ }
+ try {
+ gc.drawImage(dbuffer, 0, 0, getClientArea().width, getClientArea().height, 0, 0, getClientArea().width, getClientArea().height);
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error drawing image", e); //$NON-NLS-1$
+ }
+ gcim.dispose();
+ dbuffer.dispose();
+ gc.dispose();
+ }
+
+ /**
+ * Checks for focus of children.
+ *
+ * @param children
+ * Control to check
+ * @return true if child is on focus else false
+ */
+ protected boolean checkFocusOnChilds(Control children) {
+ if (children instanceof Composite) {
+ Control[] child = ((Composite) children).getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ return true;
+ }
+ checkFocusOnChilds(child[i]);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isFocusControl() {
+ Control[] child = getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ return true;
+ }
+ checkFocusOnChilds(child[i]);
+ }
+ return false;
+ }
+
+ @Override
+ protected void contentsMouseMoveEvent(MouseEvent event) {
+ if (fTooltip != null) {
+ fTooltip.hideToolTip();
+ }
+ super.contentsMouseMoveEvent(event);
+ if (!isFocusControl() || getViewControl().isFocusControl()) {
+ Control[] child = getParent().getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ break;
+ }
+ }
+ }
+ setFocus(-1);
+ }
+
+ @Override
+ protected void contentsMouseHover(MouseEvent e) {
+ if (fTooltip == null) {
+ fTooltip = new DrawableToolTip(this);
+ }
+ if (fFrame != null) {
+ setFocus(0);
+ for (int i = 0; i < fNodeList.size() - 1; i++) {
+ SDTimeEvent m1 = fNodeList.get(i);
+ SDTimeEvent m2 = fNodeList.get(i + 1);
+
+ if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ int y1 = ((GraphNode) m1.getGraphNode()).getY();
+ int y2 = ((GraphNode) m2.getGraphNode()).getY();
+
+ if (m1.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m1.getGraphNode();
+ if (as.getEndTime() == m1.getTime()) {
+ y1 += as.getHeight();
+ }
+ }
+ if (m2.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m2.getGraphNode();
+ if (as.getEndTime() == m2.getTime()) {
+ y2 += as.getHeight();
+ }
+ }
+ if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ if (m1.getEvent() == eo.getEndOccurrence()) {
+ y1 += eo.getHeight();
+ }
+
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+
+ ExecutionOccurrence eo2 = (ExecutionOccurrence) m2.getGraphNode();
+ if (m2.getEvent() == eo2.getEndOccurrence()) {
+ y2 += eo2.getHeight();
+ }
+ }
+ }
+ int m1Y = Math.round(y1 * fZoomValue);
+ int m2Y = Math.round(y2 * fZoomValue);
+ if ((m1Y < e.y) && (m2Y >= e.y)) {
+ ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime());
+ fTooltip.showToolTip(delta, fMinTime, fMaxTime);
+ }
+ }
+ }
+ setFocus(0);
+ }
+
+ @Override
+ protected void contentsMouseExit(MouseEvent e) {
+ if (fTooltip != null) {
+ fTooltip.hideToolTip();
+ }
+ }
+
+ @Override
+ protected void contentsMouseUpEvent(MouseEvent event) {
+ selectTimeDelta(event.y, 0);
+ setFocus();
+ super.contentsMouseUpEvent(event);
+ }
+
+ /**
+ * Force the time compression bar to highlight the event occurrences between
+ * the two given messages. The event occurrences are highlighted on the
+ * first message's end lifeline
+ *
+ * @param mes1
+ * the first message
+ * @param mes2
+ * the second message
+ */
+ public void highlightRegion(BaseMessage mes1, BaseMessage mes2) {
+ BaseMessage localMes1 = mes1;
+ BaseMessage localMes2 = mes2;
+
+ if (fFrame == null) {
+ return;
+ }
+ if (!(localMes1 instanceof ITimeRange)) {
+ return;
+ }
+ if (!(localMes2 instanceof ITimeRange)) {
+ return;
+ }
+ ITimeRange t1 = (ITimeRange) localMes1;
+ ITimeRange t2 = (ITimeRange) localMes2;
+
+ ITmfTimestamp time1 = t1.getStartTime();
+ ITmfTimestamp time2 = t2.getStartTime();
+ int event1 = localMes1.getEventOccurrence();
+ int event2 = localMes2.getEventOccurrence();
+
+ if (localMes1 instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) localMes1;
+ time1 = as.getEndTime();
+ event1 = as.getEndOccurrence();
+ }
+ if (localMes2 instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) localMes2;
+ if (as.getEndOccurrence() > as.getStartOccurrence()) {
+ time1 = as.getEndTime();
+ event1 = as.getEndOccurrence();
+ } else {
+ time1 = as.getStartTime();
+ event1 = as.getStartOccurrence();
+ }
+ }
+
+ if (event1 > event2) {
+ BaseMessage tempMes = localMes2;
+ localMes2 = localMes1;
+ localMes1 = tempMes;
+
+ t1 = (ITimeRange) localMes1;
+ t2 = (ITimeRange) localMes2;
+
+ time1 = t1.getStartTime();
+ time2 = t2.getStartTime();
+ event1 = localMes1.getEventOccurrence();
+ event2 = localMes2.getEventOccurrence();
+
+ if (localMes1 instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) localMes1;
+ time1 = as.getEndTime();
+ event1 = as.getEndOccurrence();
+ }
+ if (localMes2 instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) localMes2;
+ if (as.getEndOccurrence() > as.getStartOccurrence()) {
+ time1 = as.getEndTime();
+ event1 = as.getEndOccurrence();
+ } else {
+ time1 = as.getStartTime();
+ event1 = as.getStartOccurrence();
+ }
+ }
+ }
+
+ ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
+ double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
+
+ ITmfTimestamp delta = time2.getDelta(time1).getDelta(fMinTime);
+ long absDelta = Math.abs(delta.getValue());
+
+ int colIndex = 0;
+ if (gr != 0) {
+ colIndex = Math.round((float) (absDelta / gr));
+ if (colIndex >= fColors.length) {
+ colIndex = fColors.length - 1;
+ } else if (colIndex < 0) {
+ colIndex = 0;
+ }
+ } else {
+ colIndex = 0;
+ }
+ for (int j = 0; j < fListenerList.size(); j++) {
+ ITimeCompressionListener list = fListenerList.get(j);
+ if (localMes1.getEndLifeline() != null) {
+ list.deltaSelected(localMes1.getEndLifeline(), event1, event2 - event1, fColors[colIndex]);
+ } else if (localMes2.getStartLifeline() != null) {
+ list.deltaSelected(localMes2.getStartLifeline(), event1, event2 - event1, fColors[colIndex]);
+ } else {
+ list.deltaSelected(localMes1.getStartLifeline(), event1, event2 - event1, fColors[colIndex]);
+ }
+ }
+ }
+
+ /**
+ * Force the time compression bar to highlight the event occurrences between the two given messages. The event
+ * occurrences are highlighted on the first message's end lifeline
+ *
+ * @param mes1 the first message
+ * @param mes2 the second message
+ */
+ public void highlightRegionSync(final BaseMessage mes1, final BaseMessage mes2) {
+ getDisplay().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ highlightRegion(mes1, mes2);
+ }
+ });
+ }
+
+ @Override
+ public void scrollBy(int x, int y) {
+ }
+
+ /**
+ * Sets the zoom value.
+ *
+ * @param value The zoom value to set.
+ */
+ public void setZoom(float value) {
+ fZoomValue = value;
+ redraw();
+ }
+
+ /**
+ * Adds a listener to the time compression listener list to be notified about selected deltas.
+ *
+ * @param listener The listener to add
+ */
+ public void addTimeCompressionListener(ITimeCompressionListener listener) {
+ if (!fListenerList.contains(listener)) {
+ fListenerList.add(listener);
+ }
+ }
+
+ /**
+ * Removes a time compression listener.
+ *
+ * @param listener The listener to remove.
+ */
+ public void removeSelectionChangedListener(ITimeCompressionListener listener) {
+ fListenerList.remove(listener);
+ }
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ if (fTooltip != null) {
+ fTooltip.dispose();
+ }
+ super.removeDisposeListener(this);
+ for (int i = 0; i < fColors.length; i++) {
+ fColors[i].dispose();
+ }
+ }
+
+ @Override
+ protected void keyPressedEvent(KeyEvent event) {
+ if (fTooltip != null) {
+ fTooltip.hideToolTip();
+ }
+ if (!isFocusControl() || getViewControl().isFocusControl()) {
+ Control[] child = getParent().getChildren();
+ for (int i = 0; i < child.length; i++) {
+ if (child[i].isFocusControl()) {
+ break;
+ }
+ }
+ }
+ setFocus(-1);
+
+ boolean top = false;
+ if (fNextNodeY == 0) {
+ top = true;
+ }
+ if ((fFrame != null) && (fNextNodeY == 0)) {
+ for (int i = 0; i < fNodeList.size() - 1 && i < 1; i++) {
+ SDTimeEvent m1 = fNodeList.get(i);
+ SDTimeEvent m2 = fNodeList.get(i + 1);
+ if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ int y1 = ((GraphNode) m1.getGraphNode()).getY();
+ int y2 = ((GraphNode) m2.getGraphNode()).getY();
+ if (m1.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m1.getGraphNode();
+ if (as.getEndTime() == m1.getTime()) {
+ y1 += as.getHeight();
+ }
+ }
+ if (m2.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m2.getGraphNode();
+ if (as.getEndTime() == m2.getTime()) {
+ y2 += as.getHeight();
+ }
+ }
+ if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ if (m1.getEvent() == eo.getEndOccurrence()) {
+ y1 += eo.getHeight();
+ }
+
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+
+ ExecutionOccurrence eo2 = (ExecutionOccurrence) m2.getGraphNode();
+ if (m2.getEvent() == eo2.getEndOccurrence()) {
+ y2 += eo2.getHeight();
+ }
+ }
+ }
+ fPrevNodeY = Math.round(y1 * fZoomValue);
+ fNextNodeY = Math.round(y2 * fZoomValue);
+ }
+ }
+
+ if (fLifeline != null) {
+ for (int j = 0; j < fListenerList.size(); j++) {
+ ITimeCompressionListener list = fListenerList.get(j);
+ list.deltaSelected(fLifeline, fLifelineStart, fLifelineNumEvents, fLifelineColor);
+ }
+ }
+
+ if (event.keyCode == SWT.ARROW_DOWN) {
+ if (!top) {
+ selectTimeDelta(fNextNodeY + 1, 1);
+ } else {
+ selectTimeDelta(fPrevNodeY + 1, 1);
+ }
+ setFocus(1);
+ } else if (event.keyCode == SWT.ARROW_UP) {
+ selectTimeDelta(fPrevNodeY - 1, 2);
+ setFocus(1);
+ } else if (event.keyCode == SWT.ARROW_RIGHT) {
+ selectTimeDelta(fPrevNodeY, 1);
+ setFocus(1);
+ }
+ super.keyPressedEvent(event);
+ }
+
+ /**
+ * Selects the time delta for given delta y coordinate and direction.
+ *
+ * @param dy The delta in y coordinate.
+ * @param direction 0 no direction, 1 = down, 2 = up
+ */
+ protected void selectTimeDelta(int dy, int direction) {
+ SDTimeEvent lastM1 = null;
+ SDTimeEvent lastM2 = null;
+ int lastY1 = 0;
+ int lastY2 = 0;
+ boolean done = false;
+ if (fFrame != null) {
+ for (int i = 0; i < fNodeList.size() - 1; i++) {
+ SDTimeEvent m1 = fNodeList.get(i);
+ SDTimeEvent m2 = fNodeList.get(i + 1);
+ if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ int y1 = ((GraphNode) m1.getGraphNode()).getY();
+ int y2 = ((GraphNode) m2.getGraphNode()).getY();
+ if (m1.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m1.getGraphNode();
+ if (as.getEndTime() == m1.getTime()) {
+ y1 += as.getHeight();
+ }
+ }
+ if (m2.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m2.getGraphNode();
+ if (as.getEndTime() == m2.getTime()) {
+ y2 += as.getHeight();
+ }
+ }
+ if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ if (m1.getEvent() == eo.getEndOccurrence()) {
+ y1 += eo.getHeight();
+ }
+
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo2 = (ExecutionOccurrence) m2.getGraphNode();
+ if (m2.getEvent() == eo2.getEndOccurrence()) {
+ y2 += eo2.getHeight();
+ }
+ }
+ }
+ int m1Y = Math.round(y1 * fZoomValue);
+ int m2Y = Math.round(y2 * fZoomValue);
+
+ if ((m1Y < dy) && (m2Y > dy) || (!done && m2Y > dy && direction == 1 && lastM1 != null) || (!done && m1Y > dy && direction == 2 && lastM1 != null)) {
+ if (m1Y > dy && direction == 2) {
+ m1 = lastM1;
+ m2 = lastM2;
+ m1Y = lastY1;
+ m2Y = lastY2;
+ }
+ done = true;
+ fPrevNodeY = m1Y;
+ fNextNodeY = m2Y;
+ ITmfTimestamp minMaxdelta = fMaxTime.getDelta(fMinTime);
+ double gr = (minMaxdelta.getValue()) / (double) NUMBER_STEPS;
+
+ ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime()).getDelta(fMinTime);
+ long absDelta = Math.abs(delta.getValue());
+
+ int colIndex = 0;
+ if (gr != 0) {
+ colIndex = Math.round((float) (absDelta / gr));
+ if (colIndex >= fColors.length) {
+ colIndex = fColors.length - 1;
+ } else if (colIndex < 0) {
+ colIndex = 0;
+ }
+ } else {
+ colIndex = 0;
+ }
+ if (m1.getGraphNode() instanceof BaseMessage) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ if (mes1.getEndLifeline() != null) {
+ fLifeline = mes1.getEndLifeline();
+ fLifelineStart = m1.getEvent();
+ fLifelineNumEvents = m2.getEvent() - m1.getEvent();
+ fLifelineColor = fColors[colIndex];
+ } else if (m2.getGraphNode() instanceof BaseMessage && ((BaseMessage) m2.getGraphNode()).getStartLifeline() != null) {
+ fLifeline = ((BaseMessage) m2.getGraphNode()).getStartLifeline();
+ fLifelineStart = m1.getEvent();
+ fLifelineNumEvents = m2.getEvent() - m1.getEvent();
+ fLifelineColor = fColors[colIndex];
+ } else {
+ fLifeline = mes1.getStartLifeline();
+ fLifelineStart = m1.getEvent();
+ fLifelineNumEvents = m2.getEvent() - m1.getEvent();
+ fLifelineColor = fColors[colIndex];
+ }
+ } else if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m2.getGraphNode();
+ fLifeline = eo.getLifeline();
+ fLifelineStart = m1.getEvent();
+ fLifelineNumEvents = m2.getEvent() - m1.getEvent();
+ fLifelineColor = fColors[colIndex];
+ } else {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ fLifeline = eo.getLifeline();
+ fLifelineStart = m1.getEvent();
+ fLifelineNumEvents = m2.getEvent() - m1.getEvent();
+ fLifelineColor = fColors[colIndex];
+ }
+ }
+ for (int j = 0; j < fListenerList.size(); j++) {
+ ITimeCompressionListener list = fListenerList.get(j);
+ list.deltaSelected(fLifeline, fLifelineStart, fLifelineNumEvents, fLifelineColor);
+ }
+ break;
+ }
+ lastM1 = m1;
+ lastM2 = m2;
+ lastY1 = m1Y;
+ lastY2 = m2Y;
+ }
+ }
+ }
+
+ /**
+ * Creates a fake tool tip.
+ */
+ protected void createFakeTooltip() {
+ if (fTooltip == null) {
+ fTooltip = new DrawableToolTip(this);
+ }
+
+ if (fFrame != null) {
+ setFocus(0);
+ for (int i = 0; i < fNodeList.size() - 1; i++) {
+ SDTimeEvent m1 = fNodeList.get(i);
+ SDTimeEvent m2 = fNodeList.get(i + 1);
+
+ if ((SDViewPref.getInstance().excludeExternalTime()) && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ int y1 = ((GraphNode) m1.getGraphNode()).getY();
+ int y2 = ((GraphNode) m2.getGraphNode()).getY();
+
+ if (m1.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m1.getGraphNode();
+ if (as.getEndTime() == m1.getTime()) {
+ y1 += as.getHeight();
+ }
+ }
+ if (m2.getGraphNode() instanceof AsyncMessage) {
+ AsyncMessage as = (AsyncMessage) m2.getGraphNode();
+ if (as.getEndTime() == m2.getTime()) {
+ y2 += as.getHeight();
+ }
+ }
+ if (m1.getGraphNode() instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) m1.getGraphNode();
+ if (m1.getEvent() == eo.getEndOccurrence()) {
+ y1 += eo.getHeight();
+ }
+
+ if (m2.getGraphNode() instanceof ExecutionOccurrence) {
+
+ ExecutionOccurrence eo2 = (ExecutionOccurrence) m2.getGraphNode();
+ if (m2.getEvent() == eo2.getEndOccurrence()) {
+ y2 += eo2.getHeight();
+ }
+ }
+ }
+ int m1Y = Math.round(y1 * fZoomValue);
+ int m2Y = Math.round(y2 * fZoomValue);
+ if ((m1Y < fPrevNodeY + 1) && (m2Y >= fPrevNodeY + 1)) {
+ ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime());
+ fTooltip.showToolTip(delta, fMinTime, fMaxTime);
+ fTooltip.hideToolTip();
+ }
+ }
+ }
+ }
+
+ /**
+ * Traverse Listener implementation.
+ */
+ protected static class LocalTraverseListener implements TraverseListener {
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
+ e.doit = true;
+ }
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessage.java
new file mode 100755
index 0000000000..2355b482be
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessage.java
@@ -0,0 +1,469 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.SortAsyncForBackward;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.SortAsyncMessageComparator;
+
+/**
+ * A AsyncMessage is a asynchronous message which appear at two different event occurrences on each lifeline ends (sender
+ * and receiver).<br>
+ * <br>
+ * <br>
+ * Usage example:
+ *
+ * <pre>
+ * Frame frame;
+ * Lifeline lifeLine1;
+ * Lifeline lifeLine2;
+ *
+ * AsyncMessage message = new AsyncMessage();
+ * // Create a new event occurrence on each lifeline
+ * lifeline1.getNewOccurrenceIndex();
+ * lifeline2.getNewOccurrenceIndex();
+ * // Set the message sender and receiver
+ * message.setStartLifeline(lifeLine1);
+ * message.setEndLifline(lifeline2);
+ * message.setName(&quot;Message label&quot;);
+ * // add the message to the frame
+ * frame.addMessage(message);
+ * </pre>
+ *
+ * @see Lifeline Lifeline for more event occurence details
+ * @version 1.0
+ * @author sveyrier
+ * @since 2.0
+ */
+public class AsyncMessage extends BaseMessage implements ITimeRange {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The grahNode ID constant
+ */
+ public static final String ASYNC_MESS_TAG = "AsyncMessage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Flag whether message has time information or not.
+ */
+ private boolean fHasTime = false;
+ /**
+ * The time when the message begin
+ */
+ private ITmfTimestamp fEndTime = new TmfTimestamp();
+ /**
+ * The time when the message end
+ */
+ private ITmfTimestamp fStartTime = new TmfTimestamp();
+ /**
+ * The associated message.
+ */
+ protected AsyncMessageReturn fMessageReturn = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public AsyncMessage() {
+ setColorPrefId(ISDPreferences.PREF_ASYNC_MESS);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int getX() {
+ int x = super.getX(true);
+ int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ if ((getStartLifeline() != null) && (getEndLifeline() != null) && (getStartLifeline().getX() > getEndLifeline().getX())) {
+ activationWidth = -activationWidth;
+ }
+
+ if (isMessageStartInActivation(getStartOccurrence())) {
+ x = x + activationWidth;
+ }
+ return x;
+ }
+
+ @Override
+ public int getY() {
+ if ((getStartLifeline() != null) && (getEndLifeline() != null)) {
+ return getEndLifeline().getY() + getEndLifeline().getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getStartOccurrence();
+ }
+ return super.getY();
+ }
+
+ @Override
+ public int getWidth() {
+ int width = super.getWidth(true);
+ int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ if ((getStartLifeline() != null) && (getEndLifeline() != null) && (getStartLifeline().getX() > getEndLifeline().getX())) {
+ activationWidth = -activationWidth;
+ }
+
+ if (isMessageStartInActivation(getStartOccurrence())) {
+ width = width - activationWidth;
+ }
+
+ if (isMessageEndInActivation(getEndOccurrence())) {
+ width = width - activationWidth;
+ }
+
+ return width;
+ }
+
+ @Override
+ public int getHeight() {
+ if ((getStartLifeline() != null) && (getEndLifeline() != null)) {
+ return (getEndLifeline().getY() + getEndLifeline().getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence()) - getY();
+ }
+ return super.getHeight();
+ }
+
+ /**
+ * Set the message return associated with this message.
+ *
+ * @param message the message return to associate
+ */
+ protected void setMessageReturn(AsyncMessageReturn message) {
+ fMessageReturn = message;
+ }
+
+ /**
+ * Set the event occurrence attached to this message for its end lifeline
+ *
+ * @param occurrence the event occurrence to set
+ */
+ @Override
+ public void setEndOccurrence(int occurrence) {
+ super.setEndOccurrence(occurrence);
+ if (getStartLifeline() == null) {
+ setStartOccurrence(occurrence);
+ }
+ informFrame(getEndLifeline(), occurrence);
+ }
+
+ /**
+ * Informs the given lifeline about the maximum occurrence if applicable.
+ *
+ * @param lifeLine
+ * Concerned lifeline
+ * @param occurrence
+ * Occurrence number
+ */
+ protected void informFrame(Lifeline lifeLine, int occurrence) {
+ if ((lifeLine != null) && (lifeLine.getFrame() != null) && (lifeLine.getFrame().getMaxEventOccurrence() < occurrence)) {
+ lifeLine.getFrame().setMaxEventOccurrence(occurrence);
+ }
+ }
+
+ /**
+ * Set the event occurrence attached to this message for its start lifeline
+ *
+ * @param occurrence the event occurrence to set
+ */
+ @Override
+ public void setStartOccurrence(int occurrence) {
+ super.setStartOccurrence(occurrence);
+ if (getEndLifeline() == null) {
+ setEndOccurrence(getStartOccurrence());
+ }
+ informFrame(getStartLifeline(), occurrence);
+ }
+
+ /**
+ * Set the lifeLine which has sent the message.<br>
+ * A new EventOccurence will be create on this lifeLine.<br>
+ *
+ * @param lifeline the message sender
+ */
+ public void autoSetStartLifeline(Lifeline lifeline) {
+ lifeline.getNewEventOccurrence();
+ setStartLifeline(lifeline);
+ }
+
+ /**
+ * Set the lifeLine which has received the message.<br>
+ * A new EventOccurence will be create on this lifeLine.<br>
+ *
+ * @param lifeline the message receiver
+ */
+ public void autoSetEndLifeline(Lifeline lifeline) {
+ lifeline.getNewEventOccurrence();
+ setEndLifeline(lifeline);
+ }
+
+ @Override
+ public void setStartLifeline(Lifeline lifeline) {
+ super.setStartLifeline(lifeline);
+ setStartOccurrence(getStartLifeline().getEventOccurrence());
+ if (getEndLifeline() == null) {
+ setEndOccurrence(getStartOccurrence());
+ }
+ }
+
+ @Override
+ public void setEndLifeline(Lifeline lifeline) {
+ super.setEndLifeline(lifeline);
+ setEventOccurrence(getEndLifeline().getEventOccurrence());
+ }
+
+ /**
+ * Returns true if the point C is on the segment defined with the point A and B
+ *
+ * @param xA point A x coordinate
+ * @param yA point A y coordinate
+ * @param xB point B x coordinate
+ * @param yB point B y coordinate
+ * @param xC point C x coordinate
+ * @param yC point C y coordinate
+ * @return Return true if the point C is on the segment defined with the point A and B, else otherwise
+ */
+ protected boolean isNearSegment(int xA, int yA, int xB, int yB, int xC, int yC) {
+ if ((xA > xB) && (xC > xA)) {
+ return false;
+ }
+ if ((xA < xB) && (xC > xB)) {
+ return false;
+ }
+ if ((xA < xB) && (xC < xA)) {
+ return false;
+ }
+ if ((xA > xB) && (xC < xB)) {
+ return false;
+ }
+ double distAB = Math.sqrt((xB - xA) * (xB - xA) + (yB - yA) * (yB - yA));
+ double scalar = ((xB - xA) * (xC - xA) + (yB - yA) * (yC - yA)) / distAB;
+ double distAC = Math.sqrt((xC - xA) * (xC - xA) + (yC - yA) * (yC - yA));
+ double distToSegment = Math.sqrt(Math.abs(distAC * distAC - scalar * scalar));
+ if (distToSegment <= Metrics.MESSAGE_SELECTION_TOLERANCE) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean contains(int x, int y) {
+ // Is it a self message?
+ if (getStartLifeline() == getEndLifeline()) {
+ return super.contains(x, y);
+ }
+ if (isNearSegment(getX(), getY(), getX() + getWidth(), getY() + getHeight(), x, y)) {
+ return true;
+ }
+ int messageMaxWidth = Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH;
+ int nameWidth = getName().length() * Metrics.getAverageCharWidth();
+ if (getName().length() * Metrics.getAverageCharWidth() > messageMaxWidth) {
+ if (GraphNode.contains(getX(), getY() - Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), messageMaxWidth, Metrics.getMessageFontHeigth(), x, y)) {
+ return true;
+ }
+ } else {
+ if (GraphNode.contains(getX() + (messageMaxWidth - nameWidth) / 2, getY() + getHeight() / 2 - Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), nameWidth, Metrics.getMessageFontHeigth(), x, y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Draws the asynchronous message using giving graphical context.
+ *
+ * @param context A graphical context to draw in.
+ */
+ protected void drawAsyncMessage(IGC context) {
+ if (getStartLifeline() != null && getEndLifeline() != null && getStartLifeline() == getEndLifeline() && (getStartOccurrence() != getEndOccurrence())) {
+ int x = getX();
+ int y = getY();
+ int height = getHeight();
+ int tempx = 0;
+ boolean startInActivation = isMessageStartInActivation(getStartOccurrence());
+ boolean endInActivation = isMessageEndInActivation(getEndOccurrence());
+
+ if (endInActivation && !startInActivation) {
+ tempx = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ }
+ if (startInActivation && !endInActivation) {
+ tempx = -Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ }
+
+ int tempy = Metrics.INTERNAL_MESSAGE_WIDTH / 2;
+ if (getHeight() <= Metrics.INTERNAL_MESSAGE_WIDTH) {
+ tempy = getHeight() / 2;
+ }
+
+ context.drawLine(x, y, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y);
+ context.drawLine(x + Metrics.INTERNAL_MESSAGE_WIDTH, y + tempy, x + Metrics.INTERNAL_MESSAGE_WIDTH, y + height - tempy);
+ context.drawLine(x + tempx, y + height, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y + height);
+
+ Double xt = Double.valueOf(Math.cos(0.75) * 7);
+ Double yt = Double.valueOf(Math.sin(0.75) * 7);
+
+ context.drawLine(x + xt.intValue() + tempx, y + height + yt.intValue(), x + tempx, y + height);
+ context.drawArc(x, y, Metrics.INTERNAL_MESSAGE_WIDTH, 2 * tempy, 0, 90);
+ context.drawArc(x, y + height, Metrics.INTERNAL_MESSAGE_WIDTH, -2 * tempy, 0, -90);
+ context.drawLine(x + xt.intValue() + tempx, y + height - yt.intValue(), x + tempx, y + height);
+
+ context.drawTextTruncated(getName(), x + Metrics.INTERNAL_MESSAGE_WIDTH + Metrics.INTERNAL_MESSAGE_V_MARGIN, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH,
+ +Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), !isSelected());
+ } else {
+ super.draw(context);
+ }
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // Draw it selected?
+ if (isSelected() && (getStartLifeline() != null && getEndLifeline() != null && getStartLifeline() == getEndLifeline() && (getStartOccurrence() != getEndOccurrence()))) {
+ /*
+ * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection
+ * colors This create the highlight effect
+ */
+ context.setForeground(pref.getBackGroundColorSelection());
+ context.setLineWidth(Metrics.SELECTION_LINE_WIDTH);
+ drawAsyncMessage(context);
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ // Second drawing is done after the else
+ } else {
+ context.setBackground(pref.getBackGroundColor(getColorPrefId()));
+ context.setForeground(pref.getForeGroundColor(getColorPrefId()));
+ }
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(true);
+ }
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ drawAsyncMessage(context);
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(false);
+ }
+ }
+
+ /**
+ * Set the time when the message end
+ *
+ * @param time the time when the message end
+ * @since 2.0
+ */
+ public void setEndTime(ITmfTimestamp time) {
+ fEndTime = time;
+ fHasTime = true;
+ if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
+ getStartLifeline().getFrame().setHasTimeInfo(true);
+ } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
+ getEndLifeline().getFrame().setHasTimeInfo(true);
+ }
+ }
+
+ /**
+ * Set the time when the message start
+ *
+ * @param time the time when the message start
+ * @since 2.0
+ */
+ public void setStartTime(ITmfTimestamp time) {
+ fStartTime = time;
+ fHasTime = true;
+ if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
+ getStartLifeline().getFrame().setHasTimeInfo(true);
+ } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
+ getEndLifeline().getFrame().setHasTimeInfo(true);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getEndTime() {
+ return fEndTime;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getStartTime() {
+ return fStartTime;
+ }
+
+ @Override
+ public boolean hasTimeInfo() {
+ return fHasTime;
+ }
+
+ /**
+ * @return message return instance or null
+ * @since 2.0
+ */
+ public AsyncMessageReturn getMessageReturn() {
+ return fMessageReturn;
+ }
+
+ @Override
+ public boolean isVisible(int x, int y, int width, int height) {
+ int toDrawY = getY();
+ int toDrawHeight = getHeight();
+ if ((toDrawY > y + height + Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()) && (toDrawY + toDrawHeight > y + height + Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth())) {
+ return false;
+ }
+ if (toDrawY < y && (toDrawY + toDrawHeight < y)) {
+ return false;
+ }
+ return super.isVisible(x, y, width, height);
+ }
+
+ @Override
+ public Comparator<GraphNode> getComparator() {
+ return new SortAsyncMessageComparator();
+ }
+
+ @Override
+ public String getArrayId() {
+ return ASYNC_MESS_TAG;
+ }
+
+ @Override
+ public Comparator<GraphNode> getBackComparator() {
+ return new SortAsyncForBackward();
+ }
+
+ @Override
+ public boolean positiveDistanceToPoint(int x, int y) {
+ int mY = getY();
+ int mH = getHeight();
+ if ((mY > y) || (mY + mH > y)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessageReturn.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessageReturn.java
new file mode 100755
index 0000000000..dbc5160bca
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/AsyncMessageReturn.java
@@ -0,0 +1,112 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * The message return graph node implementation.<br>
+ * This class differs on the AsynMessage class only on the drawing line style (dashed instead of plain line).<br>
+ * Message return are generally associated to a message. This means, they are connected to the same lifelines than the
+ * associated message but in the opposite direction and for a different event occurrence.<br>
+ * <br>
+ * WARNING: The association validity is not checked, it is not necessary to provide a valid association, not even needed
+ * to set an association to drawn a message with a message return style.<br>
+ *
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage AsyncMessage for usage example
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class AsyncMessageReturn extends AsyncMessage {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The grahNode ID constant
+ */
+ public static final String ASYNC_MESS_RET_TAG = "AsyncMessageRet"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The corresponding asynchronous message.
+ */
+ protected AsyncMessage fMessage;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor.
+ */
+ public AsyncMessageReturn() {
+ setColorPrefId(ISDPreferences.PREF_ASYNC_MESS_RET);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set the associated message (the message it is the return).<br>
+ * Setting the association will activate the navigation in the default sequence diagram implementation to the
+ * message when the user right click on this message return.<br>
+ *
+ * @param parentMessage the message to associate
+ */
+ public void setMessage(AsyncMessage parentMessage) {
+ fMessage = parentMessage;
+ }
+
+ /**
+ * Returns the associated message (the message it is the return).<br>
+ *
+ * @return parentMessage the message to associate
+ * @since 2.0
+ */
+ public AsyncMessage getMessage() {
+ return fMessage;
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ setColorPrefId(ISDPreferences.PREF_ASYNC_MESS_RET);
+ int oldStyle = context.getLineStyle();
+ // Message return are dashed
+ context.setLineStyle(context.getLineDotStyle());
+ if (!isSelected()) {
+ context.setBackground(pref.getBackGroundColor(getColorPrefId()));
+ context.setForeground(pref.getForeGroundColor(getColorPrefId()));
+ }
+ super.draw(context);
+ // restore the context
+ context.setLineStyle(oldStyle);
+ }
+
+ @Override
+ public String getArrayId() {
+ return ASYNC_MESS_RET_TAG;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BaseMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BaseMessage.java
new file mode 100755
index 0000000000..532cb51e90
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BaseMessage.java
@@ -0,0 +1,724 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * The base UML2 syncMessages implementation.<br>
+ * This abstract class only define one event occurrence to attach to the message.<br>
+ * Usually a message has two event occurrences attached, one for both ends. But some syncMessages(like synchronous
+ * syncMessages) only need one event occurrence to represent the time when they appear. Others kind of message
+ * representations (like asynchronous syncMessages) will be responsible to define the missing second eventOccurrence
+ * property.<br>
+ * <br>
+ *
+ * @see Lifeline Lifeline for more event occurence details
+ * @version 1.0
+ * @author sveyrier
+ */
+public abstract class BaseMessage extends GraphNode {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The lifeline which send the message
+ */
+ private Lifeline fStartLifeline = null;
+ /**
+ * The lifeline which receive the message
+ */
+ private Lifeline fEndLifeline = null;
+ /**
+ * The visiblitiy flag.
+ */
+ private boolean fVisible = true;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int getX() {
+ // returns the exact x coordinate
+ return getX(false);
+ }
+
+ @Override
+ public int getY() {
+ /*
+ * Note: lifeline.getY() return the y coordinate of the top left corner of the rectangle which contain the
+ * lifeline name getHeight return the height of this rectangle The message y coordinate is then relative to this
+ * position depending of its eventOccurrence Space between syncMessages is constant
+ */
+ if ((fStartLifeline != null) && (fEndLifeline != null)) {
+ /*
+ * Regular message, both ends are attached to a lifeline
+ */
+ return fEndLifeline.getY() + fEndLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence();
+
+ }
+ /*
+ * UML2 lost message kind
+ */
+ if (fStartLifeline != null) {
+ return fStartLifeline.getY() + fStartLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence();
+ }
+
+ /*
+ * UML2 found message kind
+ */
+ if (fEndLifeline != null) {
+ return fEndLifeline.getY() + fEndLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getEndOccurrence();
+ }
+ // return 0 by default
+ return 0;
+ }
+
+ @Override
+ public int getWidth() {
+ // Returns the exact width
+ return getWidth(false);
+ }
+
+ @Override
+ public int getHeight() {
+ return 0;
+ }
+
+ /**
+ * Returns the graph node x coordinate.<br>
+ * Depending on the quick parameter a approximative or exact value is return.<br>
+ * The approximative value does not take into account if both message ends are connected to a Lifeline Execution
+ * Occurrence.<br>
+ * Execution occurrence on a lifeline increase the vertical line width which represent the lifeline, this directly
+ * affect the message x coordinate and width.<br>
+ * <br>
+ * This method is typically used to faster execute none graphical operation like tooltip lookup.<br>
+ * <br>
+ *
+ * @param quick true to get an approximative value<br>
+ * false to get the exact x value<br>
+ * @return the graph node x coordinate
+ */
+ protected int getX(boolean quick) {
+ int x = 0;
+ int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ if ((fStartLifeline != null) && (fEndLifeline != null)) {
+ x = fStartLifeline.getX() + Metrics.getLifelineWidth() / 2;
+ } else {
+ if (fStartLifeline != null) {
+ x = fStartLifeline.getX() + Metrics.getLifelineWidth() / 2;
+ }
+
+ if (fEndLifeline != null) {
+ x = fEndLifeline.getX() - Metrics.LIFELINE_SPACING / 2;
+ }
+ }
+
+ if (quick) {
+ return x;
+ }
+
+ if ((fStartLifeline != null) && (fEndLifeline != null) && (fStartLifeline.getX() > fEndLifeline.getX())) {
+ activationWidth = -activationWidth;
+ }
+
+ if (isMessageStartInActivation(getEndOccurrence())) {
+ x = x + activationWidth;
+ }
+
+ return x;
+ }
+
+ /**
+ * Returns the graph node width.<br>
+ * Depending on the quick parameter a approximative or exact value is returned.<br>
+ * The approximative value does not take into account if both message ends are connected to a Lifeline Execution
+ * Occurrence.<br>
+ * Execution occurrence on a lifeline increase the vertical line width which represent the lifeline, this directly
+ * affect the message x coordinate and width.<br>
+ * <br>
+ * This method is typically used to faster execute none graphical operation like tooltip lookup.<br>
+ * <br>
+ *
+ * @param quick true to get an approximative value<br>
+ * false to get the exact x value
+ * @return the graph node width
+ */
+ protected int getWidth(boolean quick) {
+ int width = 0;
+ int activationWidth = Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ if ((fStartLifeline != null) && (fEndLifeline != null)) {
+ if (fStartLifeline == fEndLifeline) {
+ width = Metrics.INTERNAL_MESSAGE_WIDTH + Metrics.EXECUTION_OCCURRENCE_WIDTH;
+ } else {
+ width = fEndLifeline.getX() + Metrics.getLifelineWidth() / 2 - getX(true);
+ }
+ } else {
+ if (fStartLifeline != null) {
+ width = Metrics.swimmingLaneWidth() / 2;
+ }
+ if (fEndLifeline != null) {
+ width = Metrics.swimmingLaneWidth() / 2;
+ }
+ }
+
+ if (quick) {
+ return width;
+ }
+
+ if ((fStartLifeline != null) && (fEndLifeline != null) && (fStartLifeline.getX() > fEndLifeline.getX())) {
+ activationWidth = -activationWidth;
+ }
+
+ if (isMessageStartInActivation(getEndOccurrence())) {
+ width = width - activationWidth;
+ }
+
+ if (isMessageEndInActivation(getEndOccurrence())) {
+ width = width - activationWidth;
+ }
+
+ return width;
+ }
+
+ @Override
+ public boolean isVisible(int x, int y, int width, int height) {
+ // ***Common*** syncMessages visibility
+ // draw the message only if at least one end is visible
+ if (fEndLifeline != null && (fEndLifeline.isVisible(x, y, width, height)) || (fStartLifeline != null && fStartLifeline.isVisible(x, y, width, height))) {
+ return true;
+ }
+ // In this case it can be a message which cross the whole visible area
+ else if (fEndLifeline != null && (!fEndLifeline.isVisible(x, y, width, height)) && (fStartLifeline != null && !fStartLifeline.isVisible(x, y, width, height))) {
+ if (fEndLifeline.getX() > x + width && fStartLifeline.getX() < x) {
+ return true;
+ } else if (fStartLifeline.getX() > x + width && fEndLifeline.getX() < x) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Sets the visibility value.
+ *
+ * @param value The visibility to set.
+ */
+ public void setVisible(boolean value) {
+ fVisible = value;
+ }
+
+ /**
+ * @return the visibility value.
+ */
+ public boolean isVisible() {
+ return fVisible;
+ }
+
+ /**
+ * Set the lifeline from which this message has been sent.
+ *
+ * @param lifeline - the message sender
+ */
+ public void setStartLifeline(Lifeline lifeline) {
+ fStartLifeline = lifeline;
+ }
+
+ /**
+ * Returns the lifeline from which this message has been sent.
+ *
+ * @return the message sender
+ */
+ public Lifeline getStartLifeline() {
+ return fStartLifeline;
+ }
+
+ /**
+ * Returns the lifeline which has received this message.
+ *
+ * @return the message receiver
+ */
+ public Lifeline getEndLifeline() {
+ return fEndLifeline;
+ }
+
+ /**
+ * Set the lifeline which has receive this message.
+ *
+ * @param lifeline the message receiver
+ */
+ public void setEndLifeline(Lifeline lifeline) {
+ fEndLifeline = lifeline;
+ }
+
+ /**
+ * Set the event occurrence when this message occurs.<br>
+ *
+ * @param occurrence the event occurrence to assign to this message.<br>
+ * @see Lifeline Lifeline for more event occurence details
+ */
+ protected void setEventOccurrence(int occurrence) {
+ setEndOccurrence(occurrence);
+ }
+
+ /**
+ * Returns the event occurence when is message occurs.<br>
+ *
+ * @return the event occurrence assigned to this message.<br>
+ * @see Lifeline Lifeline for more event occurence details
+ */
+ public int getEventOccurrence() {
+ return getEndOccurrence();
+ }
+
+ /**
+ * Determines if the given eventOccurence occurs on a executionOccurence owned by the sending lifeline.<br>
+ * WARNING: this method will return a valid result only for execution occurrences which are visible in the View.<br>
+ * As consequence this method is only used for drawing purpose, especially to determine the exact message x
+ * coordinate and width.<br>
+ *
+ * @see BaseMessage#getX(boolean)
+ * @param event the event occurrence to test
+ * @return true if occurs on a execution occurrence owned by the sending lifeine, false otherwise
+ */
+ protected boolean isMessageStartInActivation(int event) {
+ boolean inActivation = false;
+ if ((fStartLifeline != null) && (fStartLifeline.getExecutions() != null)) {
+ // int acIndex=startLifeline.getExecOccurrenceDrawIndex();
+ // acIndex = first visible execution occurrence
+ // for drawing speed reason with only search on the visivle subset
+ int thisY = getY();
+ for (int i = 0; i < fStartLifeline.getExecutions().size(); i++) {
+ BasicExecutionOccurrence toDraw = (BasicExecutionOccurrence) fStartLifeline.getExecutions().get(i);
+ if ((event >= toDraw.getStartOccurrence()) && (event <= toDraw.getEndOccurrence())) {
+ inActivation = true;
+ }
+ // if we are outside the visible area we stop right now
+ // This works because execution occurrences are ordered along the Y axis
+ if (toDraw.getY() > thisY) {
+ break;
+ }
+ }
+ }
+ return inActivation;
+ }
+
+ /**
+ * Determines if the given event occurrence occurs on a execution occurrence owned by the receiving lifeline.<br>
+ * WARNING: this method will return a valid result only for execution occurrences which are visible in the View.<br>
+ * As consequence this method is only used for drawing purpose, especially to determine the exact message x
+ * coordinate and width.<br>
+ *
+ * @see BaseMessage#getX(boolean)
+ * @param event the event occurrence to test
+ * @return true if occurs on a execution occurrence owned by the receiving lifeline, false otherwise
+ */
+ protected boolean isMessageEndInActivation(int event) {
+ boolean inActivation = false;
+ if ((fEndLifeline != null) && (fEndLifeline.getExecutions() != null)) {
+ // acIndex = first visible execution occurrence
+ // for drawing speed reason with only search on the visivle subset
+ for (int i = 0; i < fEndLifeline.getExecutions().size(); i++) {
+ BasicExecutionOccurrence toDraw = (BasicExecutionOccurrence) fEndLifeline.getExecutions().get(i);
+ if ((event >= toDraw.getStartOccurrence()) && (event <= toDraw.getEndOccurrence())) {
+ inActivation = true;
+ }
+ // if we are outside the visible area we stop right now
+ // This works because execution occurrences are ordered along the Y axis
+ if (toDraw.getY() > getY()) {
+ break;
+ }
+ }
+ }
+ return inActivation;
+ }
+
+ @Override
+ public boolean contains(int xValue, int yValue) {
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+
+ // Used to create a rectangle which contains the message label to allow selection when clicking the label
+ int tempHeight = Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth();
+
+ // Is it a self message?
+ if (fStartLifeline == fEndLifeline) {
+ /*
+ * Rectangle.contains(x,y, width, height) does not works with negative height or width We check here if the
+ * rectangle width is negative.
+ */
+ if (getName().length() * Metrics.getAverageCharWidth() > Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2 + -Metrics.INTERNAL_MESSAGE_WIDTH) {
+ if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH + 10, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2 + -Metrics.INTERNAL_MESSAGE_WIDTH, Metrics.getMessageFontHeigth(), xValue, yValue)) {
+ return true;
+ }
+ } else {
+ if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH + 10, y, getName().length() * Metrics.getAverageCharWidth(), Metrics.getMessageFontHeigth(), xValue, yValue)) {
+ return true;
+ }
+ }
+
+ // Test if the point is in part 1 of the self message
+ // see: "private void drawMessage (NGC context)" method for self message drawing schema
+ if (GraphNode.contains(x, y - Metrics.MESSAGE_SELECTION_TOLERANCE / 2, Metrics.INTERNAL_MESSAGE_WIDTH / 2, Metrics.MESSAGE_SELECTION_TOLERANCE, xValue, yValue)) {
+ return true;
+ }
+
+ // Test if the point is in part 3 of the self message
+ if (GraphNode.contains(x + Metrics.INTERNAL_MESSAGE_WIDTH - Metrics.MESSAGE_SELECTION_TOLERANCE / 2, y, Metrics.MESSAGE_SELECTION_TOLERANCE, height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, xValue, yValue)) {
+ return true;
+ }
+
+ // Test if the point is in part 5 of the self message
+ if (GraphNode.contains(x, y + height - Metrics.MESSAGE_SELECTION_TOLERANCE / 2 + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, Metrics.INTERNAL_MESSAGE_WIDTH / 2, Metrics.MESSAGE_SELECTION_TOLERANCE, xValue, yValue)) {
+ return true;
+ }
+
+ // false otherwise
+ return false;
+ }
+ if (GraphNode.contains(x, y - tempHeight, width, tempHeight, xValue, yValue)) {
+ return true;
+ }
+ // false otherwise
+ return false;
+ }
+
+ /**
+ * Method to draw the message using the graphical context.
+ *
+ * @param context A graphical context to draw in.
+ */
+ protected void drawMessage(IGC context) {
+ int fX = 0;
+ int fY = 0;
+ int fW = 0;
+ int fH = 0;
+
+ // temporary store the coordinates to avoid more methods calls
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // UML2 found message (always drawn from left to right)
+ // or UML2 lost message (always drawn from left to right)
+ if ((fStartLifeline == null || fEndLifeline == null) && fStartLifeline != fEndLifeline) {
+ // Draw the message label above the message and centered
+ // The label is truncated if it cannot fit between the two message end
+ // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label
+ IColor temp = context.getForeground();
+ context.setForeground(pref.getFontColor(getColorPrefId()));
+ context.drawTextTruncatedCentred(getName(), x, y - Metrics.getMessageFontHeigth() - 2 * Metrics.MESSAGES_NAME_SPACING, width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected());
+ context.setForeground(temp);
+ int margin = 0;
+ if (fEndLifeline == null) {
+ margin = Metrics.MESSAGE_CIRCLE_RAY;
+ }
+
+ // Draw the message main line
+ context.drawLine(x, y, x + width, y + height);
+ // Draw the two little lines which make a arrow part of the message
+ Double xt = Double.valueOf(Math.cos(0.75) * 7);
+ Double yt = Double.valueOf(Math.sin(0.75) * 7);
+ if (context.getLineStyle() == context.getLineSolidStyle()) {
+ IColor backcolor = context.getBackground();
+ context.setBackground(context.getForeground());
+ int[] points = { x + width - margin, y + height, x + width - xt.intValue() - margin, y + height - yt.intValue(), x + width - xt.intValue() - margin, y + height + yt.intValue(), x + width - margin, y + height };
+ context.fillPolygon(points);
+ context.drawPolygon(points);
+ context.setBackground(backcolor);
+ } else {
+ int currentStyle = context.getLineStyle();
+ int currentWidth = context.getLineWidth();
+ context.setLineWidth(currentWidth + 2);
+ context.setLineStyle(context.getLineSolidStyle());
+ context.drawLine(x + width - xt.intValue() - margin, y + height - yt.intValue(), x + width - margin, y + height);
+ context.drawLine(x + width - xt.intValue() - margin, y + height + yt.intValue(), x + width - margin, y + height);
+ context.setLineStyle(currentStyle);
+ context.setLineWidth(currentWidth);
+ }
+ IColor storedColor = context.getBackground();
+ context.setBackground(context.getForeground());
+
+ // Draw a circle at the message end (endLifeline side)
+ int ray = Metrics.MESSAGE_CIRCLE_RAY;
+ if (context.getLineWidth() != Metrics.NORMAL_LINE_WIDTH) {
+ ray = ray + Metrics.SELECTION_LINE_WIDTH - Metrics.NORMAL_LINE_WIDTH;
+ }
+ if (fStartLifeline == null) {
+ context.fillOval(x - ray, y - ray, ray * 2, ray * 2);
+ } else {
+ context.fillOval(x + width - ray, y + height - ray, ray * 2, ray * 2);
+ }
+ context.setBackground(storedColor);
+ context.setForeground(pref.getFontColor(getColorPrefId()));
+ fX = x;
+ fY = y - yt.intValue();
+ fW = width;
+ fH = height + 2 * yt.intValue();
+ }
+ // it is self message (always drawn at the left side of the owning lifeLifeline)
+ else if (fStartLifeline != null && fEndLifeline != null && fStartLifeline == fEndLifeline) {
+ /*
+ * Self syncMessages are drawn in 5 parts 1 -----------+ + 2 + | | | 3 | + 5 + 4 -----------+
+ */
+ int tempy = Metrics.INTERNAL_MESSAGE_WIDTH / 2;
+ if (Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT <= Metrics.INTERNAL_MESSAGE_WIDTH) {
+ tempy = Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT / 2;
+ }
+
+ // Part 1
+ context.drawLine(x, y, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y);
+ // Part 3
+ context.drawLine(x + Metrics.INTERNAL_MESSAGE_WIDTH, y + tempy, x + Metrics.INTERNAL_MESSAGE_WIDTH, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - tempy);
+ // Part 5
+ context.drawLine(x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, x + Metrics.INTERNAL_MESSAGE_WIDTH / 2, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT);
+
+ Double xt = Double.valueOf(Math.cos(0.75) * 7);
+ Double yt = Double.valueOf(Math.sin(0.75) * 7);
+
+ fX = x;
+ fY = y;
+ fW = Metrics.INTERNAL_MESSAGE_WIDTH;
+ fH = height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT;
+
+ // Draw the two little lines which make a arrow part of the message
+ if (context.getLineStyle() == context.getLineSolidStyle()) {
+ IColor backcolor = context.getBackground();
+ context.setBackground(context.getForeground());
+ int[] points = { x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + yt.intValue(), x + xt.intValue(),
+ y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT };
+ context.fillPolygon(points);
+ context.drawPolygon(points);
+ context.setBackground(backcolor);
+ } else {
+ int currentStyle = context.getLineStyle();
+ int currentWidth = context.getLineWidth();
+ context.setLineWidth(currentWidth + 2);
+ context.setLineStyle(context.getLineSolidStyle());
+ context.drawLine(x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT);
+ context.drawLine(x + xt.intValue(), y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT - yt.intValue(), x, y + height + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT);
+ context.setLineStyle(currentStyle);
+ context.setLineWidth(currentWidth);
+ }
+
+ // Part 2
+ context.drawArc(x, y, Metrics.INTERNAL_MESSAGE_WIDTH, 2 * tempy, 0, 90);
+ // Part 4
+ context.drawArc(x, y + Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT, Metrics.INTERNAL_MESSAGE_WIDTH, -2 * tempy, 0, -90);
+
+ // Draw the message label above the message and centered
+ // The label is truncated if it cannot fit between the two message end
+ // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label
+
+ // the space available for the text is sorter if are drawing internal message on the last lifeline
+ context.setForeground(pref.getFontColor(getColorPrefId()));
+ if (fStartLifeline.getIndex() == fStartLifeline.getFrame().getHorizontalIndex()) {
+ context.drawTextTruncated(getName(), x + width + Metrics.INTERNAL_MESSAGE_V_MARGIN / 2, y, Metrics.swimmingLaneWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH, +Metrics.MESSAGES_NAME_SPACING
+ - Metrics.getMessageFontHeigth(), !isSelected());
+ } else {
+ context.drawTextTruncated(getName(), x + width + Metrics.INTERNAL_MESSAGE_V_MARGIN / 2, y, Metrics.swimmingLaneWidth() - Metrics.EXECUTION_OCCURRENCE_WIDTH + -Metrics.INTERNAL_MESSAGE_WIDTH,
+ +Metrics.MESSAGES_NAME_SPACING - Metrics.getMessageFontHeigth(), !isSelected());
+ }
+ }
+ // it is regular message
+ else if (fStartLifeline != null && fEndLifeline != null) {
+ // Draw the message main line
+ context.drawLine(x, y, x + width, y + height);
+
+ int spaceBTWStartEnd = fEndLifeline.getX() - fStartLifeline.getX();
+
+ double a = height;
+ double b = width;
+ double angle = Math.atan(a / b);
+ // Compute the coordinates of the two little lines which make the arrow part of the message
+ int sign = 1;
+ if (spaceBTWStartEnd < 0) {
+ sign = -1;
+ }
+ Double x1 = Double.valueOf(sign * Math.cos(angle - 0.75) * 7);
+ Double y1 = Double.valueOf(sign * Math.sin(angle - 0.75) * 7);
+ Double x2 = Double.valueOf(sign * Math.cos(angle + 0.75) * 7);
+ Double y2 = Double.valueOf(sign * Math.sin(angle + 0.75) * 7);
+
+ fX = getX();
+ fY = y + height - y2.intValue();
+ fW = getWidth();
+ fH = y2.intValue() - y1.intValue() + 1;
+ if (fW < 0) {
+ fW = -fW;
+ fX = fX - fW;
+ }
+
+ if (fH < 0) {
+ fH = -fH;
+ fY = fY - fH;
+ }
+
+ // Draw the two little lines which make a arrow part of the message
+ if (context.getLineStyle() == context.getLineSolidStyle()) {
+ IColor backcolor = context.getBackground();
+ context.setBackground(context.getForeground());
+ int[] points = { x + width - x1.intValue(), y + height - y1.intValue(), x + width, y + height, x + width - x2.intValue(), y + height - y2.intValue(), x + width - x1.intValue(), y + height - y1.intValue() };
+ context.fillPolygon(points);
+ context.drawPolygon(points);
+ context.setBackground(backcolor);
+ } else {
+ int currentStyle = context.getLineStyle();
+ int currentWidth = context.getLineWidth();
+ context.setLineWidth(currentWidth + 2);
+ context.setLineStyle(context.getLineSolidStyle());
+ context.drawLine(x + width - x1.intValue(), y + height - y1.intValue(), x + width, y + height);
+ context.drawLine(x + width - x2.intValue(), y + height - y2.intValue(), x + width, y + height);
+ context.setLineStyle(currentStyle);
+ context.setLineWidth(currentWidth);
+ }
+
+ // Draw the message label above the message and centered
+ // The label is truncated if it cannot fit between the two message end
+ // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label
+ context.setForeground(pref.getFontColor(getColorPrefId()));
+ if (spaceBTWStartEnd > 0) {
+ context.drawTextTruncatedCentred(getName(), x, y + height / 2 - (2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()), width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected());
+ } else {
+ context.drawTextTruncatedCentred(getName(), x + width, y + height / 2 - (2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()), -width, 2 * Metrics.MESSAGES_NAME_SPACING + +Metrics.getMessageFontHeigth(), !isSelected());
+ }
+ }
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ // Draw it selected?*/
+ if (isSelected()) {
+ ISDPreferences pref = SDViewPref.getInstance();
+ /*
+ * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection
+ * colors This create the highlight effect
+ */
+ context.setForeground(pref.getBackGroundColorSelection());
+ context.setLineWidth(Metrics.SELECTION_LINE_WIDTH);
+ drawMessage(context);
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ // Second drawing is done after
+ }
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(true);
+ }
+ drawMessage(context);
+ int oldStyle = context.getLineStyle();
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(false);
+ drawFocus(context);
+ }
+ // restore the context
+ context.setLineStyle(oldStyle);
+ }
+
+ /**
+ * Determine if two messages are identical. This default implementation considers that overlapping messages with
+ * same coordinates are identical.
+ *
+ * @param message - the message to compare with
+ * @return true if identical false otherwise
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#isSameAs(org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode)
+ */
+ @Override
+ public boolean isSameAs(GraphNode message) {
+ if (message == null) {
+ return false;
+ }
+ if (!(message instanceof BaseMessage)) {
+ return super.isSameAs(message);
+ }
+ return ((getX() == message.getX()) && (getY() == message.getY()) && (getWidth() == message.getWidth()) && (getHeight() == message.getHeight()));
+ }
+
+ /**
+ * Method drawRot.
+ *
+ * @param x A x coordinate
+ * @param y A y coordinate
+ * @param w A width
+ * @param h A height
+ * @param context A graphical context
+ */
+ public void drawRot(int x, int y, int w, int h, IGC context) {
+ double angleA = Math.atan2(getHeight(), getWidth());
+ double cosA = Math.cos(angleA);
+ double sinA = Math.sin(angleA);
+
+ int gx = getX();
+ int gy = getY();
+
+ int localHeight = h;
+ localHeight = localHeight / 2;
+
+ double cw = Math.sqrt(w * w + getHeight() * getHeight());
+
+ int x1 = Math.round((float) ((x - gx) * cosA - (y - gy) * sinA));
+ int y1 = Math.round((float) ((x - gx) * sinA + (y - gy) * cosA));
+
+ int x2 = Math.round((float) (cw * cosA - (y - gy) * sinA));
+ int y2 = Math.round((float) (cw * sinA + (y - gy) * cosA));
+
+ int x3 = Math.round((float) (cw * cosA - (localHeight) * sinA));
+ int y3 = Math.round((float) (cw * sinA + (localHeight) * cosA));
+
+ int x4 = Math.round((float) ((x - gx) * cosA - (localHeight) * sinA));
+ int y4 = Math.round((float) ((x - gx) * sinA + (localHeight) * cosA));
+
+ int[] points = { x1 + getX(), y1 + getY(), x2 + getX(), y2 + getY(), x3 + getX(), y3 + getY(), x4 + getX(), y4 + getY() };
+ context.drawPolygon(points);
+ }
+
+ @Override
+ public void drawFocus(IGC context) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ if ((fStartLifeline != fEndLifeline) && (getStartOccurrence() == getEndOccurrence())) {
+ context.setLineStyle(context.getLineDotStyle());
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ context.drawFocus(getX(), getY() - 3, getWidth(), getHeight() + 6);
+ } else if ((fStartLifeline == fEndLifeline) && (getStartOccurrence() == getEndOccurrence())) {
+ context.drawFocus(getX(), getY() - 3, getWidth(), Metrics.SYNC_INTERNAL_MESSAGE_HEIGHT + 6);
+ } else if ((fStartLifeline != fEndLifeline) && (getStartOccurrence() != getEndOccurrence())) {
+ context.setLineStyle(context.getLineDotStyle());
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ drawRot(getX(), getY() - 5, getWidth(), 10, context);
+ } else {
+ super.drawFocus(context);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicExecutionOccurrence.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicExecutionOccurrence.java
new file mode 100755
index 0000000000..a1e94c5a8e
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicExecutionOccurrence.java
@@ -0,0 +1,275 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * BasicExecutionOccurrence is the UML2 execution occurrence graphical representation. It is attached to one Lifeline,
+ * the event occurrence "duration" along the lifeline is defined by two event occurrences
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class BasicExecutionOccurrence extends GraphNode {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The grahNode ID constant
+ */
+ public static final String EXEC_OCC_TAG = "Execution_Occ"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The corresponding lifeline.
+ */
+ private Lifeline fLifeline = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructore
+ */
+ public BasicExecutionOccurrence() {
+ setColorPrefId(ISDPreferences.PREF_EXEC);
+ }
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int getX() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return fLifeline.getX() + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ }
+
+ @Override
+ public int getY() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return fLifeline.getY() + fLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * getStartOccurrence();
+ }
+
+ @Override
+ public int getWidth() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return Metrics.EXECUTION_OCCURRENCE_WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return ((Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing())) * (getEndOccurrence() - getStartOccurrence());
+ }
+
+ @Override
+ public boolean contains(int xValue, int yValue) {
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+
+ if (GraphNode.contains(x, y, width, height, xValue, yValue)) {
+ return true;
+ }
+
+ if (getNodeAt(xValue, yValue) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String getName() {
+ if (super.getName() == null || super.getName().equals("")) { //$NON-NLS-1$
+ return fLifeline.getToolTipText();
+ }
+ return super.getName();
+ }
+
+ /**
+ * Set the lifeline on which the execution occurrence appears.
+ *
+ * @param theLifeline - the parent lifeline
+ */
+ public void setLifeline(Lifeline theLifeline) {
+ fLifeline = theLifeline;
+ }
+
+ /**
+ * Get the lifeline on which the execution occurrence appears.
+ *
+ * @return - the parent lifeline
+ */
+ public Lifeline getLifeline() {
+ return fLifeline;
+ }
+
+ /**
+ * Get the execution start event occurrence
+ *
+ * @return the start event occurrence to set
+ */
+ @Override
+ public int getStartOccurrence() {
+ return super.getStartOccurrence();
+ }
+
+ /**
+ * Set the execution end event occurrence
+ *
+ * @return the end event occurrence to set
+ */
+ @Override
+ public int getEndOccurrence() {
+ return super.getEndOccurrence();
+ }
+
+ /**
+ * Set the execution start event occurrence
+ *
+ * @param occurrence the start event occurrence to set
+ */
+ @Override
+ public void setStartOccurrence(int occurrence) {
+ super.setStartOccurrence(occurrence);
+ }
+
+ /**
+ * Set the execution end event occurrence
+ *
+ * @param occurrence the end event occurrence to set
+ */
+ @Override
+ public void setEndOccurrence(int occurrence) {
+ super.setEndOccurrence(occurrence);
+ }
+
+ @Override
+ public void draw(IGC context) {
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+ IColor tempFillColor = null;
+ IColor tempStrokeColor = null;
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // The execution occurrence is selected
+ // if the owning lifeline is selected
+ if (fLifeline.isSelected() || isSelected()) {
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ } else {
+ tempFillColor = setUnselectedFillColor(context);
+ }
+ if (pref.useGradienColor()) {
+ context.fillGradientRectangle(x, y, width, height, false);
+ } else {
+ context.fillRectangle(x, y, width, height);
+ }
+ tempStrokeColor = setUnselectedStrokeColor(context);
+ context.drawRectangle(x, y, width, height);
+ if (tempFillColor != null) {
+ tempFillColor.dispose();
+ }
+ if (tempStrokeColor != null) {
+ tempStrokeColor.dispose();
+ }
+ if (hasFocus()) {
+ drawFocus(context);
+ }
+ super.drawChildenNodes(context);
+ }
+
+ /**
+ * Rewrite this method in your extension in order to support customized fill colors
+ *
+ * @param context Graphics context
+ * @return IColor
+ */
+ protected IColor setUnselectedFillColor(IGC context) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ if (pref.useGradienColor()) {
+ context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_EXEC));
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
+ } else {
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_EXEC));
+ }
+ return null;
+ }
+
+ /**
+ * Rewrite this method in your extension in order to support customized stroke colors
+ *
+ * @param context Graphics context
+ * @return IColor
+ */
+ protected IColor setUnselectedStrokeColor(IGC context) {
+ context.setForeground(SDViewPref.getInstance().getForeGroundColor(ISDPreferences.PREF_EXEC));
+ return null;
+ }
+
+ @Override
+ public String getArrayId() {
+ return EXEC_OCC_TAG;
+ }
+
+ @Override
+ public boolean positiveDistanceToPoint(int x, int y) {
+ if (getY() + getHeight() > y) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isVisible(int x, int y, int width, int height) {
+ if ((getLifeline() != null) && (getLifeline().isVisible(x, y, width, height))) {
+ int ly = getY();
+ int lh = getHeight();
+ if (ly >= y && ly < y + height) {
+ return true;
+ }
+ if (ly + lh > y && ly + lh <= y + height) {
+ return true;
+ }
+ if ((ly < y) && (ly + lh > y + height)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicFrame.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicFrame.java
new file mode 100755
index 0000000000..ecea18c6d2
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/BasicFrame.java
@@ -0,0 +1,633 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * The Frame class is the base sequence diagram graph nodes container.<br>
+ * For instance, only one frame can be drawn in the View.<br>
+ * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
+ * Only the graph node added to their representing list will be drawn.
+ *
+ * The lifelines are appended along the X axsis when added in a frame.<br>
+ * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
+ * @author sveyrier
+ * @version 1.0
+ */
+public class BasicFrame extends GraphNode {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * Contains the max elapsed time between two consecutive messages in the whole frame
+ */
+ private ITmfTimestamp fMaxTime = new TmfTimestamp(0);
+ /**
+ * Contains the min elapsed time between two consecutive messages in the whole frame
+ */
+ private ITmfTimestamp fMinTime = new TmfTimestamp(0);
+ /**
+ * Indicate if the min and max elapsed time between two consecutive messages in the whole frame need to be computed
+ */
+ private boolean fComputeMinMax = true;
+ /**
+ * Store the preference set by the user regarding the external time. This flag is used determine if the min and max
+ * need to be recomputed in case this preference is changed.
+ */
+ private boolean fLastExternalTimePref = SDViewPref.getInstance().excludeExternalTime();
+ /**
+ * The greater event occurrence created on graph nodes drawn in this Frame This directly impact the Frame height
+ */
+ private int fVerticalIndex = 0;
+ /**
+ * The index along the x axis where the next lifeline will is drawn This directly impact the Frame width
+ */
+ private int fHorizontalIndex = 0;
+ /**
+ * The time information flag.
+ */
+ private boolean fHasTimeInfo = false;
+ /**
+ * The current Frame visible area - x coordinates
+ */
+ private int fVisibleAreaX;
+ /**
+ * The current Frame visible area - y coordinates
+ */
+ private int fVisibleAreaY;
+ /**
+ * The current Frame visible area - width
+ */
+ private int fVisibleAreaWidth;
+ /**
+ * The current Frame visible area - height
+ */
+ private int fVisibleAreaHeight;
+ /**
+ * The event occurrence spacing (-1 for none)
+ */
+ private int fForceEventOccurrenceSpacing = -1;
+ /**
+ * Flag to indicate customized minumum and maximum.
+ */
+ private boolean fCustomMinMax = false;
+ /**
+ * The minimum time between messages of the sequence diagram frame.
+ */
+ private ITmfTimestamp fMinSDTime = new TmfTimestamp();
+ /**
+ * The maximum time between messages of the sequence diagram frame.
+ */
+ private ITmfTimestamp fMaxSDTime = new TmfTimestamp();
+ /**
+ * Flag to indicate that initial minimum has to be computed.
+ */
+ private boolean fInitSDMin = true;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Creates an empty frame.
+ */
+ public BasicFrame() {
+ Metrics.setForcedEventSpacing(fForceEventOccurrenceSpacing);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ *
+ * Returns the greater event occurence known by the Frame
+ *
+ * @return the greater event occurrence
+ */
+ protected int getMaxEventOccurrence() {
+ return fVerticalIndex;
+ }
+
+ /**
+ * Set the greater event occurrence created in GraphNodes included in the frame
+ *
+ * @param eventOccurrence the new greater event occurrence
+ */
+ protected void setMaxEventOccurrence(int eventOccurrence) {
+ fVerticalIndex = eventOccurrence;
+ }
+
+ /**
+ * This method increase the lifeline place holder The return value is usually assign to a lifeline. This can be used
+ * to set the lifelines drawing order. Also, calling this method two times and assigning only the last given index
+ * to a lifeline will increase this lifeline draw spacing (2 times the default spacing) from the last added
+ * lifeline.
+ *
+ * @return a new lifeline index
+ */
+ protected int getNewHorizontalIndex() {
+ return ++fHorizontalIndex;
+ }
+
+ /**
+ * Returns the current horizontal index
+ *
+ * @return the current horizontal index
+ * @see Frame#getNewHorizontalIndex() for horizontal index description
+ */
+ protected int getHorizontalIndex() {
+ return fHorizontalIndex;
+ }
+
+ @Override
+ public void addNode(GraphNode nodeToAdd) {
+ setComputeMinMax(true);
+ super.addNode(nodeToAdd);
+ }
+
+ @Override
+ public int getX() {
+ return Metrics.FRAME_H_MARGIN;
+ }
+
+ @Override
+ public int getY() {
+ return Metrics.FRAME_V_MARGIN;
+ }
+
+ @Override
+ public int getWidth() {
+ if (fHorizontalIndex == 0) {
+ return 3 * Metrics.swimmingLaneWidth() + Metrics.LIFELINE_H_MAGIN * 2 - Metrics.FRAME_H_MARGIN - Metrics.LIFELINE_SPACING / 2;
+ }
+ return fHorizontalIndex * Metrics.swimmingLaneWidth() + Metrics.LIFELINE_H_MAGIN * 2 + 1 - Metrics.LIFELINE_SPACING;
+ }
+
+ @Override
+ public int getHeight() {
+ // The Frame height depends on the maximum number of messages added to a lifeline
+ if (fVerticalIndex == 0) {
+ return 5 * (Metrics.getMessagesSpacing() + Metrics.getMessageFontHeigth()) + Metrics.LIFELINE_NAME_H_MARGIN + Metrics.FRAME_NAME_H_MARGIN + Metrics.getFrameFontHeigth() + Metrics.LIFELINE_VT_MAGIN + Metrics.LIFELINE_VB_MAGIN
+ + Metrics.LIFELINE_NAME_H_MARGIN + Metrics.FRAME_NAME_H_MARGIN + Metrics.getLifelineFontHeigth() * 2;
+ }
+ if (fForceEventOccurrenceSpacing >= 0) {
+ Metrics.setForcedEventSpacing(fForceEventOccurrenceSpacing);
+ }
+ return fVerticalIndex * (Metrics.getMessagesSpacing() + Metrics.getMessageFontHeigth()) + Metrics.LIFELINE_NAME_H_MARGIN + Metrics.FRAME_NAME_H_MARGIN + Metrics.getFrameFontHeigth() + Metrics.LIFELINE_VT_MAGIN + Metrics.LIFELINE_VB_MAGIN
+ + Metrics.LIFELINE_NAME_H_MARGIN + Metrics.FRAME_NAME_H_MARGIN + Metrics.getLifelineFontHeigth() * 2;
+ }
+
+ /**
+ * @return true if mininum and maximum time needs to be calculated else false
+ * @since 2.0
+ */
+ protected boolean isComputeMinMax() {
+ return fComputeMinMax;
+ }
+
+ /**
+ * @return true if mininum and maximum time needs to be calculated else false
+ * @since 2.0
+ */
+ protected boolean isCustomMinMax() {
+ return fCustomMinMax;
+ }
+
+ /**
+ * gets the initialization flag for SD minimum.
+ *
+ * @return the initialization flag for SD minimum
+ * @since 2.0
+ */
+ protected boolean getInitSDMin() {
+ return fInitSDMin;
+ }
+
+ /**
+ * Returns the graph node which contains the point given in parameter for the given graph node list and starting the
+ * iteration at the given index<br>
+ * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br>
+ *
+ * @param x the x coordinate of the point to test
+ * @param y the y coordinate of the point to test
+ * @param list the list to search in
+ * @param fromIndex list browsing starting point
+ * @return the graph node containing the point given in parameter, null otherwise
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#getNodeFromListAt(int, int, java.util.List, int)
+ */
+ @Override
+ protected GraphNode getNodeFromListAt(int x, int y, List<GraphNode> list, int fromIndex) {
+ if (list == null) {
+ return null;
+ }
+ for (int i = fromIndex; i < list.size(); i++) {
+ GraphNode node = list.get(i);
+ // only lifeline list is x ordered
+ // Stop browsing the list if the node is outside the visible area
+ // all others nodes will be not visible
+ if ((node instanceof Lifeline) && (node.getX() > fVisibleAreaX + fVisibleAreaWidth)) {
+ break;
+ }
+ if (node.getHeight() < 0) {
+ if (node.getY() + node.getHeight() > fVisibleAreaY + fVisibleAreaHeight) {
+ break;
+ }
+ } else {
+ if (node.getY() > fVisibleAreaY + fVisibleAreaHeight) {
+ break;
+ }
+ }
+ if (node.contains(x, y)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Draw the Frame rectangle
+ *
+ * @param context the context to draw to
+ */
+ protected void drawFrame(IGC context) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_FRAME));
+
+ int x = getX();
+ int y = getY();
+ int w = getWidth();
+ int h = getHeight();
+
+ // Draw the frame main rectangle
+ context.fillRectangle(x, y, w, h);
+ context.drawRectangle(x, y, w, h);
+
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME_NAME));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_FRAME_NAME));
+ context.setFont(pref.getFont(ISDPreferences.PREF_FRAME_NAME));
+
+ int nameWidth = context.textExtent(getName()) + 2 * Metrics.FRAME_NAME_V_MARGIN;
+ int nameHeight = Metrics.getFrameFontHeigth() + +Metrics.FRAME_NAME_H_MARGIN * 2;
+
+ // Draw the frame name area
+ if (nameWidth > w) {
+ nameWidth = w;
+ }
+
+ int[] points = { x, y, x + nameWidth, y, x + nameWidth, y - 11 + nameHeight, x - 11 + nameWidth, y + nameHeight, x, y + nameHeight, x, y + nameHeight };
+ context.fillPolygon(points);
+ context.drawPolygon(points);
+ context.drawLine(x, y, x, y + nameHeight);
+
+ context.setForeground(pref.getFontColor(ISDPreferences.PREF_FRAME_NAME));
+ context.drawTextTruncatedCentred(getName(), x, y, nameWidth - 11, nameHeight, false);
+
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_FRAME));
+ }
+
+ @Override
+ public void draw(IGC context) {
+ draw(context, true);
+ }
+
+ /**
+ * Draws the Frame on the given context.<br>
+ * This method start width GraphNodes ordering if needed.<br>
+ * After, depending on the visible area, only visible GraphNodes are drawn.<br>
+ *
+ * @param context the context to draw to
+ * @param drawFrame indicate if the frame rectangle need to be redrawn
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
+ */
+ protected void draw(IGC context, boolean drawFrame) {
+ fVisibleAreaHeight = context.getVisibleHeight();
+ fVisibleAreaWidth = context.getVisibleWidth();
+ fVisibleAreaX = context.getContentsX();
+ fVisibleAreaY = context.getContentsY();
+
+ if (fForceEventOccurrenceSpacing >= 0) {
+ Metrics.setForcedEventSpacing(fForceEventOccurrenceSpacing);
+ } else {
+ Metrics.setForcedEventSpacing(-1);
+ }
+
+ super.drawChildenNodes(context);
+ }
+
+ /**
+ * Sets the event occurrence spacing (-1 for none)
+ *
+ * @param space A spacing to set.
+ */
+ public void forceEventOccurrenceSpacing(int space) {
+ fForceEventOccurrenceSpacing = space;
+ }
+
+ /**
+ * Return the X coordinates of the frame visible area
+ *
+ * @return the X coordinates of the frame visible area
+ */
+ public int getVisibleAreaX() {
+ return fVisibleAreaX;
+ }
+
+ /**
+ * Return the frame visible area width
+ *
+ * @return the frame visible area width
+ */
+ public int getVisibleAreaWidth() {
+ return fVisibleAreaWidth;
+ }
+
+ /**
+ * Return the frame visible area height
+ *
+ * @return the frame visible area height
+ */
+ public int getVisibleAreaHeight() {
+ return fVisibleAreaHeight;
+ }
+
+ /**
+ * Return the X coordinates of the frame visible area
+ *
+ * @return the X coordinates of the frame visible area
+ */
+ public int getVisibleAreaY() {
+ return fVisibleAreaY;
+ }
+
+ /**
+ * Return the minimum time stored in the frame taking all GraphNodes into account
+ *
+ * @return the minimum GraphNode time
+ * @since 2.0
+ */
+ public ITmfTimestamp getMinTime() {
+ if (fLastExternalTimePref != SDViewPref.getInstance().excludeExternalTime()) {
+ fLastExternalTimePref = SDViewPref.getInstance().excludeExternalTime();
+ setComputeMinMax(true);
+ }
+ if ((fComputeMinMax) && (!fCustomMinMax)) {
+ computeMinMax();
+ setComputeMinMax(false);
+ }
+ return fMinTime;
+ }
+
+ /**
+ * Set the minimum timestamp of the frame.
+ *
+ * @param min
+ * The minimum timestamp
+ * @since 2.0
+ */
+ public void setMin(ITmfTimestamp min) {
+ fMinTime = min;
+ fCustomMinMax = true;
+ }
+
+ /**
+ * Set the maximum timestamp of the frame.
+ *
+ * @param max
+ * The maximum timestamp
+ * @since 2.0
+ */
+ public void setMax(ITmfTimestamp max) {
+ fMaxTime = max;
+ fCustomMinMax = true;
+ }
+
+ /**
+ * Reset min/max timestamp values to the default ones.
+ */
+ public void resetCustomMinMax() {
+ fCustomMinMax = false;
+ setComputeMinMax(true);
+ }
+
+ /**
+ * Return the maximum time stored in the frame taking all GraphNodes into account
+ *
+ * @return the maximum GraphNode time
+ * @since 2.0
+ */
+ public ITmfTimestamp getMaxTime() {
+ if (fLastExternalTimePref != SDViewPref.getInstance().excludeExternalTime()) {
+ fLastExternalTimePref = SDViewPref.getInstance().excludeExternalTime();
+ setComputeMinMax(true);
+ }
+ if (fComputeMinMax) {
+ computeMinMax();
+ setComputeMinMax(false);
+ }
+ return fMaxTime;
+ }
+
+ /**
+ * Computes the minimum and maximum time between consecutive messages within the frame.
+ */
+ protected void computeMaxMinTime() {
+ if (!fInitSDMin) {
+ return;
+ }
+
+ List<SDTimeEvent> timeArray = buildTimeArray();
+
+ if ((timeArray == null) || timeArray.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < timeArray.size(); i++) {
+ SDTimeEvent m = timeArray.get(i);
+
+ if (m.getTime().compareTo(fMaxSDTime, true) > 0) {
+ fMaxSDTime = m.getTime();
+ }
+
+ if ((m.getTime().compareTo(fMinSDTime, true) < 0) || fInitSDMin) {
+ fMinSDTime = m.getTime();
+ fInitSDMin = false;
+ }
+ }
+ }
+
+ /**
+ * Returns the minimum time between consecutive messages.
+ *
+ * @return the minimum time between consecutive messages
+ * @since 2.0
+ */
+ public ITmfTimestamp getSDMinTime() {
+ computeMaxMinTime();
+ return fMinSDTime;
+ }
+
+ /**
+ * Returns the maximum time between consecutive messages.
+ *
+ * @return the maximum time between consecutive messages
+ * @since 2.0
+ */
+ public ITmfTimestamp getSDMaxTime() {
+ computeMaxMinTime();
+ return fMaxSDTime;
+ }
+
+ /**
+ * Browse all the GraphNode to compute the min and max times store in the Frame
+ */
+ protected void computeMinMax() {
+ List<SDTimeEvent> timeArray = buildTimeArray();
+
+ if ((timeArray == null) || timeArray.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < timeArray.size() - 1; i++) {
+ SDTimeEvent m1 = timeArray.get(i);
+ SDTimeEvent m2 = timeArray.get(i + 1);
+
+ updateMinMax(m1, m2);
+ }
+ }
+
+ /**
+ * Updates the minimum and maximum time between consecutive message within the frame based on the given values.
+ *
+ * @param m1 A first SD time event.
+ * @param m2 A second SD time event.
+ */
+ protected void updateMinMax(SDTimeEvent m1, SDTimeEvent m2) {
+ ITmfTimestamp delta = m2.getTime().getDelta(m1.getTime());
+ if (fComputeMinMax) {
+ fMinTime = delta;
+ if (fMinTime.compareTo(TmfTimestamp.ZERO, false) < 0) {
+ fMinTime = new TmfTimestamp(0, m1.getTime().getScale(), m1.getTime().getPrecision());
+ }
+ fMaxTime = fMinTime;
+ setComputeMinMax(false);
+ }
+
+ if ((delta.compareTo(fMinTime, true) < 0) && (delta.compareTo(TmfTimestamp.ZERO, false) > 0)) {
+ fMinTime = delta;
+ }
+
+ if ((delta.compareTo(fMaxTime, true) > 0) && (delta.compareTo(TmfTimestamp.ZERO, false) > 0)) {
+ fMaxTime = delta;
+ }
+ }
+
+ /**
+ * Builds the time array based on the list of graph nodes.
+ *
+ * @return the time array else empty list.
+ */
+ protected List<SDTimeEvent> buildTimeArray() {
+ if (!hasChildren()) {
+ return new ArrayList<>();
+ }
+
+ Iterator<String> it = getForwardSortMap().keySet().iterator();
+ List<SDTimeEvent> timeArray = new ArrayList<>();
+ while (it.hasNext()) {
+ String nodeType = it.next();
+ List<GraphNode> list = getNodeMap().get(nodeType);
+ for (int i = 0; i < list.size(); i++) {
+ Object timedNode = list.get(i);
+ if ((timedNode instanceof ITimeRange) && ((ITimeRange) timedNode).hasTimeInfo()) {
+ int event = list.get(i).getStartOccurrence();
+ ITmfTimestamp time = ((ITimeRange) list.get(i)).getStartTime();
+ SDTimeEvent f = new SDTimeEvent(time, event, (ITimeRange) list.get(i));
+ timeArray.add(f);
+ if (event != list.get(i).getEndOccurrence()) {
+ event = (list.get(i)).getEndOccurrence();
+ time = ((ITimeRange) list.get(i)).getEndTime();
+ f = new SDTimeEvent(time, event, (ITimeRange) list.get(i));
+ timeArray.add(f);
+ }
+ }
+ }
+ }
+ return timeArray;
+ }
+
+ @Override
+ public String getArrayId() {
+ return null;
+ }
+
+ @Override
+ public boolean contains(int x, int y) {
+ return false;
+ }
+
+ /**
+ * @return true if frame has time info else false
+ * @since 2.0
+ */
+ public boolean hasTimeInfo() {
+ return fHasTimeInfo;
+ }
+
+ /**
+ * Sets the flag whether the frame has time info or not
+ * @since 2.0
+ * @param hasTimeInfo
+ * true if frame has time info else false
+ */
+ public void setHasTimeInfo(boolean hasTimeInfo) {
+ fHasTimeInfo = hasTimeInfo;
+ }
+
+ /**
+ * Sets the flag for minimum and maximum computation.
+ * @param computeMinMax
+ * true if mininum and maximum time needs to be calculated else false
+ * @since 2.0
+ */
+ public void setComputeMinMax(boolean computeMinMax) {
+ fComputeMinMax = computeMinMax;
+ }
+
+ /**
+ * Sets the initialization flag for SD minimum.
+ *
+ * @param initSDMin
+ * the flag to set
+ * @since 2.0
+ */
+ public void setInitSDMin(boolean initSDMin) {
+ fInitSDMin = initSDMin;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/EllipsisMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/EllipsisMessage.java
new file mode 100755
index 0000000000..4291ddcca0
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/EllipsisMessage.java
@@ -0,0 +1,141 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * Class to draw Ellipsis Message.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class EllipsisMessage extends AsyncMessage {
+
+ @Override
+ public int getX() {
+ if (getStartLifeline() == null) {
+ return super.getX() + super.getWidth() - 16;
+ }
+ return super.getX();
+ }
+
+ @Override
+ public int getY() {
+ return super.getY() + 3;
+ }
+
+ @Override
+ public int getWidth() {
+ return 16;
+ }
+
+ @Override
+ protected void drawMessage(IGC context) {
+ // temporary store the coordinates to avoid more methods calls
+ int x = super.getX();
+ int y = getY();
+ int width = super.getWidth();
+ int height = getHeight();
+
+ // UML2 found message (always drawn from left to right)
+ if (getStartLifeline() == null && getEndLifeline() != null) {
+ // Draw the message label above the message and centered
+ // The label is truncated if it cannot fit between the two message end
+ // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label
+ context.drawTextTruncatedCentred(getName(), x, y - Metrics.getMessageFontHeigth() - 2 * Metrics.MESSAGES_NAME_SPACING, width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected());
+
+ int currentStyle = context.getLineStyle();
+ context.setLineStyle(context.getLineSolidStyle());
+ // Draw the message main line
+ context.drawRectangle(x + width - 5, y, x + width - 6, y + height);
+ context.drawRectangle(x + width - 10, y, x + width - 11, y + height);
+ context.drawRectangle(x + width - 15, y, x + width - 16, y + height);
+ context.setLineStyle(currentStyle);
+
+ IColor storedColor = context.getBackground();
+ context.setBackground(context.getForeground());
+ context.fillRectangle(x + width - 5, y, x + width - 6, y + height);
+ context.fillRectangle(x + width - 10, y, x + width - 11, y + height);
+ context.fillRectangle(x + width - 15, y, x + width - 16, y + height);
+ context.setBackground(storedColor);
+ }
+ // UML2 lost message (always drawn from left to right)
+ else if (getEndLifeline() == null && getStartLifeline() != null) {
+ // Draw the message label above the message and centered
+ // The label is truncated if it cannot fit between the two message end
+ // 2*Metrics.MESSAGES_NAME_SPACING = space above the label + space below the label
+ context.drawTextTruncatedCentred(getName(), x, y - Metrics.getMessageFontHeigth() - 2 * Metrics.MESSAGES_NAME_SPACING, width, 2 * Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth(), !isSelected());
+
+ int currentStyle = context.getLineStyle();
+ context.setLineStyle(context.getLineSolidStyle());
+ // Draw the message main line
+ context.drawRectangle(x + 5, y, 1, 1);
+ context.drawRectangle(x + 10, y, 1, 1);
+ context.drawRectangle(x + 15, y, 1, 1);
+
+ context.setLineStyle(currentStyle);
+
+ IColor storedColor = context.getBackground();
+ context.setBackground(context.getForeground());
+ context.fillRectangle(x + 5, y, 1, 1);
+ context.fillRectangle(x + 10, y, 1, 1);
+ context.fillRectangle(x + 15, y, 1, 1);
+
+ context.setBackground(storedColor);
+
+ } else {
+ super.draw(context);
+ }
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // Draw it selected?*/
+ if (isSelected()) {
+
+ /*
+ * Draw it twice First time, bigger inverting selection colors Second time, regular drawing using selection
+ * colors This create the highlight effect
+ */
+ context.setForeground(pref.getBackGroundColorSelection());
+ context.setLineWidth(Metrics.SELECTION_LINE_WIDTH);
+ drawMessage(context);
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ // Second drawing is done after the else
+ } else {
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_ASYNC_MESS));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_ASYNC_MESS));
+ }
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(true);
+ }
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ drawMessage(context);
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ if (hasFocus()) {
+ context.setDrawTextWithFocusStyle(false);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ExecutionOccurrence.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ExecutionOccurrence.java
new file mode 100755
index 0000000000..df27ae6b1d
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ExecutionOccurrence.java
@@ -0,0 +1,267 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.Arrays;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * ExecutionOccurrence is the UML2 execution occurrence graphical representation. It is a BasicExecutionOccurrence on
+ * which you can customize fill and/or.
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class ExecutionOccurrence extends BasicExecutionOccurrence implements ITimeRange {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set the red, green and blue value of the optional color to be used for filling the execution occurrence.
+ */
+ private int[] fFillRGB;
+ /**
+ * Set the red, green and blue value of the optional color to be used for drawing the execution occurrence
+ */
+ private int[] fStrokeRGB;
+ /**
+ * The occurrence image.
+ */
+ private IImage fImage;
+ /**
+ * The top ellipses image.
+ */
+ private IImage fEllipsesImage;
+ /**
+ * The start time stamp.
+ */
+ private ITmfTimestamp fStartTime;
+ /**
+ * The end time stamp;
+ */
+ private ITmfTimestamp fEndTime;
+ /**
+ * Flag to indicate whether time information is available or not.
+ */
+ private boolean fHasTimeInfo;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void setLifeline(Lifeline theLifeline) {
+ super.setLifeline(theLifeline);
+ if (getLifeline() != null && fHasTimeInfo) {
+ getLifeline().setTimeInfo(true);
+ if (getLifeline().getFrame() != null) {
+ getLifeline().getFrame().setHasTimeInfo(true);
+ }
+ }
+ }
+
+ /**
+ * Set the red, green and blue value of the optional color to be used for filling the execution occurrence.
+ *
+ * @param red A value for red.
+ * @param green A green value for green.
+ * @param blue A value blue.
+ */
+ public void setFillColor(int red, int green, int blue) {
+ fFillRGB = new int[3];
+ fFillRGB[0] = red;
+ fFillRGB[1] = green;
+ fFillRGB[2] = blue;
+ }
+
+ /**
+ * Set the red, green and blue value of the optional color to be used for drawing the execution occurrence
+ *
+ * @param red A value for red.
+ * @param green A green value for green.
+ * @param blue A value blue.
+ */
+ public void setStrokeColor(int red, int green, int blue) {
+ fStrokeRGB = new int[3];
+ fStrokeRGB[0] = red;
+ fStrokeRGB[1] = green;
+ fStrokeRGB[2] = blue;
+ }
+
+ /**
+ * Set the corresponding image.
+ *
+ * @param image A image to set.
+ */
+ public void setImage(IImage image) {
+ fImage = image;
+ }
+
+ /**
+ * Set the top ellipses image.
+ *
+ * @param image A image to set.
+ */
+ public void setTopEllipsesImage(IImage image) {
+ fEllipsesImage = image;
+ }
+
+ /**
+ * Set the time when the execution occurrence starts.
+ *
+ * @param time the time when the execution occurrence starts
+ * @since 2.0
+ */
+ public void setStartTime(ITmfTimestamp time) {
+ fStartTime = time;
+ fHasTimeInfo = true;
+ if (getLifeline() != null) {
+ getLifeline().setTimeInfo(true);
+ }
+ }
+
+ /**
+ * Set the time when the execution occurrence ends.
+ *
+ * @param time the time when the execution occurrence ends
+ * @since 2.0
+ */
+ public void setEndTime(ITmfTimestamp time) {
+ fEndTime = time;
+ fHasTimeInfo = true;
+ if (getLifeline() != null) {
+ getLifeline().setTimeInfo(true);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getStartTime() {
+ return fStartTime;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getEndTime() {
+ return fEndTime;
+ }
+
+ @Override
+ public boolean hasTimeInfo() {
+ return fHasTimeInfo;
+ }
+
+ /**
+ * @return the RGB of the occurrence filler.
+ * @since 2.0
+ */
+ public int[] getFillRGB() {
+ if (fFillRGB == null) {
+ return null;
+ }
+ return Arrays.copyOf(fFillRGB, fFillRGB.length);
+ }
+
+ /**
+ * @return the RGB of the occurrence filler.
+ * @since 2.0
+ */
+ public int[] getStrokeRGB() {
+ if (fStrokeRGB == null) {
+ return null;
+ }
+ return Arrays.copyOf(fStrokeRGB, fStrokeRGB.length);
+ }
+
+ /**
+ * @return the image.
+ * @since 2.0
+ */
+ protected IImage getImage() {
+ return fImage;
+ }
+
+ /**
+ * @return the image.
+ * @since 2.0
+ */
+ protected IImage getEllipsesImage() {
+ return fEllipsesImage;
+ }
+
+ @Override
+ public void draw(IGC context) {
+ super.draw(context);
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+ if (fImage != null) {
+ context.drawImage(fImage, x + width - 4, y + height - 11, 8, 11);
+ }
+ if (fEllipsesImage != null) {
+ context.drawImage(fEllipsesImage, x + width, y, 40, 10);
+ }
+ }
+
+ @Override
+ protected IColor setUnselectedFillColor(IGC context) {
+ ISDPreferences pref = SDViewPref.getInstance();
+ if (fFillRGB != null) {
+ IColor tempFillColor = context.createColor(fFillRGB[0], fFillRGB[1], fFillRGB[2]);
+ if (pref.useGradienColor()) {
+ context.setGradientColor(tempFillColor);
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_EXEC));
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
+ } else {
+ context.setBackground(tempFillColor);
+ }
+ return tempFillColor;
+ }
+ return super.setUnselectedFillColor(context);
+ }
+
+ @Override
+ protected IColor setUnselectedStrokeColor(IGC context) {
+ if (fStrokeRGB != null) {
+ IColor tempStrokeColor = context.createColor(fStrokeRGB[0], fStrokeRGB[1], fStrokeRGB[2]);
+ context.setForeground(tempStrokeColor);
+ return tempStrokeColor;
+ }
+ return super.setUnselectedStrokeColor(context);
+ }
+
+ /**
+ * Sets the flag whether the frame has time info or not
+ * @since 2.0
+ * @param hasTimeInfo
+ * true if frame has time info else false
+ */
+ public void setHasTimeInfo(boolean hasTimeInfo) {
+ fHasTimeInfo = hasTimeInfo;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Frame.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Frame.java
new file mode 100755
index 0000000000..d5dcf6f3da
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Frame.java
@@ -0,0 +1,1215 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.TimeEventComparator;
+
+/**
+ * The Frame class is the base sequence diagram graph nodes container.<br>
+ * For instance, only one frame can be drawn in the View.<br>
+ * Lifelines, Messages and Stop which are supposed to represent a Sequence diagram are drawn in a Frame.<br>
+ * Only the graph node added to their representing list will be drawn.
+ *
+ * The lifelines are appended along the X axsis when added in a frame.<br>
+ * The syncMessages are ordered along the Y axsis depending on the event occurrence they are attached to.<br>
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
+ * @author sveyrier
+ * @version 1.0
+ */
+public class Frame extends BasicFrame {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The lifeline that is current highlighted.
+ */
+ private Lifeline fHighlightLifeline = null;
+ /**
+ * The value of the start event.
+ */
+ private int fStartEvent = 0;
+ /**
+ * The number of events in the frame.
+ */
+ private int fNbEvent = 0;
+ /**
+ * The color for highlighting.
+ */
+ private IColor fHighlightColor = null;
+ /**
+ * The list of time events of the corresponding execution occurrences.
+ */
+ private List<SDTimeEvent> fExecutionOccurrencesWithTime;
+ /**
+ * The Array of lifeline categories.
+ */
+ private LifelineCategories[] fLifelineCategories = null;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns a list of all lifelines known by this frame. Known lifelines are the only one which can be displayed on
+ * screen.
+ *
+ * @return the lifelines list
+ */
+ protected List<GraphNode> getLifelines() {
+ if (!hasChildren()) {
+ return null;
+ }
+ return getNodeMap().get(Lifeline.LIFELINE_TAG);
+ }
+
+ /**
+ * Returns the number of lifelines stored in the frame
+ *
+ * @return the number of lifelines
+ */
+ public int lifeLinesCount() {
+ List<GraphNode> lifelines = getLifelines();
+ if (lifelines != null) {
+ return lifelines.size();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the lifeline at the given index in the lifelines array
+ *
+ * @param index the position in the lifeline array
+ * @return the lifeline or <code>null</code>
+ */
+ public Lifeline getLifeline(int index) {
+ if ((getLifelines() != null) && (index >= 0) && (index < lifeLinesCount())) {
+ return (Lifeline) getLifelines().get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of syncMessages known by this frame. Known syncMessages are the only on which can be displayed on
+ * screen
+ *
+ * @return the syncMessages list
+ */
+ protected List<GraphNode> getSyncMessages() {
+ if (!hasChildren()) {
+ return null;
+ }
+ return getNodeMap().get(SyncMessage.SYNC_MESS_TAG);
+ }
+
+ /**
+ * Returns the number of syncMessages stored in the frame
+ *
+ * @return the number of syncMessage
+ */
+ public int syncMessageCount() {
+ if (getSyncMessages() != null) {
+ return getSyncMessages().size();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the syncMessage at the given index in the syncMessages array
+ *
+ * @param index the position in the syncMessages array
+ * @return the syncMessage or <code>null</code>
+ */
+ public SyncMessage getSyncMessage(int index) {
+ if ((getSyncMessages() != null) && (index >= 0) && (index < getSyncMessages().size())) {
+ return (SyncMessage) getSyncMessages().get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of asyncMessages known by this frame. Known asyncMessages are the only on which can be displayed
+ * on screen
+ *
+ * @return the asyncMessages list or <code>null</code>
+ */
+ protected List<GraphNode> getAsyncMessages() {
+ if (!hasChildren()) {
+ return null;
+ }
+ return getNodeMap().get(AsyncMessage.ASYNC_MESS_TAG);
+ }
+
+ /**
+ * Returns the number of asyncMessage stored in the frame
+ *
+ * @return the number of asyncMessage
+ */
+ public int asyncMessageCount() {
+ if (getAsyncMessages() != null) {
+ return getAsyncMessages().size();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the asyncMessage at the given index in the asyncMessage array
+ *
+ * @param index the position in the asyncMessage array
+ * @return the asyncMessage or <code>null</code>
+ */
+ public AsyncMessage getAsyncMessage(int index) {
+ if ((getAsyncMessages() != null) && (index >= 0) && (index < getAsyncMessages().size())) {
+ return (AsyncMessage) getAsyncMessages().get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of syncMessages return known by this frame. Known syncMessages return are the only on which can be
+ * displayed on screen
+ *
+ * @return the syncMessages return list or <code>null</code>
+ */
+ protected List<GraphNode> getSyncMessagesReturn() {
+ if (!hasChildren()) {
+ return null;
+ }
+ return getNodeMap().get(SyncMessageReturn.SYNC_MESS_RET_TAG);
+ }
+
+ /**
+ * Returns the number of syncMessageReturn stored in the frame
+ *
+ * @return the number of syncMessageReturn
+ */
+ public int syncMessageReturnCount() {
+ if (getSyncMessagesReturn() != null) {
+ return getSyncMessagesReturn().size();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the syncMessageReturn at the given index in the syncMessageReturn array
+ *
+ * @param index the position in the syncMessageReturn array
+ * @return the syncMessageReturn or <code>null</code>
+ */
+ public SyncMessageReturn getSyncMessageReturn(int index) {
+ if ((getSyncMessagesReturn() != null) && (index >= 0) && (index < getSyncMessagesReturn().size())) {
+ return (SyncMessageReturn) getSyncMessagesReturn().get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of asyncMessageRetun known by this frame. Known asyncMessageRetun are the only on which can be
+ * displayed on screen
+ *
+ * @return the asyncMessageRetun list or <code>null</code>
+ */
+ protected List<GraphNode> getAsyncMessagesReturn() {
+ if (!hasChildren()) {
+ return null;
+ }
+ return getNodeMap().get(AsyncMessageReturn.ASYNC_MESS_RET_TAG);
+ }
+
+ /**
+ * Returns the number of asyncMessageReturn stored in the frame
+ *
+ * @return the number of asyncMessageReturn
+ */
+ public int asyncMessageReturnCount() {
+ if (getAsyncMessagesReturn() != null) {
+ return getAsyncMessagesReturn().size();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the asyncMessageReturn at the given index in the asyncMessageReturn array
+ *
+ * @param index the position in the asyncMessageReturn array
+ * @return the asyncMessageReturn or <code>null</code>
+ */
+ public AsyncMessageReturn getAsyncMessageReturn(int index) {
+ if ((getAsyncMessagesReturn() != null) && (index >= 0) && (index < getAsyncMessagesReturn().size())) {
+ return (AsyncMessageReturn) getAsyncMessagesReturn().get(index);
+ }
+ return null;
+ }
+
+ /**
+ * Adds a lifeline to the frame lifelines list. The lifeline X drawing order depends on the lifeline addition order
+ * into the frame lifelines list.
+ *
+ * @param lifeline the lifeline to add
+ */
+ public void addLifeLine(Lifeline lifeline) {
+ setComputeMinMax(true);
+ if (lifeline == null) {
+ return;
+ }
+ // set the lifeline parent frame
+ lifeline.setFrame(this);
+ // Increate the frame lifeline counter
+ // and set the lifeline drawing order
+ lifeline.setIndex(getNewHorizontalIndex());
+ if (lifeline.hasTimeInfo()) {
+ setHasTimeInfo(true);
+ }
+ // add the lifeline to the lifelines list
+ addNode(lifeline);
+ }
+
+ /**
+ * Returns the first visible lifeline drawn in the view
+ *
+ * @return the first visible lifeline index
+ */
+ public int getFirstVisibleLifeline() {
+ if (!hasChildren()) {
+ return 0;
+ } else if (getIndexes().get(Lifeline.LIFELINE_TAG) != null) {
+ return getIndexes().get(Lifeline.LIFELINE_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the first visible synchronous message drawn in the view
+ *
+ * @return the first visible synchronous message index
+ */
+ public int getFirstVisibleSyncMessage() {
+ if (!hasChildren()) {
+ return 0;
+ } else if (getIndexes().get(SyncMessage.SYNC_MESS_TAG) != null) {
+ return getIndexes().get(SyncMessage.SYNC_MESS_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the first visible synchronous message return drawn in the view
+ *
+ * @return the first visible synchronous message return index
+ */
+ public int getFirstVisibleSyncMessageReturn() {
+ if (!hasChildren()) {
+ return 0;
+ } else if (getIndexes().get(SyncMessageReturn.SYNC_MESS_RET_TAG) != null) {
+ return getIndexes().get(SyncMessageReturn.SYNC_MESS_RET_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the first visible synchronous message drawn in the view
+ *
+ * @return the first visible synchronous message index
+ */
+ public int getFirstVisibleAsyncMessage() {
+ if (!hasChildren()) {
+ return 0;
+ } else if (getIndexes().get(AsyncMessage.ASYNC_MESS_TAG) != null) {
+ return getIndexes().get(AsyncMessage.ASYNC_MESS_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the first visible synchronous message return drawn in the view
+ *
+ * @return the first visible synchronous message return index
+ */
+ public int getFirstVisibleAsyncMessageReturn() {
+ if (!hasChildren()) {
+ return 0;
+ } else if (getIndexes().get(AsyncMessageReturn.ASYNC_MESS_RET_TAG) != null) {
+ return getIndexes().get(AsyncMessageReturn.ASYNC_MESS_RET_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Returns the list of execution occurrences.
+ *
+ * @return the list of execution occurrences
+ */
+ public List<SDTimeEvent> getExecutionOccurrencesWithTime() {
+ return fExecutionOccurrencesWithTime;
+ }
+
+ /**
+ * Inserts a lifeline after a given lifeline.
+ *
+ * @param toInsert A lifeline to insert
+ * @param after A lifelife the toInsert-lifeline will be inserted after.
+ */
+ public void insertLifelineAfter(Lifeline toInsert, Lifeline after) {
+ if ((toInsert == null)) {
+ return;
+ }
+ if (toInsert == after) {
+ return;
+ }
+ int insertPoint = 0;
+ if (after != null) {
+ insertPoint = after.getIndex();
+ }
+ int removePoint = toInsert.getIndex() - 1;
+ if (removePoint >= insertPoint) {
+ getLifelines().remove(removePoint);
+ }
+ getLifelines().add(insertPoint, toInsert);
+ if (removePoint < insertPoint) {
+ getLifelines().remove(removePoint);
+ }
+
+ if (removePoint >= insertPoint) {
+ toInsert.setIndex(insertPoint + 1);
+ } else {
+ toInsert.setIndex(insertPoint - 1);
+ }
+
+ insertPoint++;
+ if (removePoint >= insertPoint) {
+ for (int i = insertPoint; i < getLifelines().size(); i++) {
+ getLifeline(i).setIndex(i + 1);
+ }
+ } else {
+ for (int i = 0; i < insertPoint && i < getLifelines().size(); i++) {
+ getLifeline(i).setIndex(i + 1);
+ }
+ }
+ }
+
+ /**
+ * Inserts a lifeline before a given lifeline.
+ *
+ * @param toInsert
+ * A lifeline to insert
+ * @param before
+ * A lifeline the toInsert-lifeline will be inserted before.
+ */
+ public void insertLifelineBefore(Lifeline toInsert, Lifeline before) {
+ if ((toInsert == null)) {
+ return;
+ }
+ if (toInsert == before) {
+ return;
+ }
+ int insertPoint = 0;
+ if (before != null) {
+ insertPoint = before.getIndex() - 1;
+ }
+ int removePoint = toInsert.getIndex() - 1;
+ if (removePoint >= insertPoint) {
+ getLifelines().remove(removePoint);
+ }
+ getLifelines().add(insertPoint, toInsert);
+ if (removePoint < insertPoint) {
+ getLifelines().remove(removePoint);
+ }
+
+ if (removePoint >= insertPoint) {
+ toInsert.setIndex(insertPoint + 1);
+ } else {
+ toInsert.setIndex(insertPoint - 1);
+ }
+
+ insertPoint++;
+ if (removePoint >= insertPoint) {
+ for (int i = insertPoint; i < getLifelines().size(); i++) {
+ getLifeline(i).setIndex(i + 1);
+ }
+ } else {
+ for (int i = 0; i < insertPoint && i < getLifelines().size(); i++) {
+ getLifeline(i).setIndex(i + 1);
+ }
+ }
+ }
+
+ /**
+ * Gets the closer life line to the given x-coordinate.
+ *
+ * @param x A x coordinate
+ * @return the closer lifeline
+ */
+ public Lifeline getCloserLifeline(int x) {
+ int index = (x - Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN) / Metrics.swimmingLaneWidth() - 1;
+ if (index < 0) {
+ index = 0;
+ }
+ if (index >= getLifelines().size()) {
+ index = getLifelines().size() - 1;
+ }
+ Lifeline node1, node2, node3;
+ int dist1, dist2, dist3;
+ node1 = node2 = node3 = getLifeline(index);
+ dist1 = dist2 = dist3 = Math.abs(node1.getX() + node1.getWidth() / 2 - x);
+ if (index > 0) {
+ node2 = getLifeline(index - 1);
+ dist2 = Math.abs(node2.getX() + node2.getWidth() / 2 - x);
+ }
+ if (index < getLifelines().size() - 1) {
+ node3 = getLifeline(index + 1);
+ dist3 = Math.abs(node3.getX() + node3.getWidth() / 2 - x);
+ }
+ if (dist1 <= dist2 && dist1 <= dist3) {
+ return node1;
+ } else if (dist2 <= dist1 && dist2 <= dist3) {
+ return node2;
+ }
+ return node3;
+ }
+
+ /**
+ * Re-orders the given list of lifelines.
+ *
+ * @param list A list of lifelines to reorder.
+ */
+ public void reorder(List<?> list) {
+ for (int i = 0; i < list.size(); i++) {
+ if (list.get(i) instanceof Lifeline[]) {
+ Lifeline temp[] = (Lifeline[]) list.get(i);
+ if (temp.length == 2) {
+ if (temp[1] == null) {
+ insertLifelineAfter(temp[0], getLifeline(lifeLinesCount() - 1));
+ } else {
+ insertLifelineBefore(temp[0], temp[1]);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Resets the time compression information.
+ */
+ public void resetTimeCompression() {
+ fHighlightLifeline = null;
+ this.fStartEvent = 0;
+ this.fNbEvent = 0;
+ fHighlightColor = null;
+ }
+
+ @Override
+ protected void computeMinMax() {
+ List<SDTimeEvent> timeArray = buildTimeArray();
+ if ((timeArray == null) || timeArray.isEmpty()) {
+ return;
+ }
+ for (int i = 0; i < timeArray.size() - 1; i++) {
+ SDTimeEvent m1 = timeArray.get(i);
+ SDTimeEvent m2 = timeArray.get(i + 1);
+ if (SDViewPref.getInstance().excludeExternalTime() && ((m1.getGraphNode() instanceof BaseMessage) && (m2.getGraphNode() instanceof BaseMessage))) {
+ BaseMessage mes1 = (BaseMessage) m1.getGraphNode();
+ BaseMessage mes2 = (BaseMessage) m2.getGraphNode();
+ if ((mes2.getStartLifeline() == null) || (mes1.getEndLifeline() == null)) {
+ continue;
+ }
+ }
+
+ updateMinMax(m1, m2);
+ }
+ }
+
+ /**
+ * Find the two graph nodes that are closest to this date, one just earlier, second just later. If date is before
+ * any graph node, bounds[0] is null and bounds[1] is the earliest. If date is after any graph node, bounds[1] is
+ * null and bounds[0] is the latest.
+ *
+ * @param dateToFind date to be found
+ * @param bounds a two items array that will receive bounds if found
+ * @return true if both bounds not null
+ * @since 2.0
+ */
+ public boolean findDateBounds(ITmfTimestamp dateToFind, ITimeRange bounds[]) {
+ if (hasTimeInfo()) {
+ List<SDTimeEvent> timeArray = buildTimeArray();
+
+ if ((timeArray == null) || timeArray.isEmpty()) {
+ return false;
+ }
+
+ bounds[0] = null;
+ bounds[1] = null;
+ for (int i = 0; i < timeArray.size(); i++) {
+ SDTimeEvent m = timeArray.get(i);
+ if (m.getTime().compareTo(dateToFind, true) > 0) {
+ bounds[1] = m.getGraphNode();
+ if (i > 0) {
+ bounds[0] = timeArray.get(i - 1).getGraphNode();
+ return true;
+ }
+ return false;
+ }
+ }
+ bounds[0] = timeArray.get(timeArray.size() - 1).getGraphNode();
+ }
+ return false;
+ }
+
+ /**
+ * Highlights the time compression.
+ *
+ * @param lifeline A lifeline to highlight
+ * @param startEvent A start event number
+ * @param nbEvent A number of events
+ * @param color A color for highlighting
+ */
+ public void highlightTimeCompression(Lifeline lifeline, int startEvent, int nbEvent, IColor color) {
+ fHighlightLifeline = lifeline;
+ this.fStartEvent = startEvent;
+ this.fNbEvent = nbEvent;
+ fHighlightColor = color;
+ }
+
+ /**
+ * Set the lifeline categories which will be use during the lifelines creation
+ *
+ * @see Lifeline#setCategory(int)
+ * @param categories the lifeline categories array
+ */
+ public void setLifelineCategories(LifelineCategories[] categories) {
+ fLifelineCategories = Arrays.copyOf(categories, categories.length);
+ }
+
+ /**
+ * Returns the lifeline categories array set for the this frame
+ *
+ * @return the lifeline categories array or null if not set
+ */
+ public LifelineCategories[] getLifelineCategories() {
+ return Arrays.copyOf(fLifelineCategories, fLifelineCategories.length);
+ }
+
+ /**
+ * Adds a message to the Frame message list. Four kinds of syncMessages can be added:<br>
+ * - synchronous syncMessages<br>
+ * - synchronous syncMessages return<br>
+ * - asynchronous syncMessages<br>
+ * - asynchronous syncMessages return<br>
+ * For drawing performance reason, it is recommended to add synchronous syncMessages in the same order they should
+ * appear along the Y axis in the Frame.
+ *
+ * @param message the message to add
+ */
+ public void addMessage(BaseMessage message) {
+ addNode(message);
+ }
+
+ @Override
+ public void draw(IGC context) {
+ drawFrame(context);
+ if (!hasChildren()) {
+ return;
+ }
+
+ if (fHighlightLifeline != null) {
+ IColor backupColor = context.getBackground();
+ context.setBackground(SDViewPref.getInstance().getTimeCompressionSelectionColor());
+ int gy = fHighlightLifeline.getY() + fHighlightLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fStartEvent;
+ context.fillRectangle(Metrics.FRAME_H_MARGIN + 1, gy, fHighlightLifeline.getX() + Metrics.getLifelineWidth() / 2 - Metrics.FRAME_H_MARGIN, (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fNbEvent);
+ context.setBackground(backupColor);
+ }
+ super.draw(context, false);
+ int lifelineArryStep = 1;
+ if (Metrics.swimmingLaneWidth() * context.getZoom() < Metrics.LIFELINE_SIGNIFICANT_HSPACING) {
+ lifelineArryStep = Math.round(Metrics.LIFELINE_SIGNIFICANT_HSPACING / (Metrics.swimmingLaneWidth() * context.getZoom()));
+ }
+ if (getIndexes().size() == 0) {
+ return;
+ }
+ int lifeLineDrawIndex = getIndexes().get(Lifeline.LIFELINE_TAG).intValue();
+ for (int i = lifeLineDrawIndex; i < getNodeMap().get(Lifeline.LIFELINE_TAG).size(); i = i + lifelineArryStep) {
+ Lifeline toDraw = (Lifeline) getNodeMap().get(Lifeline.LIFELINE_TAG).get(i);
+ if (toDraw.getX() - Metrics.LIFELINE_SPACING / 2 > context.getContentsX() + context.getVisibleWidth()) {
+ break;
+ }
+ toDraw.drawName(context);
+
+ if (fHighlightLifeline != null) {
+ if (toDraw == fHighlightLifeline) {
+ toDraw.highlightExecOccurrenceRegion(context, fStartEvent, fNbEvent, fHighlightColor);
+ } else if ((toDraw.getIndex() < fHighlightLifeline.getIndex()) || ((toDraw.getIndex() < fHighlightLifeline.getIndex()))) {
+
+ int acIndex = toDraw.getExecOccurrenceDrawIndex();
+ // acIndex = first visible execution occurrence
+ // for drawing speed reason with only search on the visible subset
+ if (toDraw.getExecutions() != null) {
+ for (int index = acIndex; index < toDraw.getExecutions().size(); index++) {
+ BasicExecutionOccurrence exec = (BasicExecutionOccurrence) toDraw.getExecutions().get(index);
+ int tempEvent = fStartEvent;
+ for (int j = 0; j < fNbEvent; j++) {
+ if (((tempEvent >= exec.getStartOccurrence()) && (tempEvent <= exec.getEndOccurrence()) && (tempEvent + 1 >= exec.getStartOccurrence()) && (tempEvent + 1 <= exec.getEndOccurrence()))) {
+ toDraw.highlightExecOccurrenceRegion(context, tempEvent, 1, SDViewPref.getInstance().getTimeCompressionSelectionColor());
+ }
+ tempEvent = tempEvent + 1;
+ }
+ // if we are outside the visible area we stop right now
+ // This works because execution occurrences are ordered along the Y axis
+ if (exec.getY() > getY()) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected List<SDTimeEvent> buildTimeArray() {
+
+ if (!hasChildren()) {
+ return new ArrayList<>();
+ }
+
+ List<SDTimeEvent> timeArray = super.buildTimeArray();
+ fExecutionOccurrencesWithTime = null;
+ if (getLifelines() != null) {
+ for (int i = 0; i < getNodeMap().get(Lifeline.LIFELINE_TAG).size(); i++) {
+ Lifeline lifeline = (Lifeline) getNodeMap().get(Lifeline.LIFELINE_TAG).get(i);
+ if (lifeline.hasTimeInfo() && lifeline.getExecutions() != null) {
+ for (Iterator<GraphNode> j = lifeline.getExecutions().iterator(); j.hasNext();) {
+ GraphNode o = j.next();
+ if (o instanceof ExecutionOccurrence) {
+ ExecutionOccurrence eo = (ExecutionOccurrence) o;
+ if (eo.hasTimeInfo()) {
+ int event = eo.getStartOccurrence();
+ ITmfTimestamp time = eo.getStartTime();
+ SDTimeEvent f = new SDTimeEvent(time, event, eo);
+ timeArray.add(f);
+ if (fExecutionOccurrencesWithTime == null) {
+ fExecutionOccurrencesWithTime = new ArrayList<>();
+ }
+ fExecutionOccurrencesWithTime.add(f);
+ event = eo.getEndOccurrence();
+ time = eo.getEndTime();
+ f = new SDTimeEvent(time, event, eo);
+ timeArray.add(f);
+ fExecutionOccurrencesWithTime.add(f);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (fExecutionOccurrencesWithTime != null) {
+ SDTimeEvent[] temp = fExecutionOccurrencesWithTime.toArray(new SDTimeEvent[fExecutionOccurrencesWithTime.size()]);
+ Arrays.sort(temp, new TimeEventComparator());
+ fExecutionOccurrencesWithTime = Arrays.asList(temp);
+ }
+ SDTimeEvent[] temp = timeArray.toArray(new SDTimeEvent[timeArray.size()]);
+ Arrays.sort(temp, new TimeEventComparator());
+ timeArray = Arrays.asList(temp);
+ return timeArray;
+ }
+
+ /**
+ * Get the closer leaving message.
+ *
+ * @param lifeline A lifeline reference
+ * @param message A message reference
+ * @param list A list of graph nodes
+ * @param smallerEvent A smaller event flag
+ * @return the closer leaving message.
+ */
+ protected GraphNode getCloserLeavingMessage(Lifeline lifeline, BaseMessage message, List<GraphNode> list, boolean smallerEvent) {
+ if (list == null) {
+ return null;
+ }
+
+ if (!smallerEvent) {
+ int event = 0;
+ if (message != null) {
+ event = message.getEventOccurrence();
+ }
+ for (int i = 0; i < list.size(); i++) {
+ GraphNode node = list.get(i);
+ if (node instanceof SyncMessage) {
+ SyncMessage syncNode = (SyncMessage) node;
+ if ((syncNode.getEventOccurrence() > event) && (syncNode.getStartLifeline() == lifeline) && !syncNode.isSameAs(message)) {
+ return node;
+ }
+ } else if (node instanceof AsyncMessage) {
+ AsyncMessage asyncNode = (AsyncMessage) node;
+ if ((asyncNode.getStartOccurrence() > event) && (asyncNode.getStartLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
+ return node;
+ }
+ }
+ }
+ } else {
+ int event = getMaxEventOccurrence();
+ if (message != null) {
+ if (message instanceof AsyncMessage) {
+ event = ((AsyncMessage) message).getStartOccurrence();
+ } else {
+ event = message.getEventOccurrence();
+ }
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ GraphNode node = list.get(i);
+ if (node instanceof SyncMessage) {
+ SyncMessage syncNode = (SyncMessage) node;
+ if ((syncNode.getEventOccurrence() < event) && (syncNode.getStartLifeline() == lifeline) && !syncNode.isSameAs(message)) {
+ return node;
+ }
+ } else if (node instanceof AsyncMessage) {
+ AsyncMessage asyncNode = (AsyncMessage) node;
+ if ((asyncNode.getStartOccurrence() < event) && (asyncNode.getStartLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
+ return node;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Get the closer entering message.
+ *
+ * @param lifeline A lifeline reference
+ * @param message A message reference
+ * @param list A list of graph nodes
+ * @param smallerEvent A smaller event flag
+ * @return the closer entering message.
+ */
+ protected GraphNode getCloserEnteringMessage(Lifeline lifeline, BaseMessage message, List<GraphNode> list, boolean smallerEvent) {
+ if (list == null) {
+ return null;
+ }
+ if (!smallerEvent) {
+ int event = 0;
+ if (message != null) {
+ event = message.getEventOccurrence();
+ }
+ for (int i = 0; i < list.size(); i++) {
+ GraphNode node = list.get(i);
+ if (node instanceof SyncMessage) {
+ SyncMessage syncNode = (SyncMessage) node;
+ if ((syncNode.getEventOccurrence() > event) && (syncNode.getEndLifeline() == lifeline) && !syncNode.isSameAs(message)) {
+ return node;
+ }
+ } else if (node instanceof AsyncMessage) {
+ AsyncMessage asyncNode = (AsyncMessage) node;
+ if ((asyncNode.getStartOccurrence() > event) && (asyncNode.getEndLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
+ return node;
+ }
+ }
+ }
+ } else {
+ int event = getMaxEventOccurrence();
+ if (message != null) {
+ if (message instanceof AsyncMessage) {
+ event = ((AsyncMessage) message).getStartOccurrence();
+ } else {
+ event = message.getEventOccurrence();
+ }
+ }
+ for (int i = list.size() - 1; i >= 0; i--) {
+ GraphNode node = list.get(i);
+ if (node instanceof SyncMessage) {
+ SyncMessage syncNode = (SyncMessage) node;
+ if ((syncNode.getEventOccurrence() < event) && (syncNode.getEndLifeline() == lifeline) && !syncNode.isSameAs(message)) {
+ return node;
+ }
+ } else if (node instanceof AsyncMessage) {
+ AsyncMessage asyncNode = (AsyncMessage) node;
+ if ((asyncNode.getStartOccurrence() < event) && (asyncNode.getEndLifeline() == lifeline) && !asyncNode.isSameAs(message)) {
+ return node;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get distance of given event from given graph node.
+ *
+ * @param node A graph node reference.
+ * @param event A event number to check.
+ * @return distance of event from graph node.
+ */
+ protected int distanceFromEvent(GraphNode node, int event) {
+ int distance = 0;
+ if (node instanceof SyncMessage) {
+ distance = ((SyncMessage) node).getEventOccurrence() - event;
+ } else if (node instanceof AsyncMessage) {
+ int start = ((AsyncMessage) node).getStartOccurrence();
+ int end = ((AsyncMessage) node).getEndOccurrence();
+ if ((start - event) < (end - event)) {
+ distance = start - event;
+ } else {
+ distance = end - event;
+ }
+ }
+ return Math.abs(distance);
+ }
+
+ /**
+ * Get node from 2 given nodes that is close to event.
+ *
+ * @param node1 A first graph node
+ * @param node2 A second graph node
+ * @param event A event to check.
+ * @return graph node that is closer or <code>null</code>
+ */
+ protected GraphNode getCloserToEvent(GraphNode node1, GraphNode node2, int event) {
+ if ((node1 != null) && (node2 != null)) {
+ if (distanceFromEvent(node1, event) < distanceFromEvent(node2, event)) {
+ return node1;
+ }
+ return node2;
+ } else if (node1 != null) {
+ return node1;
+ } else if (node2 != null) {
+ return node2;
+ }
+ return null;
+ }
+
+ /**
+ * Get called message based on given start message.
+ *
+ * @param startMessage A start message to check.
+ * @return called message (graph node) or <code>null</code>
+ */
+ public GraphNode getCalledMessage(BaseMessage startMessage) {
+ int event = 0;
+ GraphNode result = null;
+ Lifeline lifeline = null;
+ if (startMessage != null) {
+ event = startMessage.getEventOccurrence();
+ lifeline = startMessage.getEndLifeline();
+ if (lifeline == null) {
+ lifeline = startMessage.getStartLifeline();
+ }
+ }
+ if (lifeline == null) {
+ return null;
+ }
+ GraphNode message = getCloserLeavingMessage(lifeline, startMessage, getSyncMessages(), false);
+ GraphNode messageReturn = getCloserLeavingMessage(lifeline, startMessage, getSyncMessagesReturn(), false);
+ result = getCloserToEvent(message, messageReturn, event);
+ message = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessages(), false);
+ result = getCloserToEvent(result, message, event);
+ messageReturn = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessagesReturn(), false);
+ result = getCloserToEvent(result, messageReturn, event);
+ return result;
+ }
+
+ /**
+ * Get caller message based on given start message.
+ *
+ * @param startMessage A start message to check.
+ * @return called message (graph node) or <code>null</code>
+ */
+ public GraphNode getCallerMessage(BaseMessage startMessage) {
+ int event = getMaxEventOccurrence();
+ GraphNode result = null;
+ Lifeline lifeline = null;
+ if (startMessage != null) {
+ event = startMessage.getEventOccurrence();
+ lifeline = startMessage.getStartLifeline();
+ if (lifeline == null) {
+ lifeline = startMessage.getEndLifeline();
+ }
+ }
+ if (lifeline == null) {
+ return null;
+ }
+ GraphNode message = getCloserEnteringMessage(lifeline, startMessage, getSyncMessages(), true);
+ GraphNode messageReturn = getCloserEnteringMessage(lifeline, startMessage, getSyncMessagesReturn(), true);
+ result = getCloserToEvent(message, messageReturn, event);
+ message = getCloserEnteringMessage(lifeline, startMessage, getAsyncMessages(), true);
+ result = getCloserToEvent(result, message, event);
+ messageReturn = getCloserEnteringMessage(lifeline, startMessage, getAsyncMessagesReturn(), true);
+ result = getCloserToEvent(result, messageReturn, event);
+ return result;
+ }
+
+ /**
+ * Get next lifeline based on given message.
+ *
+ * @param lifeline A lifeline reference
+ * @param startMessage A start message to check
+ * @return next lifeline or <code>null</code>
+ */
+ public GraphNode getNextLifelineMessage(Lifeline lifeline, BaseMessage startMessage) {
+ int event = 0;
+ if (startMessage != null) {
+ event = startMessage.getEventOccurrence();
+ }
+ if (lifeline == null) {
+ return null;
+ }
+ GraphNode message = getCloserLeavingMessage(lifeline, startMessage, getSyncMessages(), false);
+ GraphNode messageReturn = getCloserLeavingMessage(lifeline, startMessage, getSyncMessagesReturn(), false);
+ GraphNode result = getCloserToEvent(message, messageReturn, event);
+ message = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessages(), false);
+ result = getCloserToEvent(result, message, event);
+ messageReturn = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessagesReturn(), false);
+ result = getCloserToEvent(result, messageReturn, event);
+ return result;
+ }
+
+ /**
+ * Get previous lifeline based on given message.
+ *
+ * @param lifeline A lifeline reference
+ * @param startMessage A start message to check.
+ * @return previous lifeline or <code>null</code>
+ */
+ public GraphNode getPrevLifelineMessage(Lifeline lifeline, BaseMessage startMessage) {
+ int event = getMaxEventOccurrence();
+ if (startMessage != null) {
+ if (startMessage instanceof AsyncMessage) {
+ event = ((AsyncMessage) startMessage).getStartOccurrence();
+ } else {
+ event = startMessage.getEventOccurrence();
+ }
+ }
+ if (lifeline == null) {
+ return null;
+ }
+ GraphNode message = getCloserLeavingMessage(lifeline, startMessage, getSyncMessages(), true);
+ GraphNode messageReturn = getCloserLeavingMessage(lifeline, startMessage, getSyncMessagesReturn(), true);
+ GraphNode result = getCloserToEvent(message, messageReturn, event);
+ message = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessages(), true);
+ result = getCloserToEvent(result, message, event);
+ messageReturn = getCloserLeavingMessage(lifeline, startMessage, getAsyncMessagesReturn(), true);
+ result = getCloserToEvent(result, messageReturn, event);
+ return result;
+ }
+
+ /**
+ * Get the first execution occurrence.
+ *
+ * @param lifeline A lifeline reference
+ * @return the first execution occurrence of lifeline or <code>null</code>.
+ */
+ public BasicExecutionOccurrence getFirstExecution(Lifeline lifeline) {
+ if (lifeline == null) {
+ return null;
+ }
+ List<GraphNode> list = lifeline.getExecutions();
+
+ if ((list == null) || (list.isEmpty())) {
+ return null;
+ }
+
+ BasicExecutionOccurrence result = (BasicExecutionOccurrence) list.get(0);
+ for (int i = 0; i < list.size(); i++) {
+ BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
+ if ((e.getStartOccurrence() < result.getEndOccurrence())) {
+ result = e;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the previous execution occurrence relative to a given execution occurrence.
+ *
+ * @param exec A execution occurrence reference.
+ * @return the previous execution occurrence of lifeline or <code>null</code>.
+ */
+ public BasicExecutionOccurrence getPrevExecOccurrence(BasicExecutionOccurrence exec) {
+ if (exec == null) {
+ return null;
+ }
+ Lifeline lifeline = exec.getLifeline();
+ if (lifeline == null) {
+ return null;
+ }
+ List<GraphNode> list = lifeline.getExecutions();
+ if (list == null) {
+ return null;
+ }
+ BasicExecutionOccurrence result = null;
+ for (int i = 0; i < list.size(); i++) {
+ BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
+ if ((e.getStartOccurrence() < exec.getStartOccurrence()) && (result == null)) {
+ result = e;
+ }
+ if ((e.getStartOccurrence() < exec.getStartOccurrence()) && (result != null) && (e.getStartOccurrence() >= result.getEndOccurrence())) {
+ result = e;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the next execution occurrence relative to a given execution occurrence.
+ *
+ * @param exec A execution occurrence reference.
+ * @return the next execution occurrence of lifeline or <code>null</code>.
+ */
+ public BasicExecutionOccurrence getNextExecOccurrence(BasicExecutionOccurrence exec) {
+ if (exec == null) {
+ return null;
+ }
+ Lifeline lifeline = exec.getLifeline();
+ if (lifeline == null) {
+ return null;
+ }
+ List<GraphNode> list = lifeline.getExecutions();
+ if (list == null) {
+ return null;
+ }
+ BasicExecutionOccurrence result = null;
+ for (int i = 0; i < list.size(); i++) {
+ BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
+ if ((e.getStartOccurrence() > exec.getStartOccurrence()) && (result == null)) {
+ result = e;
+ }
+ if ((e.getStartOccurrence() > exec.getStartOccurrence()) && (result != null) && (e.getStartOccurrence() <= result.getEndOccurrence())) {
+ result = e;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Get the last execution occurrence.
+ *
+ * @param lifeline A lifeline reference.
+ * @return the last execution occurrence of lifeline or <code>null</code>.
+ */
+ public BasicExecutionOccurrence getLastExecOccurrence(Lifeline lifeline) {
+ if (lifeline == null) {
+ return null;
+ }
+ List<GraphNode> list = lifeline.getExecutions();
+ if (list == null) {
+ return null;
+ }
+ BasicExecutionOccurrence result = null;
+ for (int i = 0; i < list.size(); i++) {
+ BasicExecutionOccurrence e = (BasicExecutionOccurrence) list.get(i);
+ if (result == null) {
+ result = e;
+ }
+ if (e.getStartOccurrence() > result.getEndOccurrence()) {
+ result = e;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return highlighted life line if set else null.
+ * @since 2.0
+ */
+ protected Lifeline getHighlightLifeline() {
+ return fHighlightLifeline;
+ }
+
+ /**
+ * @return the start event value.
+ * @since 2.0
+ */
+ protected int getStartEvent() {
+ return fStartEvent;
+ }
+
+ /**
+ * Returns the number of events
+ *
+ * @return the number of events
+ * @since 2.0
+ */
+ protected int getNumberOfEvents() {
+ return fNbEvent;
+ }
+
+ /**
+ * Returns the highlight color.
+ * @return the highlight color
+ * @since 2.0
+ */
+ protected IColor getHighlightColor() {
+ return fHighlightColor;
+ }
+
+ /**
+ * Set the highlighted life line.
+ * @param lifeline
+ * The highlighted life line if set else null
+ * @since 2.0
+ */
+ protected void setHighlightLifeline(Lifeline lifeline) {
+ fHighlightLifeline = lifeline;
+ }
+
+ /**
+ * Sets the start event value
+ * @param startEvent
+ * the start event value.
+ * @since 2.0
+ */
+ protected void setStartEvent(int startEvent) {
+ fStartEvent = startEvent;
+ }
+
+ /**
+ * Sets the number of events
+ *
+ * @param nbEvents
+ * The number of events
+ * @since 2.0
+ */
+ protected void setNumberOfEvents(int nbEvents) {
+ fNbEvent = nbEvents;
+ }
+
+ /**
+ * Sets the highlight color.
+ * @param color
+ * the highlight color
+ * @since 2.0
+ */
+ protected void setHighlightColor(IColor color) {
+ fHighlightColor = color;
+ }
+
+ /**
+ * sets the list of execution occurrences.
+ *
+ * @param occurences
+ * the list of execution occurrences
+ * @since 2.0
+ */
+ protected void setExecutionOccurrencesWithTime(List<SDTimeEvent> occurences) {
+ fExecutionOccurrencesWithTime = occurences;
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/GraphNode.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/GraphNode.java
new file mode 100755
index 0000000000..f0c026a74a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/GraphNode.java
@@ -0,0 +1,906 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.tracecompass.internal.tmf.ui.TmfUiTracer;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * The base class used for all UML2 graph nodes displayed in the Sequence Diagram SDWidget.
+ *
+ * @author sveyrier
+ * @version 1.0
+ */
+public abstract class GraphNode {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The start event occurrence.
+ */
+ private int fStartEventOccurrence = 0;
+ /**
+ * The event event occurrence.
+ */
+ private int fEndEventOccurrence = 0;
+ /**
+ * Preference ColorId to use to draw font
+ */
+ private String fPrefId = ISDPreferences.PREF_SYNC_MESS;
+ /**
+ * The selection state of the graph node.
+ */
+ private boolean fSelected = false;
+ /**
+ * The focus state of the graph node.
+ */
+ private boolean fFocused = false;
+ /**
+ * Flag to indicate whether node has children or not.
+ */
+ private boolean fHasChilden = false;
+ /**
+ * The graph node name used to label the graph node in the View.
+ */
+ private String fName = ""; //$NON-NLS-1$
+ /**
+ * A map from node name to graph node.
+ */
+ private Map<String, List<GraphNode>> fNodes;
+ /**
+ * A map from node name to graph node for forward sorting
+ */
+ private Map<String, List<GraphNode>> fForwardNodes;
+ /**
+ * A map from node name to graph node for backwards sorting.
+ */
+ private Map<String, List<GraphNode>> fBackwardNodes;
+ /**
+ * A map from node name to index.
+ */
+ private Map<String, Integer> fIndexes;
+ /**
+ * A map from node name to flag for forwards sorting.
+ */
+ private Map<String, Boolean> fForwardSort;
+ /**
+ * A map from node name to flag for backwards sorting.
+ */
+ private Map<String, Boolean> fBackwardSort;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Reset the internal index of the first visible GraphNode for each ordered GraphNode lists
+ */
+ public void resetIndex() {
+ if (!fHasChilden) {
+ return;
+ }
+
+ Iterator<String> it = fIndexes.keySet().iterator();
+ while (it.hasNext()) {
+ String nodeType = it.next();
+ fIndexes.put(nodeType, Integer.valueOf(0));
+ }
+ }
+
+ /**
+ * Add a GraphNode into the receiver
+ *
+ * @param nodeToAdd the node to add
+ */
+ public void addNode(GraphNode nodeToAdd) {
+ if (!fHasChilden) {
+ fNodes = new HashMap<>(2);
+ fForwardNodes = new HashMap<>(2);
+ fBackwardNodes = new HashMap<>(2);
+ fIndexes = new HashMap<>(2);
+ fBackwardSort = new HashMap<>(2);
+ fForwardSort = new HashMap<>(2);
+ fHasChilden = true;
+ }
+
+ // Nothing to add
+ if (nodeToAdd == null) {
+ return;
+ }
+
+ if (fNodes.get(nodeToAdd.getArrayId()) == null) {
+ fNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1));
+ fIndexes.put(nodeToAdd.getArrayId(), Integer.valueOf(0));
+ fForwardNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1));
+ fForwardSort.put(nodeToAdd.getArrayId(), Boolean.FALSE);
+ if (nodeToAdd.getBackComparator() != null) {
+ fBackwardNodes.put(nodeToAdd.getArrayId(), new ArrayList<GraphNode>(1));
+ fBackwardSort.put(nodeToAdd.getArrayId(), Boolean.FALSE);
+ }
+ }
+
+ List<GraphNode> fNodeList = fForwardNodes.get(nodeToAdd.getArrayId());
+ List<GraphNode> bNodeList = null;
+ if (fBackwardNodes != null) {
+ bNodeList = fBackwardNodes.get(nodeToAdd.getArrayId());
+ }
+ if (fNodeList != null && fNodeList.size() > 0) {
+ // check if the nodes are added y ordered
+ // if not, tag the list to sort it later (during draw)
+ GraphNode node = fNodeList.get(fNodeList.size() - 1);
+ Comparator<GraphNode> fcomp = nodeToAdd.getComparator();
+ Comparator<GraphNode> bcomp = nodeToAdd.getBackComparator();
+ if ((fcomp != null) && (fcomp.compare(node, nodeToAdd) > 0)) {
+ fForwardSort.put(nodeToAdd.getArrayId(), Boolean.TRUE);
+ }
+ if ((bcomp != null) && (bcomp.compare(node, nodeToAdd) > 0)) {
+ fBackwardSort.put(nodeToAdd.getArrayId(), Boolean.TRUE);
+ }
+ }
+
+ if (fNodeList == null) {
+ fNodeList = new ArrayList<>();
+ }
+
+ fNodeList.add(nodeToAdd);
+ fNodes.put(nodeToAdd.getArrayId(), fNodeList);
+ fForwardNodes.put(nodeToAdd.getArrayId(), fNodeList);
+ if ((bNodeList != null) && (nodeToAdd.getBackComparator() != null)) {
+ bNodeList.add(nodeToAdd);
+ fBackwardNodes.put(nodeToAdd.getArrayId(), bNodeList);
+ }
+ }
+
+ /**
+ * Set the graph node name.<br>
+ * It is the name display in the view to label the graph node.
+ *
+ * @param nodeName the name to set
+ */
+ public void setName(String nodeName) {
+ fName = nodeName;
+ }
+
+ /**
+ * Returns the graph node name.<br>
+ * It is the name display in the view to label the graph node.
+ *
+ * @return the graph node name
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Tags the the graph node has selected.<br>
+ * WARNING: This method is only used to draw the graph node using the system selection colors. <br>
+ * To use the complete SDViewer selection mechanism (selection management, notification, etc..) see SDWidget class
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#addSelection(GraphNode)
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#removeSelection(GraphNode)
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#clearSelection()
+ * @param selection - true to set selected, false to set unselected
+ */
+ public void setSelected(boolean selection) {
+ fSelected = selection;
+ }
+
+ /**
+ * Tags the the graph node as focused.<br>
+ * WARNING: This method is only used to draw the graph node using the system focus style. <br>
+ * To use the complete SDViewer focus mechanism see SDWidget class
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#addSelection(GraphNode)
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#removeSelection(GraphNode)
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget#clearSelection()
+ * @param focus - true to set focued, false otherwise
+ */
+ public void setFocused(boolean focus) {
+ fFocused = focus;
+ }
+
+ /**
+ * Returns true if the graph node is selected, false otherwise.<br>
+ * The returned value is used to highlight the graph node in the View.
+ *
+ * @return true if selected, false otherwise
+ */
+ public boolean isSelected() {
+ return fSelected;
+ }
+
+ /**
+ * Returns true if the graph node is focused, false otherwise.<br>
+ * The returned value is used to highlight the graph node in the View.
+ *
+ * @return true if focused, false otherwise
+ */
+ public boolean hasFocus() {
+ return fFocused;
+ }
+
+ /**
+ * Returns true if the graph node contains the point given in parameter,
+ * return false otherwise.
+ *
+ * @param x
+ * the x coordinate of the point to test containment
+ * @param y
+ * the y coordinate of the point to test containment
+ * @return true if contained, false otherwise
+ */
+ abstract public boolean contains(int x, int y);
+
+ /**
+ * Returns the x coordinate of the graph node
+ *
+ * @return the x coordinate
+ */
+ abstract public int getX();
+
+ /**
+ * Returns the y coordinate of the graph node
+ *
+ * @return the y coordinate
+ */
+ abstract public int getY();
+
+ /**
+ * Returns the graph node height
+ *
+ * @return the graph node height
+ */
+ abstract public int getHeight();
+
+ /**
+ * Returns the graph node width
+ *
+ * @return the graph node width
+ */
+ abstract public int getWidth();
+
+ /**
+ * Draws the graph node in the given context
+ *
+ * @param context the graphical context to draw in
+ */
+ abstract protected void draw(IGC context);
+
+ /**
+ * Returns the GraphNode visibility for the given visible area. Wrong
+ * visibility calculation, may strongly impact drawing performance
+ *
+ * @param x
+ * The X coordinate
+ * @param y
+ * The Y coordinate
+ * @param width
+ * The width of the area
+ * @param height
+ * The height of the area
+ * @return true if visible, false otherwise
+ */
+ public boolean isVisible(int x, int y, int width, int height) {
+ return true;
+ }
+
+ /**
+ * Return a comparator to sort the GraphNode of the same type This
+ * comparator is used to order the GraphNode array of the given node type.
+ * (see getArrayId).
+ *
+ * @return the comparator
+ */
+ public Comparator<GraphNode> getComparator() {
+ return null;
+ }
+
+ /**
+ * If needed, return a different comparator to backward scan the GraphNode
+ * array
+ *
+ * @return the backward comparator or null if not needed
+ */
+ public Comparator<GraphNode> getBackComparator() {
+ return null;
+ }
+
+ /**
+ * Compare two graphNodes
+ *
+ * @param node
+ * the node to compare to
+ * @return true if equal false otherwise
+ */
+ public boolean isSameAs(GraphNode node) {
+ return false;
+ }
+
+ /**
+ * Return the node type for all class instances. This id is used to store the same nodes kind in the same ordered
+ * array.
+ *
+ * @return the node type identifier
+ */
+ abstract public String getArrayId();
+
+ /**
+ * Return true if the distance from the GraphNode to the given point is positive
+ *
+ * @param x the point x coordinate
+ * @param y the point y coordinate
+ * @return true if positive false otherwise
+ */
+ public boolean positiveDistanceToPoint(int x, int y) {
+ return false;
+ }
+
+ /**
+ * Returns the graph node which contains the point given in parameter WARNING: Only graph nodes in the current
+ * visible area can be returned
+ *
+ * @param x the x coordinate of the point to test
+ * @param y the y coordinate of the point to test
+ * @return the graph node containing the point given in parameter, null otherwise
+ */
+ public GraphNode getNodeAt(int x, int y) {
+ GraphNode toReturn = null;
+
+ if (!fHasChilden) {
+ return null;
+ }
+
+ Iterator<String> it = fNodes.keySet().iterator();
+ GraphNode node = null;
+ while (it.hasNext()) {
+ Object nodeType = it.next();
+ List<GraphNode> list = fNodes.get(nodeType);
+ int index = fIndexes.get(nodeType).intValue();
+ node = getNodeFromListAt(x, y, list, index);
+ if (toReturn == null) {
+ toReturn = node;
+ }
+ if (node != null) {
+ GraphNode internalNode = node.getNodeAt(x, y);
+ if (internalNode != null) {
+ return internalNode;
+ } else if (Math.abs(node.getWidth()) < Math.abs(toReturn.getWidth()) || Math.abs(node.getHeight()) < Math.abs(toReturn.getHeight())) {
+ toReturn = node;
+ }
+ }
+ }
+ return toReturn;
+ }
+
+ /**
+ * Gets node list from node A to node B
+
+ * @param from A from node
+ * @param to A to node
+ * @return the list of nodes
+ */
+ public List<GraphNode> getNodeList(GraphNode from, GraphNode to) {
+ List<GraphNode> result = new ArrayList<>();
+
+ if (from != null) {
+ result.add(from);
+ } else if (to != null) {
+ result.add(to);
+ }
+
+ if ((from == null) || (to == null)) {
+ return result;
+ }
+
+ if (from == to) {
+ return result;
+ }
+
+ int startX = Math.min(from.getX(), Math.min(to.getX(), Math.min(from.getX() + from.getWidth(), to.getX() + to.getWidth())));
+ int endX = Math.max(from.getX(), Math.max(to.getX(), Math.max(from.getX() + from.getWidth(), to.getX() + to.getWidth())));
+ int startY = Math.min(from.getY(), Math.min(to.getY(), Math.min(from.getY() + from.getHeight(), to.getY() + to.getHeight())));
+ int endY = Math.max(from.getY(), Math.max(to.getY(), Math.max(from.getY() + from.getHeight(), to.getY() + to.getHeight())));
+
+ if (!fHasChilden) {
+ return result;
+ }
+
+ Iterator<String> it = fNodes.keySet().iterator();
+ while (it.hasNext()) {
+ Object nodeType = it.next();
+ List<GraphNode> nodesList = fNodes.get(nodeType);
+ if (nodesList == null || nodesList.isEmpty()) {
+ return null;
+ }
+ for (int i = 0; i < nodesList.size(); i++) {
+ GraphNode node = nodesList.get(i);
+ int nw = node.getWidth();
+ int nh = node.getHeight();
+ int nx = node.getX();
+ int ny = node.getY();
+ if (contains(startX, startY, endX - startX, endY - startY, nx + 1, ny + 1) && contains(startX, startY, endX - startX, endY - startY, nx + nw - 2, ny + nh - 2)) {
+ result.add(node);
+ }
+ result.addAll(node.getNodeList(from, to));
+ }
+ }
+
+ if (!result.contains(to)) {
+ result.add(to);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the graph node which contains the point given in parameter for the given graph node list and starting the
+ * iteration at the given index<br>
+ * WARNING: Only graph nodes with smaller coordinates than the current visible area can be returned.<br>
+ *
+ * @param x the x coordinate of the point to test
+ * @param y the y coordinate of the point to test
+ * @param list the list to search in
+ * @param fromIndex list browsing starting point
+ * @return the graph node containing the point given in parameter, null otherwise
+ */
+ protected GraphNode getNodeFromListAt(int x, int y, List<GraphNode> list, int fromIndex) {
+ if (list == null) {
+ return null;
+ }
+ for (int i = fromIndex; i < list.size(); i++) {
+ GraphNode node = list.get(i);
+ if (node.contains(x, y)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the start event occurrence attached to this graphNode.
+ *
+ * @return the start event occurrence attached to the graphNode
+ */
+ public int getStartOccurrence() {
+ return fStartEventOccurrence;
+ }
+
+ /**
+ * Returns the end event occurrence attached to this graphNode
+ *
+ * @return the start event occurrence attached to the graphNode
+ */
+ public int getEndOccurrence() {
+ return fEndEventOccurrence;
+ }
+
+ /**
+ * Computes the index of the first visible GraphNode for each ordered graph node lists depending on the visible area
+ * given in parameter
+ *
+ * @param x visible area top left corner x coordinate
+ * @param y visible area top left corner y coordinate
+ * @param width visible area width
+ * @param height visible area height
+ */
+ public void updateIndex(int x, int y, int width, int height) {
+ if (!fHasChilden) {
+ return;
+ }
+ if(TmfUiTracer.isIndexTraced()) {
+ TmfUiTracer.traceIndex("*****************************\n"); //$NON-NLS-1$
+ TmfUiTracer.traceIndex("Visible area position in virtual screen (x,y)= " + x + " " + y + "\n\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ Iterator<String> it = fNodes.keySet().iterator();
+ while (it.hasNext()) {
+ String nodeType = it.next();
+ int direction = 1;
+ int drawIndex = fIndexes.get(nodeType).intValue();
+ /*
+ * if (x==0) { drawIndex = 0; indexes.put(nodeType,new Integer(drawIndex)); }
+ */
+ if ((fNodes.get(nodeType) != null) && (fNodes.get(nodeType).size() > 1)) {
+ if (fNodes.get(nodeType).get(drawIndex).positiveDistanceToPoint(x, y)) {
+ direction = -1;
+ }
+
+ if (drawIndex == 0) {
+ direction = 1;
+ }
+
+ if ((direction == -1) && (fBackwardNodes.get(nodeType) != null)) {
+ GraphNode currentNode = fNodes.get(nodeType).get(drawIndex);
+ drawIndex = Arrays.binarySearch(fBackwardNodes.get(nodeType).toArray(new GraphNode[fBackwardNodes.get(nodeType).size()]),
+ fNodes.get(nodeType).get(drawIndex), currentNode.getBackComparator());
+ fNodes.put(nodeType, fBackwardNodes.get(nodeType));
+ if (drawIndex < 0) {
+ drawIndex = 0;
+ direction = 1;
+ } else {
+ fNodes.put(nodeType, fBackwardNodes.get(nodeType));
+ }
+ }
+ GraphNode prev = null;
+
+ for (int i = drawIndex; i < fNodes.get(nodeType).size() && i >= 0; i = i + direction) {
+ drawIndex = i;
+ fIndexes.put(nodeType, Integer.valueOf(i));
+
+ GraphNode currentNode = fNodes.get(nodeType).get(i);
+
+ if (prev == null) {
+ prev = currentNode;
+ }
+
+ Comparator<GraphNode> comp = currentNode.getComparator();
+ Map<String, Boolean> sort = fForwardSort;
+
+ if ((direction == -1) && (currentNode.getBackComparator() != null)) {
+ comp = currentNode.getBackComparator();
+ sort = fBackwardSort;
+ }
+
+ if (i < fNodes.get(nodeType).size() - 1) {
+ GraphNode next = fNodes.get(nodeType).get(i + 1);
+
+ if ((comp != null) && (comp.compare(currentNode, next) > 0)) {
+ sort.put(nodeType, Boolean.TRUE);
+ }
+ }
+ if (direction == 1) {
+ if (fNodes.get(nodeType).get(i).positiveDistanceToPoint(x, y)) {
+ break;
+ }
+ } else {
+ if (currentNode.getBackComparator() == null) {
+ if // (currentNode.isVisible(x,y,width,height)
+ (!currentNode.positiveDistanceToPoint(x, y)) {
+ break;
+ }
+ } else {
+ if (currentNode.isVisible(x, y, width, height) && !currentNode.positiveDistanceToPoint(x, y)) {
+ if ((comp != null) && (comp.compare(currentNode, prev) <= 0)) {
+ break;
+ }
+ } else if ((comp != null) && (comp.compare(currentNode, prev) <= 0)) {
+ prev = currentNode;
+ }
+ }
+ }
+ }
+
+ fNodes.put(nodeType, fForwardNodes.get(nodeType));
+ if ((fBackwardNodes.get(nodeType) != null) && (direction == -1)) {
+ // nodes.put(nodeType,fnodes.get(nodeType));
+ int index = fIndexes.get(nodeType).intValue();
+ List<GraphNode> list = fNodes.get(nodeType);
+ List<GraphNode> backList = fBackwardNodes.get(nodeType);
+ GraphNode currentNode = (backList.get(index));
+ if (index > 0) {
+ index = Arrays.binarySearch(list.toArray(new GraphNode[list.size()]), backList.get(index), currentNode.getComparator());
+ if (index < 0) {
+ index = 0;
+ }
+ fIndexes.put(nodeType, Integer.valueOf(index));
+ }
+ }
+
+ for (int i = drawIndex; i < fNodes.get(nodeType).size() && i >= 0; i++) {
+ GraphNode toDraw = fNodes.get(nodeType).get(i);
+ toDraw.updateIndex(x, y, width, height);
+ if (!toDraw.isVisible(x, y, width, height)) {
+ break;
+ }
+ }
+ }
+ if (TmfUiTracer.isIndexTraced()) {
+ TmfUiTracer.traceIndex("First drawn " + nodeType + " index = " + drawIndex + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ TmfUiTracer.traceIndex(nodeType + " found in " + 0 + " iterations\n"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ if (TmfUiTracer.isIndexTraced()) {
+ TmfUiTracer.traceIndex("*****************************\n"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Draws the children nodes on the given context.<br>
+ * This method start width GraphNodes ordering if needed.<br>
+ * After, depending on the visible area, only visible GraphNodes are drawn.<br>
+ *
+ * @param context the context to draw to
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode#draw(IGC)
+ */
+ protected void drawChildenNodes(IGC context) {
+
+ if (!fHasChilden) {
+ return;
+ }
+ // If the nodes have not been added ordered, the array is ordered
+ Iterator<String> it = fForwardSort.keySet().iterator();
+ while (it.hasNext()) {
+ String nodeType = it.next();
+ boolean sort = fForwardSort.get(nodeType).booleanValue();
+ if (sort) {
+ GraphNode[] temp = fForwardNodes.get(nodeType).toArray(new GraphNode[fForwardNodes.get(nodeType).size()]);
+ GraphNode node = fNodes.get(nodeType).get(0);
+ Arrays.sort(temp, node.getComparator());
+ fForwardSort.put(nodeType, Boolean.FALSE);
+ fNodes.put(nodeType, Arrays.asList(temp));
+ fForwardNodes.put(nodeType, Arrays.asList(temp));
+ if (TmfUiTracer.isSortingTraced()) {
+ TmfUiTracer.traceSorting(nodeType + " array sorted\n"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ Iterator<String> it2 = fBackwardSort.keySet().iterator();
+ while (it2.hasNext()) {
+ String nodeType = it2.next();
+ boolean sort = fBackwardSort.get(nodeType).booleanValue();
+ if (sort) {
+ GraphNode[] temp = fBackwardNodes.get(nodeType).toArray(new GraphNode[fBackwardNodes.get(nodeType).size()]);
+ GraphNode node = fNodes.get(nodeType).get(0);
+ Arrays.sort(temp, node.getBackComparator());
+ fBackwardSort.put(nodeType, Boolean.FALSE);
+ fBackwardNodes.put(nodeType, Arrays.asList(temp));
+ if (TmfUiTracer.isSortingTraced()) {
+ TmfUiTracer.traceSorting(nodeType + " back array sorted\n"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ if (TmfUiTracer.isDisplayTraced()) {
+ TmfUiTracer.traceDisplay("*****************************\n"); //$NON-NLS-1$
+ }
+
+ int arrayStep = 1;
+ if ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * context.getZoom() < Metrics.MESSAGE_SIGNIFICANT_VSPACING) {
+ arrayStep = Math.round(Metrics.MESSAGE_SIGNIFICANT_VSPACING / ((Metrics.getMessageFontHeigth() + Metrics.MESSAGES_NAME_SPACING * 2) * context.getZoom()));
+ }
+
+ int count = 0;
+ Iterator<String> it3 = fForwardSort.keySet().iterator();
+ while (it3.hasNext()) {
+ count = 0;
+ Object nodeType = it3.next();
+ GraphNode node = fNodes.get(nodeType).get(0);
+ context.setFont(SDViewPref.getInstance().getFont(node.fPrefId));
+ int index = fIndexes.get(nodeType).intValue();
+ count = drawNodes(context, fNodes.get(nodeType), index, arrayStep);
+ if (TmfUiTracer.isDisplayTraced()) {
+ TmfUiTracer.traceDisplay(count + " " + nodeType + " drawn, starting from index " + index + "\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ if (TmfUiTracer.isDisplayTraced()) {
+ TmfUiTracer.traceDisplay("*****************************\n"); //$NON-NLS-1$
+ }
+
+ }
+
+ /**
+ * Draw the GraphNode stored in the given list, starting at index startIndex with the given step
+ *
+ * @param context the context to draw to
+ * @param list the GraphNodes list
+ * @param startIndex the start index
+ * @param step the step to browse the list
+ * @return the number of GraphNodes drawn
+ */
+ protected int drawNodes(IGC context, List<GraphNode> list, int startIndex, int step) {
+ if (!fHasChilden) {
+ return 0;
+ }
+
+ GraphNode last = null;
+ int nodesCount = 0;
+ if (list.size() < 0) {
+ return 0;
+ }
+
+ GraphNode node = list.get(0);
+ context.setFont(SDViewPref.getInstance().getFont(node.fPrefId));
+ Comparator<GraphNode> comparator = node.getComparator();
+ for (int i = startIndex; i < list.size(); i = i + step) {
+ GraphNode toDraw = list.get(i);
+ if (i < list.size() - 1) {
+ GraphNode next = list.get(i + 1);
+ if ((comparator != null) && (comparator.compare(toDraw, next) > 0)) {
+ fForwardSort.put(next.getArrayId(), Boolean.TRUE);
+ }
+ }
+ int cx = context.getContentsX();
+ int cy = context.getContentsY();
+ int cw = context.getVisibleWidth();
+ int ch = context.getVisibleHeight();
+ // The arrays should be ordered, no needs to continue for this one
+ if (!toDraw.isVisible(cx, cy, cw, ch) && toDraw.positiveDistanceToPoint(cx + cw, cy + ch)) {
+ break;
+ }
+ // ***Common*** nodes visibility
+ if ((!toDraw.isSameAs(last) || toDraw.isSelected()) && (toDraw.isVisible(context.getContentsX(), context.getContentsY(), context.getVisibleWidth(), context.getVisibleHeight()))) {
+ nodesCount++;
+
+ toDraw.draw(context);
+ if (hasFocus()) {
+ toDraw.drawFocus(context);
+ }
+ }
+ last = toDraw;
+ }
+ return nodesCount;
+ }
+
+ /**
+ * Draws the focus within the graphical context.
+ *
+ * @param context
+ * The context
+ */
+ public void drawFocus(IGC context) {
+ context.drawFocus(getX(), getY(), getWidth(), getHeight());
+ }
+
+ /**
+ * Determine if the given point (px,py) is contained in the rectangle (x,y,width,height)
+ *
+ * @param x the rectangle x coordinate
+ * @param y the rectangle y coordinate
+ * @param width the rectangle width
+ * @param height the rectangle height
+ * @param px the x coordinate of the point to test
+ * @param py the y coordinate of the point to test
+ * @return true if contained false otherwise
+ */
+ public static boolean contains(int x, int y, int width, int height, int px, int py) {
+ int locX = x;
+ int locY = y;
+ int locWidth = width;
+ int locHeight = height;
+
+ if (width < 0) {
+ locX = locX + width;
+ locWidth = -locWidth;
+ }
+
+ if (height < 0) {
+ locY = locY + height;
+ locHeight = -locHeight;
+ }
+ return (px >= locX) && (py >= locY) && ((px - locX) <= locWidth) && ((py - locY) <= locHeight);
+ }
+
+ /**
+ * Sets the start event occurrence attached to this graphNode.
+ *
+ * @param occurence
+ * the start event occurrence attached to the graphNode
+ * @since 2.0
+ */
+ protected void setStartOccurrence(int occurence) {
+ fStartEventOccurrence = occurence;
+ }
+
+ /**
+ * Sets the end event occurrence attached to this graphNode
+ *
+ * @param occurence
+ * the start event occurrence attached to the graphNode
+ * @since 2.0
+ */
+ protected void setEndOccurrence(int occurence) {
+ fEndEventOccurrence = occurence;
+ }
+
+ /**
+ * Sets the color preference id
+ * @param id
+ * The color preference id
+ * @since 2.0
+ */
+ protected void setColorPrefId(String id) {
+ fPrefId = id;
+ }
+
+ /**
+ * Gets the color preference id
+ * @return the color preference id
+ * @since 2.0
+ */
+ protected String getColorPrefId() {
+ return fPrefId;
+ }
+
+ /**
+ * @return if node has children or not
+ * @since 2.0
+ */
+ protected boolean hasChildren() {
+ return fHasChilden;
+ }
+
+ /**
+ * Sets the flag indicating where the node has children or not.
+ * @param hasChildren
+ * if node has children or not
+ * @since 2.0
+ */
+ protected void hasChildren(boolean hasChildren) {
+ fHasChilden = hasChildren;
+ }
+ /**
+ * Returns a map from node name to graph node.
+ *
+ * @return map with children graph bodes
+ * @since 2.0
+ */
+ protected Map<String, List<GraphNode>> getNodeMap() {
+ return fNodes;
+ }
+ /**
+ * Returns a map from node name to graph node for forward sorting
+ *
+ * @return forward sorting map
+ * @since 2.0
+ */
+ protected Map<String, List<GraphNode>> getForwardNodes() {
+ return fForwardNodes;
+ }
+ /**
+ * Returns a map from node name to graph node for backwards sorting.
+ *
+ * @return backwards sorting map
+ * @since 2.0
+ */
+ protected Map<String, List<GraphNode>> getBackwardNodes() {
+ return fBackwardNodes;
+ }
+ /**
+ * Returns a map from node name to index.
+ *
+ * @return map with node name to index
+ * @since 2.0
+ */
+ protected Map<String, Integer> getIndexes() {
+ return fIndexes;
+ }
+
+ /**
+ * Returns a map from node name to sort flag for forwards sorting.
+ * @return a map from node name to sort flag
+ * @since 2.0
+ */
+ protected Map<String, Boolean> getForwardSortMap() {
+ return fForwardSort;
+ }
+ /**
+ * Returns a map from node name to flag for backwards sorting.
+ * @return map from node name to flag for backwards sorting.
+ * @since 2.0
+ */
+ protected Map<String, Boolean> getBackwardSortMap() {
+ return fBackwardSort;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/HotSpot.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/HotSpot.java
new file mode 100755
index 0000000000..703db9c1f4
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/HotSpot.java
@@ -0,0 +1,193 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * Class to add a hot spot marker.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class HotSpot extends GraphNode {
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The grahNode ID constant
+ */
+ public static final String GLYPH = "Glyph"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The execution occurrence the hot spot marker is for.
+ */
+ private BasicExecutionOccurrence fExecOcc = null;
+ /**
+ * The occurrence number.
+ */
+ private int fOccurrence = 0;
+ /**
+ * The marker image to display.
+ */
+ private IImage fImage = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public HotSpot() {
+ setColorPrefId(ISDPreferences.PREF_EXEC);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set the marker image.
+ *
+ * @param img A image to set
+ */
+ public void setImage(IImage img) {
+ fImage = img;
+ }
+
+ /**
+ * Returns the marker image.
+ *
+ * @return the image
+ * @since 2.0
+ */
+ protected IImage getImage() {
+ return fImage;
+ }
+
+ @Override
+ public int getX() {
+ if (fExecOcc != null) {
+ return fExecOcc.getX() - 3;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getY() {
+ if (fExecOcc != null){
+ return fExecOcc.getY();
+ }
+ return 0;
+ }
+
+ @Override
+ public int getWidth() {
+ if (fExecOcc != null) {
+ return fExecOcc.getWidth() + 7;
+ }
+ return 0;
+ }
+
+ @Override
+ public int getHeight() {
+ if (fExecOcc != null) {
+ return fExecOcc.getWidth() + 10;
+ }
+ return 0;
+ }
+
+ /**
+ * Set the lifeline on which the execution occurrence appears.
+ *
+ * @param occ the parent lifeline
+ */
+ public void setExecution(BasicExecutionOccurrence occ) {
+ fExecOcc = occ;
+ fExecOcc.addNode(this);
+ }
+
+ /**
+ * Get the lifeline on which the execution occurrence appears.
+ *
+ * @return - the parent lifeline
+ */
+ public BasicExecutionOccurrence getExecOcc() {
+ return fExecOcc;
+ }
+
+ /**
+ * Returns the occurrence number.
+ *
+ * @return the occurrence number.
+ */
+ public int getOccurrence() {
+ return fOccurrence;
+ }
+
+ /**
+ * Set the occurrence number.
+ *
+ * @param occ A number to set.
+ */
+ public void setOccurrence(int occ) {
+ fOccurrence = occ;
+ }
+
+ @Override
+ public void draw(IGC context) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // The execution occurrence is selected
+ // if the owning lifeline is selected
+ if (isSelected() || (fExecOcc != null && fExecOcc.isSelected()) || (fExecOcc != null && fExecOcc.getLifeline() != null && fExecOcc.getLifeline().isSelected())) {
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ } else {
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_EXEC));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_EXEC));
+ }
+ context.drawImage(fImage, getX(), getY(), getWidth(), getHeight());
+ }
+
+ @Override
+ public String getArrayId() {
+ return GLYPH;
+ }
+
+ @Override
+ public boolean isVisible(int x, int y, int width, int height) {
+ return true;
+ }
+
+ @Override
+ public boolean contains(int xValue, int yValue) {
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+
+ if (GraphNode.contains(x, y, width, height, xValue, yValue)) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ITimeRange.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ITimeRange.java
new file mode 100755
index 0000000000..9ea37acf4a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/ITimeRange.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+
+/**
+ * A interface for handling time ranges.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ITimeRange {
+
+ /**
+ * Returns the time when the message began.
+ * @return the time when the message began
+ * @since 2.0
+ */
+ ITmfTimestamp getStartTime();
+
+ /**
+ * Returns the time when the message ended.
+ *
+ * @return the time when the message ended
+ * @since 2.0
+ */
+ ITmfTimestamp getEndTime();
+
+ /**
+ * Returns flag to indicate whether time information is available or not.
+ *
+ * @return flag to indicate whether time information is available or not
+ */
+ boolean hasTimeInfo();
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Lifeline.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Lifeline.java
new file mode 100755
index 0000000000..3bbabf1238
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Lifeline.java
@@ -0,0 +1,534 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * Lifeline is the UML2 lifeline graphical representation.<br>
+ * Each lifeline owns a set of event occurrences. An event occurrence is the base element in UML2 to set an event in a
+ * sequence diagram.<br>
+ * Event occurrence define the drawing order of graph node along a lifeline. In this lifeline implementation, event
+ * occurrences are just integer index. The event occurrences with the same value on different lifelines will correspond
+ * the same y coordinate value.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class Lifeline extends GraphNode {
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The life line tag.
+ */
+ public static final String LIFELINE_TAG = "Lifeline"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attribute
+ // ------------------------------------------------------------------------
+ /**
+ * The lifeline position in the containing frame
+ */
+ private int fIndexInFrame = 0;
+ /**
+ * The frame where the lifeline is drawn
+ */
+ private Frame fFrame = null;
+ /**
+ * The current event occurrence created in the lifeline
+ */
+ private int fEventOccurrence = 0;
+ /**
+ * The lifeline category.
+ */
+ private int fCategory = -1;
+ /**
+ * Flag whether lifeline has time information available or not
+ */
+ private boolean fHasTimeInfo = false;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public Lifeline() {
+ setColorPrefId(ISDPreferences.PREF_LIFELINE);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int getX() {
+ return Metrics.FRAME_H_MARGIN + Metrics.LIFELINE_H_MAGIN + (fIndexInFrame - 1) * Metrics.swimmingLaneWidth();
+ }
+
+ @Override
+ public int getY() {
+ return 2 * Metrics.FRAME_NAME_H_MARGIN + Metrics.LIFELINE_VT_MAGIN / 2 + Metrics.getFrameFontHeigth() + Metrics.getLifelineHeaderFontHeigth() + Metrics.FRAME_V_MARGIN + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
+ }
+
+ @Override
+ public int getWidth() {
+ return Metrics.getLifelineWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ // Set room for two text lines
+ return Metrics.getLifelineFontHeigth()/** 2 */
+ + 2 * Metrics.LIFELINE_NAME_H_MARGIN;
+ }
+
+ /**
+ * Set the lifeline category for this lifeline.
+ *
+ * @param arrayIndex the index of the category to use
+ * @see Frame#setLifelineCategories(LifelineCategories[])
+ */
+ public void setCategory(int arrayIndex) {
+ fCategory = arrayIndex;
+ }
+
+ /**
+ * Gets the lifeline category for this lifeline.
+ *
+ * @return arrayIndex the index of the category to use
+ * @since 2.0
+ */
+ public int getCategory() {
+ return fCategory;
+ }
+
+ /**
+ * Returns the tooltip text for the lifeline. It is the combination between the category name(if any) and the
+ * lifeline name
+ *
+ * @return the tooltip text
+ */
+ public String getToolTipText() {
+ if (fCategory >= 0) {
+ LifelineCategories[] categories = fFrame.getLifelineCategories();
+ if (fCategory < categories.length) {
+ return categories[fCategory].getName() + " " + getName(); //$NON-NLS-1$
+ }
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Returns the index of the first visible Execution Occurrence in the execution occurrence array.<br>
+ * Execution Occurrences are Y ordered in this array
+ *
+ * @return the first visible Execution Occurrence
+ */
+ public int getExecOccurrenceDrawIndex() {
+ if (!hasChildren()) {
+ return 0;
+ }
+ if (getIndexes().get(BasicExecutionOccurrence.EXEC_OCC_TAG) != null) {
+ return getIndexes().get(BasicExecutionOccurrence.EXEC_OCC_TAG).intValue();
+ }
+ return 0;
+ }
+
+ /**
+ * Set the frame on which this lifeline must be drawn
+ *
+ * @param parentFrame
+ * Parent frame
+ */
+ protected void setFrame(Frame parentFrame) {
+ fFrame = parentFrame;
+ if (fHasTimeInfo) {
+ fFrame.setHasTimeInfo(true);
+ }
+ if (fFrame.getMaxEventOccurrence() < getEventOccurrence() + 1) {
+ fFrame.setMaxEventOccurrence(getEventOccurrence() + 1);
+ }
+ }
+
+ /**
+ * Returns the frame which this lifeline is drawn
+ *
+ * @return the Frame
+ */
+ protected Frame getFrame() {
+ return fFrame;
+ }
+
+ /**
+ * Set the lifeline position index in the containing frame
+ *
+ * @param index the lifeline X position
+ */
+ protected void setIndex(int index) {
+ fIndexInFrame = index;
+ }
+
+ /**
+ * Returns the lifeline position in de the containing frame
+ *
+ * @return the X position
+ */
+ public int getIndex() {
+ return fIndexInFrame;
+ }
+
+ /**
+ * Set the lifeline event occurrence to the value given in parameter This only change the current event occurrence,
+ * greater event created on this lifeline are still valid and usable. This also need to inform the frame of the
+ * operation mostly to store in the frame the greater event found in the diagram (used to determine the frame
+ * height)
+ *
+ * @param eventOcc the new current event occurrence
+ */
+ public void setCurrentEventOccurrence(int eventOcc) {
+ if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < eventOcc)) {
+ fFrame.setMaxEventOccurrence(eventOcc);
+ }
+ fEventOccurrence = eventOcc;
+ }
+
+ /**
+ * Returns the last created event occurrence along the lifeline.
+ *
+ * @return the current event occurrence
+ */
+ public int getEventOccurrence() {
+ return fEventOccurrence;
+ }
+
+ /**
+ * Creates a new event occurrence along the lifeline.
+ *
+ * @return the new created event occurrence
+ */
+ public int getNewEventOccurrence() {
+ setCurrentEventOccurrence(fEventOccurrence + 1);
+ return fEventOccurrence;
+ }
+
+ /**
+ * Adds the execution occurrence given in parameter to the lifeline.<br>
+ * A Execution occurrence is never drawn in the frame instead it is added to a lifeline
+ *
+ * @param exec the execution occurrence to add
+ */
+ public void addExecution(BasicExecutionOccurrence exec) {
+ exec.setLifeline(this);
+ addNode(exec);
+ if ((fFrame != null) && (fFrame.getMaxEventOccurrence() < exec.getEndOccurrence())) {
+ fFrame.setMaxEventOccurrence(exec.getEndOccurrence());
+ }
+ }
+
+ /**
+ * Set whether lifeline has time information available or not.
+ * @param value The value to set
+ */
+ protected void setTimeInfo(boolean value) {
+ fHasTimeInfo = value;
+ if ((fFrame != null) && value) {
+ fFrame.setHasTimeInfo(value);
+ }
+ }
+
+ /**
+ * Returns true if at least one execution occurrence has time info.
+ *
+ * @return true if at least one execution occurrence has time info
+ */
+ public boolean hasTimeInfo() {
+ return fHasTimeInfo;
+ }
+
+ /**
+ * Returns the list of execution occurrence on this lifeline.
+ *
+ * @return the execution occurrence list
+ */
+ public List<GraphNode> getExecutions() {
+ if (hasChildren()) {
+ return getNodeMap().get(BasicExecutionOccurrence.EXEC_OCC_TAG);
+ }
+ return new ArrayList<>();
+ }
+
+ @Override
+ public boolean contains(int xValue, int yValue) {
+ int x = getX();
+ int y = getY();
+ int width = getWidth();
+ int height = getHeight();
+
+ if (fFrame == null) {
+ return false;
+ }
+ if (GraphNode.contains(x, y, width, height, xValue, yValue)) {
+ return true;
+ }
+ if (GraphNode.contains(x + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2, y + height, Metrics.EXECUTION_OCCURRENCE_WIDTH, (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence()
+ + Metrics.LIFELINE_VB_MAGIN - 4, xValue, yValue)) {
+ return true;
+ }
+
+ height = Metrics.getLifelineFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
+ int hMargin = (Metrics.LIFELINE_VT_MAGIN - height) / 2;
+
+ if (hMargin >= 2) {
+ if (fFrame.getVisibleAreaY() < y - height - hMargin) {
+ if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height + 1, xValue, yValue)) {
+ return true;
+ }
+ } else {
+ if (GraphNode.contains(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height, xValue, yValue)) {
+ return true;
+ }
+ }
+ }
+ if (getNodeAt(xValue, yValue) != null) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the lifeline visibility for the given visible area
+ *
+ * @param vx The x coordinate of the visible area
+ * @param vy The y coordinate of the visible area
+ * @param vwidth The width of the visible area
+ * @param vheight The height of the visible area
+ * @return true if visible false otherwise
+ */
+ @Override
+ public boolean isVisible(int vx, int vy, int vwidth, int vheight) {
+ int x = getX();
+ int width = getWidth();
+ if (((x >= vx) && (x <= vx + vwidth)) || ((x + width >= vx) && (x <= vx))) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Draws the name within the graphical context.
+ *
+ * @param context The graphical context.
+ */
+ protected void drawName(IGC context) {
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ int x = getX();
+ int y = getY();
+ int height = Metrics.getLifelineHeaderFontHeigth() + 2 * Metrics.LIFELINE_HEARDER_TEXT_V_MARGIN;
+ int hMargin = Metrics.LIFELINE_VT_MAGIN / 4;// (Metrics.LIFELINE_NAME_H_MARGIN)/2;
+
+ context.setLineStyle(context.getLineSolidStyle());
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE_HEADER));
+ if (hMargin >= 0) {
+ if (fFrame.getVisibleAreaY() < y - height - hMargin) {
+ context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height);
+ context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2, height);
+ context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ context.drawTextTruncatedCentred(getName(), x + Metrics.LIFELINE_NAME_V_MARGIN - Metrics.LIFELINE_SPACING / 2 + 1, y - height - hMargin, Metrics.swimmingLaneWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN - 2, height, true);
+ } else {
+ context.fillRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height);
+ context.drawRectangle(x - Metrics.LIFELINE_SPACING / 2 + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2, height);
+ context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE_HEADER));
+ context.drawTextTruncatedCentred(getName(), x - Metrics.LIFELINE_SPACING / 2 + Metrics.LIFELINE_NAME_V_MARGIN + 1, fFrame.getVisibleAreaY(), Metrics.swimmingLaneWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN - 2, height, true);
+ }
+ }
+ }
+
+ /**
+ * Force the lifeline to be drawn at the given coordinate
+ *
+ * @param context - the context to draw into
+ * @param x - the x coordinate
+ * @param y - the y coordinate
+ */
+ public void draw(IGC context, int x, int y) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // Set the draw color depending if the lifeline must be selected or not
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ if (isSelected()) {
+ if (pref.useGradienColor()) {
+ context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
+ }
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ } else {
+ if (pref.useGradienColor()) {
+ context.setGradientColor(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_FRAME));
+ } else {
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
+ }
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE));
+ }
+ // Store the lifeline coordinates to save some calls
+ int width = getWidth();
+ int height = getHeight();
+
+ // Draw the rectangle which contain the lifeline name
+ if (pref.useGradienColor()) {
+ context.fillGradientRectangle(x, y, width, height / 2 - 7, true);
+ context.fillRectangle(x, y + height / 2 - 8, width, +height / 2 - 5);
+ context.fillGradientRectangle(x, y + height, width, -height / 2 + 6, true);
+ } else {
+ context.fillRectangle(x, y, width, height);
+ }
+ context.drawRectangle(x, y, width, height);
+
+ if (fCategory >= 0) {
+ LifelineCategories[] categories = fFrame.getLifelineCategories();
+ if (fCategory < categories.length) {
+ IImage image = categories[fCategory].getImage();
+ if (image != null) {
+ context.drawImage(image, x, y, width, height);
+ }
+ }
+ }
+
+ // Draw the lifeline label into the rectangle
+ // The label is truncated if it cannot fit
+ IColor temp = context.getForeground();
+ context.setFont(pref.getFont(ISDPreferences.PREF_LIFELINE));
+ context.setForeground(pref.getFontColor(ISDPreferences.PREF_LIFELINE));
+ context.drawTextTruncatedCentred(getName(), x + Metrics.LIFELINE_NAME_V_MARGIN, y, Metrics.getLifelineWidth() - 2 * Metrics.LIFELINE_NAME_V_MARGIN, height, true);
+
+ context.setLineStyle(context.getLineDashStyle());
+ context.setForeground(temp);
+ int oldStyle = context.getLineStyle();
+
+ // Now draw the lifeline vertical line
+ // this line height depends on a stop assignment
+ // if there is no stop the line is drawn to the bottom of the frame
+
+ // by default set the height to reach the frame bottom
+ int dashedLineEnd = y + height + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fFrame.getMaxEventOccurrence() + Metrics.LIFELINE_VB_MAGIN;
+ /*
+ * if (stop != null) { dashedLineEnd = stop.getY(); }
+ */
+
+ if (isSelected()) {
+ context.setForeground(pref.getBackGroundColorSelection());
+ context.setLineWidth(5);
+ context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
+ context.setForeground(pref.getForeGroundColorSelection());
+ }
+
+ context.setLineWidth(Metrics.NORMAL_LINE_WIDTH);
+ context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
+ context.drawLine(x + Metrics.getLifelineWidth() / 2, y + height, x + Metrics.getLifelineWidth() / 2, dashedLineEnd - 4);
+ context.setLineStyle(oldStyle);
+
+ context.setLineStyle(context.getLineSolidStyle());
+
+ if (hasFocus()) {
+ drawFocus(context);
+ }
+
+ super.drawChildenNodes(context);
+ }
+
+ /**
+ * Draws the select execution occurrence region using the given color
+ *
+ * @param context the graphical context
+ * @param startEvent the region start
+ * @param nbEvent the region height
+ * @param color the color to use
+ */
+ public void highlightExecOccurrenceRegion(IGC context, int startEvent, int nbEvent, IColor color) {
+ IColor backupColor = context.getBackground();
+ context.setBackground(color);
+ int x = getX() + Metrics.getLifelineWidth() / 2 - Metrics.EXECUTION_OCCURRENCE_WIDTH / 2;
+ int y = getY() + getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * startEvent;
+ int width = Metrics.EXECUTION_OCCURRENCE_WIDTH;
+ int height = ((Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing())) * nbEvent;
+ context.fillRectangle(x, y, width, height);
+ context.setBackground(backupColor);
+ }
+
+ @Override
+ public void draw(IGC context) {
+ draw(context, getX(), getY());
+ }
+
+ @Override
+ public String getArrayId() {
+ return LIFELINE_TAG;
+ }
+
+ @Override
+ public boolean positiveDistanceToPoint(int x, int y) {
+ if (getX() > x - Metrics.swimmingLaneWidth()) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public GraphNode getNodeAt(int x, int y) {
+ int vy = 0;
+ int vh = 0;
+ if (getFrame() != null) {
+ vy = getFrame().getVisibleAreaY();
+ vh = getFrame().getVisibleAreaHeight();
+ } else {
+ return null;
+ }
+ if (getExecutions() == null) {
+ return null;
+ }
+ for (int i = getExecOccurrenceDrawIndex(); i < getExecutions().size(); i++) {
+ GraphNode node = getExecutions().get(i);
+ if (node.getHeight() < 0) {
+ if (node.getY() + node.getHeight() > vy + vh) {
+ break;
+ }
+ } else {
+ if (node.getY() > vy + vh) {
+ break;
+ }
+ }
+ if (node.contains(x, y)) {
+ GraphNode internal = node.getNodeAt(x, y);
+ if (internal != null) {
+ return internal;
+ }
+ return node;
+ }
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/LifelineCategories.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/LifelineCategories.java
new file mode 100755
index 0000000000..db1449caad
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/LifelineCategories.java
@@ -0,0 +1,81 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+
+/**
+ * <p>
+ * LifelineCategories is used to assign additional description for
+ * lifelines of the same type. This consists in providing a type name and an icon.
+ * The icon will be displayed in the rectangle which contains the lifeline name.
+ * The category name is only display in the lifeline tooltip.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class LifelineCategories {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The category name
+ */
+ private String fName = null;
+ /**
+ * The category image
+ */
+ private IImage fCategoryImage = null;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the category name.
+ *
+ * @return the category name
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * Sets the category name.
+ *
+ * @param string the name
+ */
+ public void setName(String string) {
+ fName = string;
+ }
+
+ /**
+ * Returns the category icon.
+ *
+ * @return the category icon
+ */
+ public IImage getImage() {
+ return fCategoryImage;
+ }
+
+ /**
+ * Sets the category icon.
+ *
+ * @param image the icon
+ */
+ public void setImage(IImage image) {
+ fCategoryImage = image;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Metrics.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Metrics.java
new file mode 100755
index 0000000000..57f6a13193
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Metrics.java
@@ -0,0 +1,332 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2012 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+/**
+ * This class contains the metrics used to layout a sequence diagram on a view The class method are mostly used in
+ * combination with the preferences
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class Metrics {
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Space between the Frame and the top of the View This also represent the space between the frame and the bottom of
+ * the View
+ */
+ public static final int FRAME_H_MARGIN = 10;
+ /**
+ * Space between the Frame and the left of the View This also represent the space between the Frame and the right of
+ * the View
+ */
+ public static final int FRAME_V_MARGIN = 10;
+ /**
+ * Space between the Lifelines and the right of the Frame
+ */
+ public static final int LIFELINE_H_MAGIN = 23;
+ /**
+ * Space between the Lifelines and the bottom of the Frame
+ */
+ public static final int LIFELINE_VB_MAGIN = 20;
+ /**
+ * Space between the Lifelines and the top of the Frame
+ */
+ public static final int LIFELINE_VT_MAGIN = 30;// 18
+ /**
+ * Vertical space between the lifeline name and the rectangle which contains that name This is only for the
+ * "always visible" lifeline name rectangle
+ */
+ public static final int LIFELINE_HEARDER_TEXT_V_MARGIN = 4;
+ /**
+ * Vertical spacing between messages
+ */
+ public static final int MESSAGES_SPACING = 30;
+ /**
+ * Vertical spacing between the message and its name
+ */
+ public static final int MESSAGES_NAME_SPACING = 10;
+ /**
+ * Horizontal spacing between the Frame name and its containing rectangle
+ */
+ public static final int FRAME_NAME_H_MARGIN = 4;
+ /**
+ * Vertical spacing between the Frame name and its containing rectangle
+ */
+ public static final int FRAME_NAME_V_MARGIN = 8;
+ /**
+ * Horizontal spacing between the lifeline name and its containing rectangle
+ */
+ public static final int LIFELINE_NAME_H_MARGIN = 14;
+ /**
+ * Vertical spacing between the lifeline name and its containing rectangle
+ */
+ public static final int LIFELINE_NAME_V_MARGIN = 20;
+ /**
+ * Space between the rectangles which contain the Lifelines name
+ */
+ public static final int LIFELINE_SPACING = 45;
+ /**
+ * The circle ray used to draw the circle which compose Found and Lost messages
+ */
+ public static final int MESSAGE_CIRCLE_RAY = 5;
+ /**
+ * Execution occurrence vertical width
+ */
+ public static final int EXECUTION_OCCURRENCE_WIDTH = 8;
+ /**
+ * The square width which contains the Stop representation (a cross)
+ */
+ public static final int STOP_WIDTH = 20;
+ /**
+ * The internal message width.
+ */
+ public static final int INTERNAL_MESSAGE_WIDTH = 20;
+ /**
+ * The internal sychrounous message height.
+ */
+ public static final int SYNC_INTERNAL_MESSAGE_HEIGHT = 10;
+ /**
+ * Line width used when drawing selected GraphNode
+ */
+ public static final int SELECTION_LINE_WIDTH = 5;
+ /**
+ * Line width used when drawing non selected GraphNode
+ */
+ public static final int NORMAL_LINE_WIDTH = 1;
+ /**
+ * The internal vertical message margin
+ */
+ public static final int INTERNAL_MESSAGE_V_MARGIN = 10;
+
+ /**
+ * Used to sample the diagram. When the lifeline spacing is smaller than this constant when zooming out then less
+ * lifelines are displayed to avoid lifelines overlapping and mainly saving some execution time
+ */
+ public static final int LIFELINE_SIGNIFICANT_HSPACING = 10;
+ /**
+ * Used to sample the diagram. When the message spacing is smaller than this constant when zooming out then less
+ * message are displayed to avoid message overlapping and mainly saving some execution time
+ */
+ public static final int MESSAGE_SIGNIFICANT_VSPACING = 1;
+ /**
+ * Message selection tolerance. Used for internal syncMessages only
+ */
+ public static final int MESSAGE_SELECTION_TOLERANCE = 30;
+ /**
+ * The focus drawing margin.
+ */
+ public static final int FOCUS_DRAWING_MARGIN = 10;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The lifeline font height
+ */
+ private static int fLifelineFontHeight = 0;
+ /**
+ * The message font height
+ */
+ private static int fMessageFontHeight = 0;
+ /**
+ * The frame font height
+ */
+ private static int fFrameFontHeight = 0;
+ /**
+ * The lifeline header font height
+ */
+ private static int fLifelineHeaderFontHeight = 0;
+ /**
+ * The lifeline font widht
+ */
+ private static int fLifelineFontWidth = 0;
+ /**
+ * The lifeline width
+ */
+ private static int fLifeLineWidth = 119;
+ /**
+ * The (forced) event spacing
+ */
+ private static int fForcedEventSpacing = -1;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor
+ *
+ * Hide private constructor
+ */
+ private Metrics() {
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set the character height used to draw the lifeline name
+ *
+ * @param height the character height
+ */
+ static public void setLifelineFontHeight(int height) {
+ fLifelineFontHeight = height;
+ }
+
+ /**
+ * Set the character width used to draw the lifeline name
+ *
+ * @param width the character width
+ */
+ static public void setLifelineFontWidth(int width) {
+ fLifelineFontWidth = width;
+ }
+
+ /**
+ * Set the character height used to draw the message name
+ *
+ * @param fontHeight the character height
+ */
+ static public void setMessageFontHeight(int fontHeight) {
+ fMessageFontHeight = fontHeight;
+ }
+
+ /**
+ * Returns the character height used to draw the lifeline name
+ *
+ * @return the character height
+ */
+ static public int getFrameFontHeigth() {
+ return fFrameFontHeight;
+ }
+
+ /**
+ * Set the character height used to draw the message name
+ *
+ * @param fontHeight the character height
+ */
+ static public void setFrameFontHeight(int fontHeight) {
+ fFrameFontHeight = fontHeight;
+ }
+
+ /**
+ * Returns the character height used to draw the lifeline name
+ *
+ * @return the character height
+ */
+ static public int getLifelineHeaderFontHeigth() {
+ return fLifelineHeaderFontHeight;
+ }
+
+ /**
+ * Set the character height used to draw the message name
+ *
+ * @param fontHeight the character height
+ */
+ static public void setLifelineHeaderFontHeight(int fontHeight) {
+ fLifelineHeaderFontHeight = fontHeight;
+ }
+
+ /**
+ * Returns the character height used to draw the lifeline name
+ *
+ * @return the character height
+ */
+ static public int getLifelineFontHeigth() {
+ return fLifelineFontHeight;
+ }
+
+ /**
+ * Returns the character height used to draw the message name
+ *
+ * @return the character height
+ */
+ static public int getMessageFontHeigth() {
+ if (fForcedEventSpacing >= 0) {
+ return 0;
+ }
+ return fMessageFontHeight;
+ }
+
+ /**
+ * This is the vertical space used by a Lifeline (mostly the rectangle which contain its name)
+ *
+ * @return the vertical space used by a Lifeline
+ */
+ static public int getLifelineWidth() {
+ return fLifeLineWidth;
+ }
+
+ /**
+ * Set the vertical space used by a Lifeline (mostly the rectangle which contain its name)
+ *
+ * @param value the vertical space
+ */
+ static public void setLifelineWidth(int value) {
+ fLifeLineWidth = value;
+ }
+
+ /**
+ * Returns the swimming lane width
+ *
+ * @return the swimming lane width
+ */
+ static public int swimmingLaneWidth() {
+ return getLifelineWidth() + LIFELINE_SPACING;
+ }
+
+ /**
+ * Returns the character width used to draw the Lifelines name
+ *
+ * @return the average character width
+ */
+ static public int getAverageCharWidth() {
+ return fLifelineFontWidth;
+ }
+
+ /**
+ * Returns the message spacing.
+ *
+ * @return the message spacing
+ */
+ static public int getMessagesSpacing() {
+ if (fForcedEventSpacing >= 0) {
+ return fForcedEventSpacing;
+ }
+ return MESSAGES_SPACING;
+ }
+
+ /**
+ * Sets the forced event spacing value .
+ *
+ * @param eventSpacing
+ * The spacing value
+ */
+ static public void setForcedEventSpacing(int eventSpacing) {
+ fForcedEventSpacing = eventSpacing;
+ }
+
+ /**
+ * Gets the forced event spacing value.
+ *
+ * @return forcedEventSpacing
+ */
+ static public int getForcedEventSpacing() {
+ return fForcedEventSpacing;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SDTimeEvent.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SDTimeEvent.java
new file mode 100755
index 0000000000..3b7dbd807f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SDTimeEvent.java
@@ -0,0 +1,91 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+
+/**
+ * Class implementation of a sequence diagram time event.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SDTimeEvent {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The time stamp of the event
+ */
+ private final ITmfTimestamp fTimestamp;
+ /**
+ * The event index.
+ */
+ private final int fEvent;
+ /**
+ * The time range implementing node.
+ */
+ private final ITimeRange fNode;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * The default constructor.
+ *
+ * @param time The time stamp of the event.
+ * @param event The event index.
+ * @param node The time range implementing node.
+ * @since 2.0
+ */
+ public SDTimeEvent(ITmfTimestamp time, int event, ITimeRange node) {
+ fTimestamp = time;
+ fEvent = event;
+ fNode = node;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+ /**
+ * Returns the timestamp of the event.
+ *
+ * @return the timestamp of the event.
+ * @since 2.0
+ */
+ public ITmfTimestamp getTime() {
+ return fTimestamp;
+ }
+
+ /**
+ * Returns the event index.
+ *
+ * @return the event index.
+ */
+ public int getEvent() {
+ return fEvent;
+ }
+
+ /**
+ * Returns the time range implementing node.
+ *
+ * @return the time range implementing node.
+ */
+ public ITimeRange getGraphNode() {
+ return fNode;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Stop.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Stop.java
new file mode 100755
index 0000000000..c795fb87c1
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/Stop.java
@@ -0,0 +1,167 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * <p>
+ * It is the UML2 stop graphical representation in the sequence diagram viewer.
+ * This draw a cross on the lifeline. The stop y coordinate depend on the event occurrence when it appears.
+ * A stop is never drawn it is assigned to a lifeline.
+ * </p>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class Stop extends GraphNode {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The graphNode ID
+ */
+ public static final String STOP = "STOP"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The owning lifeline on which the stop appears
+ */
+ private Lifeline fLifeline = null;
+ /**
+ * This basically represents the time when the stop occurs on the owning Lifeline
+ *
+ * @see Lifeline Lifeline for more event occurence details
+ */
+ private int fEventOccurrence = 0;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int getX() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return fLifeline.getX() + Metrics.getLifelineWidth() / 2 - Metrics.STOP_WIDTH / 2;
+ }
+
+ @Override
+ public int getY() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return fLifeline.getY() + fLifeline.getHeight() + (Metrics.getMessageFontHeigth() + Metrics.getMessagesSpacing()) * fEventOccurrence - Metrics.STOP_WIDTH / 2;
+ }
+
+ @Override
+ public int getWidth() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return Metrics.STOP_WIDTH;
+ }
+
+ @Override
+ public int getHeight() {
+ if (fLifeline == null) {
+ return 0;
+ }
+ return Metrics.STOP_WIDTH;
+ }
+
+ /**
+ * Set the lifeline on which the stop must be draw
+ *
+ * @param theLifeline The the stop owing lifeline
+ */
+ public void setLifeline(Lifeline theLifeline) {
+ fLifeline = theLifeline;
+ }
+
+ /**
+ * Get the lifeline on which the stop must be draw
+ *
+ * @return the the stop owing lifeline
+ * @since 2.0
+ */
+ public Lifeline getLifeline() {
+ return fLifeline;
+ }
+
+ /**
+ * Get the event occurrence when this stop appears
+ *
+ * @return the eventOccurence to assign to the stop
+ * @since 2.0
+ */
+ public int getEventOccurrence() {
+ return fEventOccurrence;
+ }
+
+ /**
+ * Set the event occurrence when this stop appears
+ *
+ * @param occurrence the eventOccurence to assign to the stop
+ */
+ public void setEventOccurrence(int occurrence) {
+ fEventOccurrence = occurrence;
+ }
+
+ @Override
+ public void draw(IGC context) {
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // Set the appropriate color depending if the graph node if selected or not
+ if (fLifeline.isSelected()) {
+ context.setForeground(pref.getBackGroundColorSelection());
+ context.setLineWidth(Metrics.SELECTION_LINE_WIDTH);
+ int lastWidth = context.getLineWidth();
+ context.setLineWidth(9);
+ // Draw a cross on the lifeline
+ context.drawLine(getX(), getY(), getX() + getWidth(), getY() + getHeight());
+ context.drawLine(getX() + getWidth(), getY(), getX(), getY() + getHeight());
+ // restore the context
+ context.setLineWidth(lastWidth);
+ context.setBackground(pref.getBackGroundColorSelection());
+ context.setForeground(pref.getForeGroundColorSelection());
+ } else {
+ context.setBackground(pref.getBackGroundColor(ISDPreferences.PREF_LIFELINE));
+ context.setForeground(pref.getForeGroundColor(ISDPreferences.PREF_LIFELINE));
+ }
+ int lastWidth = context.getLineWidth();
+ context.setLineWidth(3);
+ // Draw a cross on the lifeline
+ context.drawLine(getX(), getY(), getX() + getWidth(), getY() + getHeight());
+ context.drawLine(getX() + getWidth(), getY(), getX(), getY() + getHeight());
+ // restore the context
+ context.setLineWidth(lastWidth);
+ }
+
+ @Override
+ public String getArrayId() {
+ return STOP;
+ }
+
+ @Override
+ public boolean contains(int x, int y) {
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessage.java
new file mode 100755
index 0000000000..04b8394030
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessage.java
@@ -0,0 +1,296 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.SortSyncMessageComparator;
+
+/**
+ * A SyncMessage is a synchronous message which appear at the same event occurrence on both lifeline ends (sender and
+ * receiver).<br>
+ * A Sync message is usually drawn horizontally.<br>
+ * <br>
+ * <br>
+ * Usage example:
+ *
+ * <pre>
+ * Frame frame;
+ * Lifeline lifeLine1;
+ * Lifeline lifeLine2;
+ *
+ * SyncMessage message = new SyncMessage();
+ * // Create a new event occurrence on each lifeline
+ * lifeline1.getNewOccurrenceIndex();
+ * lifeline2.getNewOccurrenceIndex();
+ * // Set the message sender and receiver
+ * message.setStartLifeline(lifeLine1);
+ * message.setEndLifline(lifeline2);
+ * message.setName(&quot;Message label&quot;);
+ * // add the message to the frame
+ * frame.addMessage(message);
+ * </pre>
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline Lifeline for more event occurence details
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SyncMessage extends BaseMessage implements ITimeRange {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The graphNode ID
+ */
+ public static final String SYNC_MESS_TAG = "SyncMessage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The associated message return
+ */
+ private SyncMessageReturn fMessageReturn;
+ /**
+ * The time when the message occurs
+ */
+ private ITmfTimestamp fEventTime = new TmfTimestamp();
+ /**
+ * Flag whether the message has time information available or not
+ */
+ private boolean fHasTimeInfo = false;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public SyncMessage() {
+ setColorPrefId(ISDPreferences.PREF_SYNC_MESS);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Ensure both lifelines have the same event occurrence (the greater found on each lifeline)
+ */
+ protected void syncLifelinesEventOccurrence() {
+ if ((getStartLifeline() != null) && (getEndLifeline() != null)) {
+ int newIndex = 0;
+ if (getStartLifeline().getEventOccurrence() > getEndLifeline().getEventOccurrence()) {
+ newIndex = getStartLifeline().getEventOccurrence();
+ } else {
+ newIndex = getEndLifeline().getEventOccurrence();
+ }
+ getStartLifeline().setCurrentEventOccurrence(newIndex);
+ getEndLifeline().setCurrentEventOccurrence(newIndex);
+ setEventOccurrence(getStartLifeline().getEventOccurrence());
+ }
+ }
+
+ /**
+ * Set the lifeLine from which the message has been sent.<br>
+ * A new event occurrence will be created on this lifeLine.<br>
+ * SyncMessage must occur at the same event occurrence on both lifeline, this method is responsible to synchronize the
+ * event occurrence on each lifeline (the greater value will be used).<br>
+ * This synchronization is only done if the end lifeline has already been set.
+ *
+ * @param lifeline the message sender
+ */
+ public void autoSetStartLifeline(Lifeline lifeline) {
+ lifeline.getNewEventOccurrence();
+ setStartLifeline(lifeline);
+ }
+
+ /**
+ * Set the lifeLine which has receiver the message.<br>
+ * A new EventOccurence will be create on this lifeLine.<br>
+ * SyncMessage must occur at the same event occurrence on both lifeline, this method is responsible to synchronize the
+ * event occurrence on each lifeline (the greater value will be used).<br>
+ * This synchronization is only done if the start lifeline has already been set.
+ *
+ * @param lifeline the message receiver
+ */
+ public void autoSetEndLifeline(Lifeline lifeline) {
+ lifeline.getNewEventOccurrence();
+ setEndLifeline(lifeline);
+ }
+
+ /**
+ * Set the lifeLine which has receiver the message.<br>
+ * SyncMessage must occur at the same event occurrence on both lifeline, this method is responsible to synchronize the
+ * event occurrence on each lifeline (the greater value will be used).<br>
+ * This synchronization is only done if the start lifeline has already been set.
+ *
+ * @param lifeline the message receiver
+ */
+ @Override
+ public void setStartLifeline(Lifeline lifeline) {
+ super.setStartLifeline(lifeline);
+ if ((getEndLifeline() == null)) {
+ setEventOccurrence(getStartLifeline().getEventOccurrence());
+ } else {
+ syncLifelinesEventOccurrence();
+ }
+ }
+
+ /**
+ * Set the lifeLine which has receiver the message.<br>
+ * SyncMessage must occur at the same event occurrence on both lifelines, this method is responsible to synchronize the
+ * event occurrence on each lifeline (the greater value will be used).<br>
+ * This synchronization is only done if the start lifeline has already been set.
+ *
+ * @param lifeline the message receiver
+ */
+ @Override
+ public void setEndLifeline(Lifeline lifeline) {
+ super.setEndLifeline(lifeline);
+ if ((getStartLifeline() == null)) {
+ setEventOccurrence(getEndLifeline().getEventOccurrence());
+ } else {
+ syncLifelinesEventOccurrence();
+ }
+ }
+
+ /**
+ * Set the event occurrence when this message occurs.<br>
+ *
+ * @param occurrence the event occurrence to assign to this message.<br>
+ * @see Lifeline Lifeline for more event occurence details
+ */
+ @Override
+ protected void setEventOccurrence(int occurrence) {
+ setStartOccurrence(occurrence);
+ setEndOccurrence(occurrence);
+ }
+
+ /**
+ * Set the message return associated with this message.
+ *
+ * @param message the message return to associate
+ */
+ protected void setMessageReturn(SyncMessageReturn message) {
+ fMessageReturn = message;
+ }
+
+ /**
+ * Returns the syncMessageReturn associated to this syncMessage
+ *
+ * @return the message return
+ */
+ public SyncMessageReturn getMessageReturn() {
+ return fMessageReturn;
+ }
+
+ /**
+ * Set the time when the message occurs
+ *
+ * @param time the time when the message occurs
+ * @since 2.0
+ */
+ public void setTime(ITmfTimestamp time) {
+ fEventTime = time;
+ fHasTimeInfo = true;
+ if (getStartLifeline() != null && getStartLifeline().getFrame() != null) {
+ getStartLifeline().getFrame().setHasTimeInfo(true);
+ } else if (getEndLifeline() != null && getEndLifeline().getFrame() != null) {
+ getEndLifeline().getFrame().setHasTimeInfo(true);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getEndTime() {
+ return fEventTime;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public ITmfTimestamp getStartTime() {
+ return fEventTime;
+ }
+
+ @Override
+ public boolean hasTimeInfo() {
+ return fHasTimeInfo;
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ // Draw it selected?
+ if (!isSelected()) {
+ context.setBackground(pref.getBackGroundColor(getColorPrefId()));
+ context.setForeground(pref.getForeGroundColor(getColorPrefId()));
+ }
+ super.draw(context);
+ }
+
+ @Override
+ public boolean isVisible(int x, int y, int width, int height) {
+ if (getY() > y + height +
+ // take into account the message name drawn above the arrow
+ Metrics.MESSAGES_NAME_SPACING + Metrics.getMessageFontHeigth()) {
+ return false;
+ }
+
+ // UML2 lost/found message visibility special case
+ // Others visibility cases are perform in the ***common*** case
+ if ((getEndLifeline() == null && getStartLifeline() != null) || (getEndLifeline() != null && getStartLifeline() == null)) {
+ if (x + width > getX() + getWidth() && x < getX() + getWidth()) {
+ return true;
+ }
+ }
+ // ***Common*** syncMessages visibility
+ return super.isVisible(x, y, width, height);
+ }
+
+ @Override
+ public Comparator<GraphNode> getComparator() {
+ return new SortSyncMessageComparator();
+ }
+
+ @Override
+ public String getArrayId() {
+ return SYNC_MESS_TAG;
+ }
+
+ @Override
+ public boolean positiveDistanceToPoint(int x, int y) {
+ if (getY() > y) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessageReturn.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessageReturn.java
new file mode 100755
index 0000000000..c3b0f0804c
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/core/SyncMessageReturn.java
@@ -0,0 +1,112 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.core;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.ISDPreferences;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences.SDViewPref;
+
+/**
+ * The message return graph node implementation.<br>
+ * This class differs on the SynMessage class only on the drawing line style (dashed instead of plain line).<br>
+ * Message return are generally associated to a message. This means, they are connected to the same lifelines than the
+ * associated message but in the opposite direction and for a different event occurrence.<br>
+ * <br>
+ * WARNING: The association validity is not checked, it is not necessary to provide a valid association, not even needed
+ * to set an association to drawn a message with a message return style.<br>
+ *
+ *
+ * @see org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage SyncMessage for usage example
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SyncMessageReturn extends SyncMessage {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The graphNode ID
+ */
+ public static final String SYNC_MESS_RET_TAG = "SyncMessageRet"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The associated message(the message it is the return).
+ */
+ private SyncMessage fMessage = null;
+
+ // ------------------------------------------------------------------------
+ // Constractors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public SyncMessageReturn() {
+ setColorPrefId(ISDPreferences.PREF_SYNC_MESS_RET);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Set the associated message (the message it is the return).<br>
+ * Setting the association will activate the navigation in the default sequence diagram implementation to the
+ * message when the user right click on this message return.<br>
+ *
+ * @param parentMessage the message to associate
+ */
+ public void setMessage(SyncMessage parentMessage) {
+ fMessage = parentMessage;
+ fMessage.setMessageReturn(this);
+ }
+
+ /**
+ * Returns the syncMessage associated to this SyncMessageReturn
+ *
+ * @return the associated message
+ */
+ public SyncMessage getMessage() {
+ return fMessage;
+ }
+
+ @Override
+ public void draw(IGC context) {
+ if (!isVisible()) {
+ return;
+ }
+
+ ISDPreferences pref = SDViewPref.getInstance();
+
+ int oldStyle = context.getLineStyle();
+ // Message return are dashed
+ context.setLineStyle(context.getLineDotStyle());
+ // Draw it selected?
+ if (!isSelected()) {
+ context.setBackground(pref.getBackGroundColor(getColorPrefId()));
+ context.setForeground(pref.getForeGroundColor(getColorPrefId()));
+ }
+ super.draw(context);
+ // restore the context
+ context.setLineStyle(oldStyle);
+ }
+
+ @Override
+ public String getArrayId() {
+ return SYNC_MESS_RET_TAG;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/Criteria.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/Criteria.java
new file mode 100755
index 0000000000..7c2a304f3b
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/Criteria.java
@@ -0,0 +1,415 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDGraphNodeSupporter;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * This class describes the find or filter criteria selected by the user in the find or filter dialog box
+ *
+ * @version 1.0
+ * @author sveyrier
+ * @author Bernd Hufmann
+ */
+public class Criteria {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Flag whether lifeline is selected or not.
+ */
+ private boolean fLifeLineSelected = false;
+ /**
+ * Flag whether synchronous message is selected or not.
+ */
+ private boolean fSyncMessageSelected = false;
+ /**
+ * Flag whether synchronous message return is selected or not.
+ */
+ private boolean fSyncMessageReturnSelected = false;
+ /**
+ * Flag whether asynchronous message is selected or not.
+ */
+ private boolean fAsyncMessageSelected = false;
+ /**
+ * Flag whether asynchronous message return is selected or not.
+ */
+ private boolean fAsyncMessageReturnSelected = false;
+ /**
+ * Flag whether case sensitive find is required or not.
+ */
+ private boolean fCaseSenstiveSelected = false;
+ /**
+ * Flag whether stop graph node is selected or not.
+ */
+ private boolean fStopSelected = false;
+ /**
+ * The find expression.
+ */
+ private String fExpression = null;
+ /**
+ * The find pattern as regular expression.
+ */
+ private Pattern pattern = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public Criteria () {
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param other Criteria to create new criteria
+ */
+ public Criteria (Criteria other) {
+ this.fLifeLineSelected = other.fLifeLineSelected;
+ this.fSyncMessageSelected = other.fSyncMessageSelected;
+ this.fSyncMessageReturnSelected = other.fSyncMessageReturnSelected;
+ this.fAsyncMessageSelected = other.fAsyncMessageSelected;
+ this.fAsyncMessageReturnSelected = other.fAsyncMessageReturnSelected;
+ this.fCaseSenstiveSelected = other.fCaseSenstiveSelected;
+ this.fStopSelected = other.fStopSelected;
+ fExpression = other.fExpression;
+ updatePattern();
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns true if the AsyncMessageReturn is selected, false otherwise.
+ *
+ * @return true if the AsyncMessageReturn is selected, false otherwise
+ */
+ public boolean isAsyncMessageReturnSelected() {
+ return fAsyncMessageReturnSelected;
+ }
+
+ /**
+ * Returns true if the AsyncMessage is selected, false otherwise.
+ *
+ * @return true if the AsyncMessage is selected, false otherwise
+ */
+ public boolean isAsyncMessageSelected() {
+ return fAsyncMessageSelected;
+ }
+
+ /**
+ * Returns the text enter by the user.
+ *
+ * @return the expression text
+ */
+ public String getExpression() {
+ return fExpression;
+ }
+
+ /**
+ * Returns the regular expression pattern.
+ *
+ * @return the regular expression pattern
+ */
+ public Pattern getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Sets the regular expression pattern.
+ *
+ * @param pattern
+ * The pattern to set
+ */
+ public void setPattern(Pattern pattern) {
+ this.pattern = pattern;
+ }
+
+ /**
+ * Returns true if the LifeLine is selected, false otherwise.
+ *
+ * @return true if the LifeLine is selected, false otherwise
+ */
+ public boolean isLifeLineSelected() {
+ return fLifeLineSelected;
+ }
+
+ /**
+ * Returns true if the Stop is selected, false otherwise.
+ *
+ * @return true if the Stop is selected, false otherwise
+ */
+ public boolean isStopSelected() {
+ return fStopSelected;
+ }
+
+ /**
+ * Returns true if the SyncMessageReturn is selected, false otherwise.
+ *
+ * @return true if the SyncMessageReturn is selected, false otherwise
+ */
+ public boolean isSyncMessageReturnSelected() {
+ return fSyncMessageReturnSelected;
+ }
+
+ /**
+ * Returns true if the SyncMessage is selected, false otherwise.
+ *
+ * @return true if the SyncMessage is selected, false otherwise
+ */
+ public boolean isSyncMessageSelected() {
+ return fSyncMessageSelected;
+ }
+
+ /**
+ * Sets the AsyncMessageReturn selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setAsyncMessageReturnSelected(boolean b) {
+ fAsyncMessageReturnSelected = b;
+ }
+
+ /**
+ * Sets the AsyncMessage selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setAsyncMessageSelected(boolean b) {
+ fAsyncMessageSelected = b;
+ }
+
+ /**
+ * Sets the text entered by the user and compiles the regular expression.
+ *
+ * @param string the text
+ */
+ public void setExpression(String string) {
+ fExpression = string;
+ updatePattern();
+ }
+
+ /**
+ * Sets the Stop selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setLifeLineSelected(boolean b) {
+ fLifeLineSelected = b;
+ }
+
+ /**
+ * Set Stop selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setStopSelected(boolean b) {
+ fStopSelected = b;
+ }
+
+ /**
+ * Sets the SyncMessageReturn selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setSyncMessageReturnSelected(boolean b) {
+ fSyncMessageReturnSelected = b;
+ }
+
+ /**
+ * Sets the SyncMessage selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setSyncMessageSelected(boolean b) {
+ fSyncMessageSelected = b;
+ }
+
+ /**
+ * Returns true if the case sensitive is selected, false otherwise.
+ *
+ * @return true if the case sensitive is selected, false otherwise
+ */
+ public boolean isCaseSenstiveSelected() {
+ return fCaseSenstiveSelected;
+ }
+
+ /**
+ * Set case sensitive selection state.
+ *
+ * @param b true if selected, false otherwise
+ */
+ public void setCaseSenstiveSelected(boolean b) {
+ fCaseSenstiveSelected = b;
+ // Make sure that pattern is set
+ setExpression(fExpression);
+ }
+
+ /**
+ * Compares this criteria with a given criteria.
+ *
+ * @param to The criteria to compare
+ * @return usual comparison result (< 0, 0, > 0)
+ */
+ public boolean compareTo(Criteria to) {
+ boolean retVal = true;
+ if (getExpression() != null) {
+ retVal = getExpression().equals(to.getExpression());
+ } else if (to.getExpression() != null) {
+ retVal = to.getExpression().equals(getExpression());
+ }
+ return retVal && isCaseSenstiveSelected() == to.isCaseSenstiveSelected() && isAsyncMessageReturnSelected() == to.isAsyncMessageReturnSelected() && isAsyncMessageSelected() == to.isAsyncMessageSelected()
+ && isLifeLineSelected() == to.isLifeLineSelected() && isStopSelected() == to.isStopSelected() && isSyncMessageReturnSelected() == to.isSyncMessageReturnSelected() && isSyncMessageSelected() == to.isSyncMessageSelected();
+ }
+
+ /**
+ * Saves current criteria attributes in the dialog settings.
+ *
+ * @param settings The dialog settings
+ */
+ public void save(DialogSettings settings) {
+ settings.put("expression", getExpression()); //$NON-NLS-1$
+ settings.put("isCaseSenstiveSelected", isCaseSenstiveSelected()); //$NON-NLS-1$
+ settings.put("isAsyncMessageReturnSelected", isAsyncMessageReturnSelected()); //$NON-NLS-1$
+ settings.put("isAsyncMessageSelected", isAsyncMessageSelected()); //$NON-NLS-1$
+ settings.put("isLifeLineSelected", isLifeLineSelected()); //$NON-NLS-1$
+ settings.put("isStopSelected", isStopSelected()); //$NON-NLS-1$
+ settings.put("isSyncMessageReturnSelected", isSyncMessageReturnSelected()); //$NON-NLS-1$
+ settings.put("isSyncMessageSelected", isSyncMessageSelected()); //$NON-NLS-1$
+ }
+
+ /**
+ * Loads the criteria with values of the dialog settings.
+ *
+ * @param settings The dialog settings
+ */
+ public void load(DialogSettings settings) {
+ setExpression(settings.get("expression")); //$NON-NLS-1$
+ setCaseSenstiveSelected(settings.getBoolean("isCaseSenstiveSelected")); //$NON-NLS-1$
+ setAsyncMessageReturnSelected(settings.getBoolean("isAsyncMessageReturnSelected")); //$NON-NLS-1$
+ setAsyncMessageSelected(settings.getBoolean("isAsyncMessageSelected")); //$NON-NLS-1$
+ setLifeLineSelected(settings.getBoolean("isLifeLineSelected")); //$NON-NLS-1$
+ setStopSelected(settings.getBoolean("isStopSelected")); //$NON-NLS-1$
+ setSyncMessageReturnSelected(settings.getBoolean("isSyncMessageReturnSelected")); //$NON-NLS-1$
+ setSyncMessageSelected(settings.getBoolean("isSyncMessageSelected")); //$NON-NLS-1$
+ }
+
+ /**
+ * Gets the summary of supported graph nodes.
+ *
+ * @param provider A filter provider
+ * @param loaderClassName A class loader
+ * @return graph node summary
+ */
+ public String getGraphNodeSummary(ISDFilterProvider provider, String loaderClassName) {
+ ArrayList<String> list = new ArrayList<>();
+
+ if (provider != null) {
+ if (isLifeLineSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.LIFELINE, loaderClassName));
+ }
+ if (isSyncMessageSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.SYNCMESSAGE, loaderClassName));
+ }
+ if (isSyncMessageReturnSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.SYNCMESSAGERETURN, loaderClassName));
+ }
+ if (isAsyncMessageSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.ASYNCMESSAGE, loaderClassName));
+ }
+ if (isAsyncMessageReturnSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.ASYNCMESSAGERETURN, loaderClassName));
+ }
+ if (isStopSelected()) {
+ list.add(provider.getNodeName(ISDGraphNodeSupporter.STOP, loaderClassName));
+ }
+ } else {
+ if (isLifeLineSelected()) {
+ list.add(Messages.SequenceDiagram_Lifeline);
+ }
+ if (isSyncMessageSelected()) {
+ list.add(Messages.SequenceDiagram_SynchronousMessage);
+ }
+ if (isSyncMessageReturnSelected()) {
+ list.add(Messages.SequenceDiagram_SynchronousMessageReturn);
+ }
+ if (isAsyncMessageSelected()) {
+ list.add(Messages.SequenceDiagram_AsynchronousMessage);
+ }
+ if (isAsyncMessageReturnSelected()) {
+ list.add(Messages.SequenceDiagram_AsynchronousMessageReturn);
+ }
+ if (isStopSelected()) {
+ list.add(Messages.SequenceDiagram_Stop);
+ }
+ }
+ StringBuffer ret = new StringBuffer();
+ String prefix = "["; //$NON-NLS-1$
+ for (Iterator<String> i = list.iterator(); i.hasNext();) {
+ String s = i.next();
+ ret.append(prefix);
+ ret.append(s);
+ prefix = " " + Messages.SequenceDiagram_or + " "; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ ret.append("]"); //$NON-NLS-1$
+ return ret.toString();
+ }
+
+ /**
+ * Matches given string using compiled pattern based on user expression.
+ *
+ * @param stringToMatch A string to match
+ * @return true if string matches expression
+ */
+ public boolean matches(String stringToMatch) {
+ if (pattern == null) {
+ return false;
+ }
+ return pattern.matcher(stringToMatch).matches();
+ }
+
+ /**
+ * Updates the regular expression pattern based on the expression.
+ */
+ private void updatePattern() {
+ if (fExpression != null) {
+ try {
+ if (fCaseSenstiveSelected) {
+ pattern = Pattern.compile(fExpression);
+ }
+ else {
+ pattern = Pattern.compile(fExpression, Pattern.CASE_INSENSITIVE);
+ }
+ } catch (PatternSyntaxException e) {
+ pattern = null;
+ }
+ }
+ else {
+ pattern = null;
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterCriteria.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterCriteria.java
new file mode 100755
index 0000000000..91ec6e876c
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterCriteria.java
@@ -0,0 +1,273 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.DialogSettings;
+
+/**
+ * A filter criteria is a criteria that can be activated or not, positive or not.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class FilterCriteria {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The filter state value for 'active'.
+ */
+ protected static final String ACTIVE = "active"; //$NON-NLS-1$
+ /**
+ * The property value for positive filter.
+ */
+ protected static final String POSITIVE = "positive"; //$NON-NLS-1$
+ /**
+ * The filter loader class name property.
+ */
+ protected static final String LOADERCLASSNAME = "loaderClassName"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The criteria reference.
+ */
+ private Criteria fCriteria;
+ /**
+ * Flag whether this criteria is active or not
+ */
+ private boolean fIsActive;
+ /**
+ * Flag whether this criteria is for positive filter or not
+ */
+ private boolean fIsPositive;
+ /**
+ * The loader class name.
+ */
+ private String fLoaderClassName;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * Standard constructor
+ *
+ * @param criteria A criteria reference
+ * @param isActive <code>true</code> if filter criteria is active else <code>false</code>
+ * @param isPositive <code>true</code> for positive filter else <code>false</code>
+ */
+ public FilterCriteria(Criteria criteria, boolean isActive, boolean isPositive) {
+ this(criteria, isActive, isPositive, null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param criteria A criteria reference
+ * @param isActive <code>true</code> if filter criteria is active else <code>false</code>
+ * @param isPositive <code>true</code> for positive filter else <code>false</code>
+ * @param loaderClassName A loader class name
+ */
+ public FilterCriteria(Criteria criteria, boolean isActive, boolean isPositive, String loaderClassName) {
+ fCriteria = criteria;
+ fIsActive = isActive;
+ fIsPositive = isPositive;
+ fLoaderClassName = loaderClassName;
+ }
+
+ /**
+ * Copy Constructor
+ * @param other FilterCriteria
+ */
+ public FilterCriteria (FilterCriteria other) {
+ fCriteria = new Criteria(other.fCriteria);
+ fIsActive = other.fIsActive;
+ fIsPositive = other.fIsPositive;
+ fLoaderClassName = other.fLoaderClassName;
+ }
+
+ /**
+ * Default constructor
+ */
+ protected FilterCriteria() {
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer(super.toString());
+ sb.append(':');
+ if (fCriteria != null) {
+ sb.append(" expression=");sb.append(fCriteria.getExpression()); //$NON-NLS-1$
+ sb.append(" active=");sb.append(fIsActive); //$NON-NLS-1$
+ sb.append(" positive=");sb.append(fIsPositive); //$NON-NLS-1$
+ } else {
+ sb.append("empty criteria"); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Sets a criteria reference.
+ * @param criteria A criteria reference
+ */
+ public void setCriteria(Criteria criteria) {
+ fCriteria = criteria;
+ }
+
+ /**
+ * Returns the criteria reference.
+ *
+ * @return the criteria reference
+ */
+ public Criteria getCriteria() {
+ return fCriteria;
+ }
+
+ /**
+ * Sets the active flag.
+ *
+ * @param isActive A active value.
+ */
+ public void setActive(boolean isActive) {
+ fIsActive = isActive;
+ }
+
+ /**
+ * Returns whether filter criteria is active or not.
+ *
+ * @return whether filter criteria is active or not.
+ */
+ public boolean isActive() {
+ return fIsActive;
+ }
+
+ /**
+ * Sets filter is for positive filtering or not.
+ *
+ * @param isPositive The value to set.
+ */
+ public void setPositive(boolean isPositive) {
+ fIsPositive = isPositive;
+ }
+
+ /**
+ * Returns whether the filter si for positive filtering or not.
+ *
+ * @return Returns the positive.
+ */
+ public boolean isPositive() {
+ return fIsPositive;
+ }
+
+ /**
+ * Sets the loader class name for this filter.
+ *
+ * @param loaderClassName The loader class name to set
+ */
+ public void setLoaderClassName(String loaderClassName) {
+ fLoaderClassName = loaderClassName;
+ }
+
+ /**
+ * Returns the class loader name.
+ *
+ * @return the class loader name.
+ */
+ public String getLoaderClassName() {
+ return fLoaderClassName;
+ }
+
+ /**
+ * Finds a filter criteria within a list of criteria.
+ *
+ * @param what The filter to find
+ * @param list A list of filter criteria
+ * @return The found filter criteria or null
+ */
+ public static FilterCriteria find(FilterCriteria what, List<FilterCriteria> list) {
+ if (what != null && list != null) {
+ try {
+ for (Iterator<FilterCriteria> i = list.iterator(); i.hasNext();) {
+ FilterCriteria fc = i.next();
+ if (what.compareTo(fc)) {
+ return fc;
+ }
+ }
+ } catch (Exception e) {
+ // Silence
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Compares this filter criteria with a given criteria.
+ *
+ * @param to The filter criteria to compare.
+ * @return usual comparison result (< 0, 0, > 0)
+ */
+ public boolean compareTo(FilterCriteria to) {
+ if (isPositive() == to.isPositive() && getCriteria().compareTo(to.getCriteria())) {
+ if (getLoaderClassName() == null && to.getLoaderClassName() == null) {
+ return true;
+ }
+ if ((getLoaderClassName() != null && to.getLoaderClassName() != null) && getLoaderClassName().equals(to.getLoaderClassName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Saves current criteria attributes in the dialog settings.
+ *
+ * @param settings The dialog settings
+ */
+ public void save(DialogSettings settings) {
+ settings.put(ACTIVE, isActive());
+ settings.put(POSITIVE, isPositive());
+ if (getLoaderClassName() != null) {
+ settings.put(LOADERCLASSNAME, getLoaderClassName());
+ } else {
+ settings.put(LOADERCLASSNAME, ""); //$NON-NLS-1$
+ }
+ if (fCriteria != null) {
+ fCriteria.save(settings);
+ }
+ }
+
+ /**
+ * Loads the criteria with values of the dialog settings.
+ *
+ * @param settings The dialog settings
+ */
+ public void load(DialogSettings settings) {
+ setActive(settings.getBoolean(ACTIVE));
+ setPositive(settings.getBoolean(POSITIVE));
+ String loaderClassName = settings.get(LOADERCLASSNAME);
+ setLoaderClassName(loaderClassName != null && loaderClassName.length() > 0 ? loaderClassName : null);
+ if (fCriteria != null) {
+ fCriteria.load(settings);
+ }
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterListDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterListDialog.java
new file mode 100755
index 0000000000..a905c391b6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/FilterListDialog.java
@@ -0,0 +1,518 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * This is the filters list dialog.<br>
+ * It is associated to an SDView and to a ISDFilterProvider.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class FilterListDialog extends Dialog {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Filter list criteria property name
+ */
+ protected static final String FILTERS_LIST_CRITERIA = "filtersListsCriteria"; //$NON-NLS-1$
+ /**
+ * Filter list size property name
+ */
+ protected static final String FILTERS_LIST_SIZE = "filtersListSize"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The viewer and provided are kept here as attributes
+ */
+ private final IViewPart fViewer;
+ /**
+ * The filter provider implementation
+ */
+ private final ISDFilterProvider fProvider;
+ /**
+ * The filters are the result of editing this list
+ */
+ private List<FilterCriteria> fFilters;
+ /**
+ * The add button.
+ */
+ private Button fAdd;
+ /**
+ * The remove button.
+ */
+ private Button fRemove;
+ /**
+ * The edit button.
+ */
+ private Button fEdit;
+ /**
+ * The table with list of filters.
+ */
+ private Table fTable;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param view The view reference
+ * @param loader The filter provider implementation
+ */
+ public FilterListDialog(IViewPart view, ISDFilterProvider loader) {
+ super(view.getSite().getShell());
+ fViewer = view;
+ fProvider = loader;
+ fFilters = null;
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Adds a criteria to the table
+ *
+ * @param criteria A criteria to add
+ * @param checked A flag whether criteria is checked (selected) or not
+ * @param positive A flag whether criteria is for positive filter or not
+ * @param loaderClassName A loader class name for the filters
+ */
+ protected void addCriteria(Criteria criteria, boolean checked, boolean positive, String loaderClassName) {
+ CriteriaTableItem cti = new CriteriaTableItem(fTable, checked, positive, loaderClassName);
+ cti.setCriteria(criteria);
+ }
+
+ /**
+ * Replaces a selected criteria with a new criteria.
+ *
+ * @param newCriteria A new criteria.
+ */
+ protected void replaceSelectedCriteria(Criteria newCriteria) {
+ CriteriaTableItem cti = (CriteriaTableItem) fTable.getSelection()[0].getData();
+ cti.setCriteria(newCriteria);
+ }
+
+ /**
+ * Handles table selection count.
+ */
+ protected void handleTableSelectionCount() {
+ int count = fTable.getSelectionCount();
+ fEdit.setEnabled(count == 1);
+ fRemove.setEnabled(count > 0);
+ }
+
+ @Override
+ public Control createDialogArea(Composite parent) {
+
+ Group ret = new Group(parent, SWT.NONE);
+ ret.setText(Messages.SequenceDiagram_ListOfHideDisplayPatterns);
+ RowLayout rowLayout = new RowLayout();
+ rowLayout.wrap = false;
+ rowLayout.pack = true;
+ rowLayout.justify = false;
+ rowLayout.type = SWT.HORIZONTAL;
+ rowLayout.marginLeft = 4;
+ rowLayout.marginTop = 4;
+ rowLayout.marginRight = 4;
+ rowLayout.marginBottom = 4;
+ rowLayout.spacing = 8;
+ ret.setLayout(rowLayout);
+
+ fTable = new Table(ret, SWT.MULTI | SWT.CHECK);
+ fTable.setLayoutData(new RowData(220, 84));
+ fTable.setHeaderVisible(false);
+ fTable.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ int count = fTable.getSelectionCount();
+ if (count == 1) {
+ Criteria criteria = openFilterDialog(((CriteriaTableItem) fTable.getSelection()[0].getData()).getCriteria(), Messages.SequenceDiagram_Update);
+ if (criteria != null) {
+ replaceSelectedCriteria(criteria);
+ }
+ }
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleTableSelectionCount();
+ }
+ });
+ if (fFilters != null) {
+ for (Iterator<FilterCriteria> i = fFilters.iterator(); i.hasNext();) {
+ FilterCriteria filterCriteria = i.next();
+ addCriteria(filterCriteria.getCriteria(), filterCriteria.isActive(), filterCriteria.isPositive(), filterCriteria.getLoaderClassName());
+ }
+ }
+
+ Composite commands = new Composite(ret, SWT.NONE);
+ RowLayout rowLayoutCommands = new RowLayout();
+ rowLayoutCommands.wrap = false;
+ rowLayoutCommands.pack = false;
+ rowLayoutCommands.justify = true;
+ rowLayoutCommands.type = SWT.VERTICAL;
+ rowLayoutCommands.marginLeft = 0;
+ rowLayoutCommands.marginTop = 4;
+ rowLayoutCommands.marginRight = 0;
+ rowLayoutCommands.marginBottom = 4;
+ rowLayoutCommands.spacing = 8;
+ commands.setLayout(rowLayoutCommands);
+ fAdd = new Button(commands, SWT.NONE);
+ fAdd.setText(Messages.SequenceDiagram_Add);
+ fAdd.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ Criteria init = new Criteria();
+ Criteria c = openFilterDialog(init, Messages.SequenceDiagram_Create);
+ if (c != null) {
+ addCriteria(c, true, false, null);
+ }
+ }
+ });
+
+ fEdit = new Button(commands, SWT.NONE);
+ fEdit.setText(Messages.SequenceDiagram_EditIt);
+ fEdit.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ Criteria c = openFilterDialog(((CriteriaTableItem) fTable.getSelection()[0].getData()).getCriteria(), Messages.SequenceDiagram_Update);
+ if (c != null) {
+ replaceSelectedCriteria(c);
+ }
+ }
+ });
+ fEdit.setEnabled(false);
+
+ fRemove = new Button(commands, SWT.NONE);
+ fRemove.setText(Messages.SequenceDiagram_Remove);
+ fRemove.addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fTable.remove(fTable.getSelectionIndices());
+ handleTableSelectionCount();
+ }
+ });
+ fRemove.setEnabled(false);
+
+ getShell().setText(Messages.SequenceDiagram_SequenceDiagramHidePatterns);
+ /*
+ * for (int i=0;i<filters.size();i++) { if (filters.get(i) instanceof FilterCriteria)
+ * addCriteria(((FilterCriteria)filters.get(i)).getCriteria(),true); }
+ */
+ return ret;
+ }
+
+ /**
+ * Opens the filter dialog box with given parameter.
+ *
+ * @param criteria The criteria reference to pass
+ * @param action to distinguish between "Update" and "Create"
+ * @return the criteria that has been updated or created
+ */
+ protected Criteria openFilterDialog(Criteria criteria, String action) {
+ SearchFilterDialog filter = new SearchFilterDialog((SDView) fViewer, fProvider, true, SWT.APPLICATION_MODAL);
+ filter.setCriteria(criteria);
+ filter.setOkText(action);
+ filter.setTitle(Messages.SequenceDiagram_DefinitionOfHidePattern);
+ filter.open();
+ return filter.getCriteria();
+ }
+
+ @Override
+ public int open() {
+ create();
+ getShell().pack();
+ getShell().setLocation(getShell().getDisplay().getCursorLocation());
+ loadFiltersCriteria();
+ return super.open();
+ }
+
+ @Override
+ public void okPressed() {
+ if (fTable.getItemCount() > 0) {
+ fFilters = new ArrayList<>();
+ } else {
+ fFilters = null;
+ }
+ for (int i = 0; i < fTable.getItemCount(); i++) {
+ TableItem item = fTable.getItem(i);
+ CriteriaTableItem cti = (CriteriaTableItem) item.getData();
+ FilterCriteria fc = new FilterCriteria(cti.getCriteria(), item.getChecked(), cti.isPositive(), cti.getLoaderClassName());
+ FilterCriteria efc = FilterCriteria.find(fc, fFilters);
+ if (efc == null) {
+ fFilters.add(fc);
+ } else {
+ efc.setActive(efc.isActive() || fc.isActive());
+ }
+ }
+ super.close();
+ fProvider.filter(fFilters);
+ saveFiltersCriteria(fFilters);
+ }
+
+ /**
+ * Sets the list of filters.
+ *
+ * @param filters The list of filters to set.
+ */
+ public void setFilters(List<FilterCriteria> filters) {
+ fFilters = filters;
+ }
+
+ /**
+ * Returns the filters list after editing.
+ *
+ * @return the filters list after editing
+ */
+ public List<FilterCriteria> getFilters() {
+ return fFilters;
+ }
+
+ /**
+ * Loads the filter criteria from global filters which are saved in the dialog settings.
+ */
+ protected void loadFiltersCriteria() {
+ List<FilterCriteria> globalFilters = getGlobalFilters();
+ for (Iterator<FilterCriteria> i = globalFilters.iterator(); i.hasNext();) {
+ FilterCriteria filterCriteria = i.next();
+ addCriteria(filterCriteria.getCriteria(), filterCriteria.isActive(), filterCriteria.isPositive(), filterCriteria.getLoaderClassName());
+ }
+ }
+
+ /**
+ * Returns the global filters which are saved in the dialog settings..
+ *
+ * @return the saved global filters
+ */
+
+ public static List<FilterCriteria> getGlobalFilters() {
+ DialogSettings settings = (DialogSettings) Activator.getDefault().getDialogSettings().getSection(FILTERS_LIST_CRITERIA);
+ int i = 0;
+ DialogSettings section = null;
+ int size = 0;
+ List<FilterCriteria> globalFilters = new ArrayList<>();
+ if (settings != null) {
+ try {
+ size = settings.getInt(FILTERS_LIST_SIZE);
+ } catch (NumberFormatException e) {
+ // This is not a problem
+ size = 0;
+ }
+ section = (DialogSettings) settings.getSection(FILTERS_LIST_CRITERIA + i);
+
+ while ((section != null) && (i < size)) {
+ FilterCriteria criteria = new FilterCriteria();
+ criteria.setCriteria(new Criteria());
+ criteria.load(section);
+ globalFilters.add(criteria);
+ section = (DialogSettings) settings.getSection(FILTERS_LIST_CRITERIA + (++i));
+ }
+ }
+
+ return globalFilters;
+ }
+
+ /**
+ * Saves the filter criteria in the dialog settings.
+ *
+ * @param globalFilters A list of filters to save.
+ */
+ public static void saveFiltersCriteria(List<FilterCriteria> globalFilters) {
+ DialogSettings settings = (DialogSettings) Activator.getDefault().getDialogSettings();
+ DialogSettings section = (DialogSettings) settings.getSection(FILTERS_LIST_CRITERIA);
+ if (section == null) {
+ section = (DialogSettings) settings.addNewSection(FILTERS_LIST_CRITERIA);
+ }
+
+ if (globalFilters == null) {
+ section.put(FILTERS_LIST_SIZE, 0);
+ return;
+ }
+
+ section.put(FILTERS_LIST_SIZE, globalFilters.size());
+
+ FilterCriteria criteria;
+
+ for (int j = 0; j < globalFilters.size(); j++) {
+ if (globalFilters.get(j) == null) {
+ return;
+ }
+
+ criteria = globalFilters.get(j);
+ DialogSettings subSection = (DialogSettings) section.getSection(FILTERS_LIST_CRITERIA + j);
+
+ if (subSection == null) {
+ subSection = (DialogSettings) section.addNewSection(FILTERS_LIST_CRITERIA + j);
+ }
+ criteria.save(subSection);
+ }
+ }
+
+ /**
+ * Deactivates the saved global filters.
+ */
+ public static void deactivateSavedGlobalFilters() {
+ // Deactivate all filters
+ List<FilterCriteria> filters = getGlobalFilters();
+ for(FilterCriteria criteria : filters) {
+ criteria.setActive(false);
+ }
+ // Save settings
+ FilterListDialog.saveFiltersCriteria(filters);
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper classes
+ // ------------------------------------------------------------------------
+ /**
+ * A class to map TableItems that can be toggled active or inactive and Criteria
+ */
+ protected class CriteriaTableItem {
+
+ /**
+ * The criteria reference
+ */
+ protected Criteria fCriteria;
+ /**
+ * The "positive" value.
+ */
+ protected boolean fIsPositive;
+ /**
+ * The loader class name
+ */
+ protected String fLoaderClassName;
+ /**
+ * The actual table item.
+ */
+ protected TableItem fTableItem;
+
+ /**
+ * Constructor
+ *
+ * @param parent The parent table
+ * @param isActive <code>true</code> if filter criteria is active else <code>false</code>
+ * @param isPositive <code>true</code> for positive filter else <code>false</code>
+ * @param loaderClassName The loader class name
+ */
+ public CriteriaTableItem(Table parent, boolean isActive, boolean isPositive, String loaderClassName) {
+ fTableItem = new TableItem(parent, SWT.NONE);
+ fTableItem.setData(this);
+ fTableItem.setChecked(isActive);
+ fIsPositive = isPositive;
+ fLoaderClassName = loaderClassName;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param parent The parent table
+ * @param isActive <code>true</code> if filter criteria is active else <code>false</code>
+ * @param isPositive <code>true</code> for positive filter else <code>false</code>
+ * @param loaderClassName The loader class name
+ * @param index The table item index
+ */
+ public CriteriaTableItem(Table parent, boolean isActive, boolean isPositive, String loaderClassName, int index) {
+ fTableItem = new TableItem(parent, SWT.NONE, index);
+ fTableItem.setChecked(isActive);
+ fIsPositive = isPositive;
+ fLoaderClassName = loaderClassName;
+ }
+
+ /**
+ * Sets the criteria.
+ *
+ * @param criteria The criteria to set
+ */
+ public void setCriteria(Criteria criteria) {
+ fCriteria = criteria;
+ fTableItem.setText((fIsPositive ? Messages.SequenceDiagram_display : Messages.SequenceDiagram_hide) + " " + fCriteria.getExpression() + " " + fCriteria.getGraphNodeSummary(fProvider, fLoaderClassName)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns the criteria.
+ * @return the criteria
+ */
+ public Criteria getCriteria() {
+ return fCriteria;
+ }
+
+ /**
+ * Returns whether positive filtering is active or not.
+ *
+ * @return <code>true</code> for positive filter else <code>false</code>
+ */
+ public boolean isPositive() {
+ return fIsPositive;
+ }
+
+ /**
+ * Returns the loader class name.
+ *
+ * @return the loader class name
+ */
+ public String getLoaderClassName() {
+ return fLoaderClassName;
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/MinMaxDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/MinMaxDialog.java
new file mode 100755
index 0000000000..4847b1d41e
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/MinMaxDialog.java
@@ -0,0 +1,190 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Dialog box for entering minimum and maximum time range for time compression bar.
+ *
+ * @version 1.0
+ * @author sveyrier
+ * @author Bernd Hufmann
+ *
+ */
+public class MinMaxDialog extends Dialog {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Text field for minimum.
+ */
+ private Text fMinText;
+ /**
+ * Text field for maximum.
+ */
+ private Text fMaxText;
+ /**
+ * Text field for scale.
+ */
+ private Text fScaleText;
+ /**
+ * Text field for precision.
+ */
+ private Text fPrecisionText;
+ /**
+ * The sequence diagram widget reference.
+ */
+ private SDWidget fSdWidget;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * Standard constructor.
+ * @param shell The shell
+ * @param viewer The sequence diagram widget reference.
+ */
+ public MinMaxDialog(Shell shell, SDWidget viewer) {
+ super(shell);
+ fSdWidget = viewer;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Method to create a grid data base on horizontal span.
+ * @param span The horizontal span
+ * @return a grid data object
+ */
+ protected GridData newGridData(int span) {
+ GridData data = new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = span;
+ return data;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite p) {
+ p.getShell().setText(Messages.SequenceDiagram_TimeCompressionBarConfig);
+ Composite parent = (Composite) super.createDialogArea(p);
+
+ GridLayout parentLayout = new GridLayout();
+ parentLayout.numColumns = 6;
+ parent.setLayout(parentLayout);
+
+ Group g1 = new Group(parent, SWT.SHADOW_NONE);
+ g1.setLayoutData(newGridData(3));
+ GridLayout g1layout = new GridLayout();
+ g1layout.numColumns = 3;
+ g1.setLayout(g1layout);
+
+ Label minLabel = new Label(g1, SWT.RADIO);
+ minLabel.setText(Messages.SequenceDiagram_MinTime);
+ minLabel.setLayoutData(newGridData(1));
+
+ fMinText = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fMinText.setLayoutData(newGridData(2));
+ fMinText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getValue()));
+
+ Label maxLabel = new Label(g1, SWT.RADIO);
+ maxLabel.setText(Messages.SequenceDiagram_MaxTime);
+ maxLabel.setLayoutData(newGridData(1));
+
+ fMaxText = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fMaxText.setLayoutData(newGridData(2));
+ fMaxText.setText(String.valueOf(fSdWidget.getFrame().getMaxTime().getValue()));
+
+ Label scaleLabel = new Label(g1, SWT.RADIO);
+ scaleLabel.setText(Messages.SequenceDiagram_Scale);
+ scaleLabel.setLayoutData(newGridData(1));
+
+ fScaleText = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fScaleText.setLayoutData(newGridData(2));
+ fScaleText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getScale()));
+
+
+ Label precisionLabel = new Label(g1, SWT.RADIO);
+ precisionLabel.setText(Messages.SequenceDiagram_Precision);
+ precisionLabel.setLayoutData(newGridData(1));
+
+ fPrecisionText = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fPrecisionText.setLayoutData(newGridData(2));
+ fPrecisionText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getPrecision()));
+
+ return parent;
+ }
+
+ @Override
+ protected void okPressed() {
+ long min = 0;
+ long max = 0;
+ int scale = 0;
+ int precision = 0;
+ try {
+ min = Long.parseLong(fMinText.getText());
+ max = Long.parseLong(fMaxText.getText());
+ scale = Integer.parseInt(fScaleText.getText());
+ precision = Integer.parseInt(fPrecisionText.getText());
+
+ fSdWidget.getFrame().setMax(new TmfTimestamp(max, scale, precision));
+ fSdWidget.getFrame().setMin(new TmfTimestamp(min, scale, precision));
+
+ fSdWidget.redraw();
+
+ super.okPressed();
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_InvalidRange);
+ }
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+ super.createButtonsForButtonBar(parent);
+ createButton(parent, IDialogConstants.CLIENT_ID, Messages.SequenceDiagram_Default, false);
+ getButton(IDialogConstants.CLIENT_ID).addSelectionListener(new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fSdWidget.getFrame().resetCustomMinMax();
+ fMinText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getValue()));
+ fMaxText.setText(String.valueOf(fSdWidget.getFrame().getMaxTime().getValue()));
+ fScaleText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getScale()));
+ fPrecisionText.setText(String.valueOf(fSdWidget.getFrame().getMinTime().getPrecision()));
+ fMaxText.getParent().layout(true);
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // nothing to do
+ }
+ });
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/PagesDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/PagesDialog.java
new file mode 100755
index 0000000000..29c8b737db
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/PagesDialog.java
@@ -0,0 +1,204 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.text.MessageFormat;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDAdvancedPagingProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * Class implementation of the pages dialog.<br>
+ *
+ * It is associated to an SDView and to a ISDAdvancedPagingProvider.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class PagesDialog extends Dialog {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * viewer and provided are kept here as attributes
+ */
+ private ISDAdvancedPagingProvider fProvider = null;
+
+ /** Current page */
+ private TextArea fCurrentPage;
+
+ /** Comment label */
+ private Label fTotalPageComment;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param view The sequence diagram view reference
+ * @param provider The paging provider reference
+ */
+ public PagesDialog(IViewPart view, ISDAdvancedPagingProvider provider) {
+ super(view.getSite().getShell());
+ fProvider = provider;
+ setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public Control createDialogArea(Composite parent) {
+
+ Group ret = new Group(parent, SWT.NONE);
+ GridData data = new GridData();
+ data.grabExcessHorizontalSpace = true;
+ data.horizontalAlignment = GridData.FILL;
+ ret.setLayoutData(data);
+ ret.setText(Messages.SequenceDiagram_PageNavigation);
+
+ FillLayout fillLayout = new FillLayout(SWT.VERTICAL);
+ ret.setLayout(fillLayout);
+
+ Label label = new Label(ret, SWT.NONE);
+ label.setText(Messages.SequenceDiagram_CurrentPage);
+
+ fCurrentPage = new TextArea(ret);
+ fCurrentPage.setBounds(1, fProvider.pagesCount());
+ fCurrentPage.setValue(fProvider.currentPage() + 1);
+
+ fTotalPageComment = new Label(ret, SWT.NONE);
+ fTotalPageComment.setAlignment(SWT.RIGHT);
+
+ updateComments();
+
+ getShell().setText(Messages.SequenceDiagram_SequenceDiagramPages);
+ return ret;
+ }
+
+ @Override
+ public void okPressed() {
+ int currentPageValue = fCurrentPage.getValue() - 1;
+ super.close();
+ fProvider.pageNumberChanged(currentPageValue);
+ }
+
+ /**
+ * Updates the comments texts.
+ */
+ private void updateComments() {
+ int pages = Math.max(0, fProvider.pagesCount());
+ StringBuffer totalPageCommentText = new StringBuffer();
+ totalPageCommentText.append(Messages.SequenceDiagram_Total);
+ totalPageCommentText.append(pages);
+ totalPageCommentText.append(" "); //$NON-NLS-1$
+ if (pages == 0) {
+ totalPageCommentText.append(Messages.SequenceDiagram_pages);
+ } else if (pages == 1) {
+ totalPageCommentText.append(Messages.SequenceDiagram_page);
+ } else {
+ totalPageCommentText.append(Messages.SequenceDiagram_pages);
+ }
+ fTotalPageComment.setText(totalPageCommentText.toString());
+ }
+
+
+ // ------------------------------------------------------------------------
+ // Helper classes
+ // ------------------------------------------------------------------------
+
+ /**
+ * This is a Text Control that accepts only digits and ensures that bounds are respected
+ */
+ protected static class TextArea {
+ /**
+ * The text field.
+ */
+ private Text fText;
+ /**
+ * The minimum page value
+ */
+ private int fMin;
+ /**
+ * The maximum page value
+ */
+ private int fMax;
+
+ /**
+ * Constructor
+ *
+ * @param parent The paren composite
+ */
+ public TextArea(Composite parent) {
+ fText = new Text(parent, SWT.SINGLE | SWT.BORDER | SWT.RIGHT);
+ fText.setTextLimit(10);
+ }
+
+ /**
+ * Sets the page value.
+ *
+ * @param page The page value
+ */
+ public void setValue(int page) {
+ int value = Math.max(fMin, Math.min(fMax, page));
+ fText.setText(Integer.toString(value));
+ }
+
+ /**
+ * Returns the page value.
+ *
+ * @return the page value
+ */
+ public int getValue() {
+ int res;
+ try {
+ res = Integer.parseInt(fText.getText());
+ } catch (Exception e) {
+ // ignored
+ res = 0;
+ }
+ return Math.max(fMin, Math.min(fMax, res));
+ }
+
+ /**
+ * Sets the minimum and maximum page values.
+ *
+ * @param min A minimum page value
+ * @param max A maximum page value
+ */
+ public void setBounds(int min, int max) {
+ fMin = Math.max(0, min);
+ fMax = Math.max(fMin, max);
+ Integer tab[] = new Integer[2];
+ tab[0] = Integer.valueOf(fMin);
+ tab[1] = Integer.valueOf(fMax);
+ fText.setToolTipText(MessageFormat.format(Messages.SequenceDiagram_IsInBetween, (Object[]) tab));
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialog.java
new file mode 100755
index 0000000000..b5378652ee
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialog.java
@@ -0,0 +1,174 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * This class implements a dialog box for collecting printing information.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDPrintDialog extends Dialog {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The sequence dialog widget reference.
+ */
+ private SDWidget fSdView;
+ /**
+ * Sequence dialog print dialog UI
+ */
+ private SDPrintDialogUI fDialogUI;
+ /**
+ * Error message to display.
+ */
+ private String fErrorMessage = null;
+ /**
+ * A message label.
+ */
+ private Label fMessageLabel = null;
+ /**
+ * Flag whether the page is complete or not
+ */
+ private boolean fIsPageComplete = true;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Standard constructor
+ *
+ * @param shell Shell reference
+ * @param viewer Sequence diagram widget reference
+ */
+ public SDPrintDialog(Shell shell, SDWidget viewer) {
+ super(shell);
+ fSdView = viewer;
+
+ fDialogUI = new SDPrintDialogUI(shell, fSdView);
+ fDialogUI.setParentDialog(this);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected Control createDialogArea(Composite p) {
+ p.getShell().setText(Messages.SequenceDiagram_Print);
+ Composite parent = (Composite) super.createDialogArea(p);
+
+ fDialogUI.createDialogArea(parent);
+
+ fMessageLabel = new Label(parent, SWT.NONE);
+ GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
+ gridData.horizontalSpan = 6;
+ fMessageLabel.setLayoutData(gridData);
+ setErrorMessage(fErrorMessage);
+
+ return parent;
+ }
+
+ @Override
+ protected void okPressed() {
+
+ if (fDialogUI.okPressed()) {
+ super.okPressed();
+ }
+ }
+
+ @Override
+ protected void createButtonsForButtonBar(Composite parent) {
+
+ super.createButtonsForButtonBar(parent);
+ createButton(parent, IDialogConstants.CLIENT_ID, Messages.SequenceDiagram_Printer, false);
+
+ getButton(IDialogConstants.CLIENT_ID).addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ fDialogUI.printButtonSelected();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
+ updateButtons();
+ }
+
+ /**
+ * @return the dialog UI
+ */
+ public SDPrintDialogUI getDialogUI() {
+ return fDialogUI;
+ }
+
+ /**
+ * Sets the error message.
+ *
+ * @param message error message to set
+ */
+ public void setErrorMessage(String message) {
+ fErrorMessage = message;
+ if (fMessageLabel != null) {
+ if (fErrorMessage == null) {
+ fMessageLabel.setText(""); //$NON-NLS-1$
+ } else {
+ fMessageLabel.setText(fErrorMessage);
+ }
+ }
+ }
+
+ /**
+ * Sets the page complete flag.
+ * @param complete whether page is complete or not
+ */
+ public void setPageComplete(boolean complete) {
+ fIsPageComplete = complete;
+ updateButtons();
+ }
+
+ /**
+ * Udates the button enable state.
+ */
+ public void updateButtons() {
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ if (fIsPageComplete) {
+ if (okButton != null) {
+ okButton.setEnabled(true);
+ }
+ } else {
+ if (okButton != null) {
+ okButton.setEnabled(false);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialogUI.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialogUI.java
new file mode 100755
index 0000000000..8780c8d243
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SDPrintDialogUI.java
@@ -0,0 +1,1424 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.text.MessageFormat;
+import java.util.Arrays;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.events.TraverseEvent;
+import org.eclipse.swt.events.TraverseListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.printing.PrintDialog;
+import org.eclipse.swt.printing.Printer;
+import org.eclipse.swt.printing.PrinterData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.DiagramToolTip;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.NGC;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * The class implements the actual print dialog UI for collecting printing data.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDPrintDialogUI {
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The set horizontal pages number.
+ */
+ private Button fSetHPagesNumber;
+ /**
+ * The set vertical pages number.
+ */
+ private Button fSetVPagesNumber;
+ /**
+ * Flag whether to use current zoom or not.
+ */
+ private Button fUseCurrentZoom;
+ /**
+ * Flag whether to print all pages or not
+ */
+ private Button fAllPages;
+ /**
+ * Flag whether to print current page only
+ */
+ private Button fCurrentPage;
+ /**
+ * Button to select a page list.
+ */
+ private Button fPageList;
+ /**
+ * Button to select a page range.
+ */
+ private Button fPageRange;
+ /**
+ * Text field to enter from page.
+ */
+ private Text fFromPage;
+ /**
+ * Text field to enter to page.
+ */
+ private Text fToPage;
+ /**
+ * The sequence diagram widget reference.
+ */
+ private SDWidget fSdView;
+ /**
+ * Text field for number of horizontal pages
+ */
+ private Text fHorPagesNum;
+ /**
+ * Text field for number of vertical pages
+ */
+ private Text fVertPagesNum;
+ /**
+ * Text field for toal number of pages
+ */
+ private Text fTotalPages;
+ /**
+ * A modify listener implementation to handle modifications.
+ */
+ private ModifyListener fModifyListener;
+ /**
+ * A selection listener implementation to handle selections.
+ */
+ private SelectionListener fSelectionListener;
+ /**
+ * Local canvas displaying sequence diagram overview.
+ */
+ private LocalSD fOverviewCanvas;
+ /**
+ * Number of pages
+ */
+ private int fNbPages = 0;
+ /**
+ * Number of selected pages.
+ */
+ private int fPageNum = -1;
+ /**
+ * Number of first page.
+ */
+ private int fFirstPage = -1;
+ /**
+ * List of pages to print.
+ */
+ private int fPagesList[];
+
+ /**
+ * Value for dividing the sequence diagram into pages
+ */
+ private float fStepX;
+
+ /**
+ * Value for dividing the sequence diagram into pages
+ */
+ private float fStepY;
+
+ /**
+ * Value for dividing the sequence diagram into pages
+ */
+ private float sTX;
+
+ /**
+ * Value for dividing the sequence diagram into pages
+ */
+ private float sTY;
+
+ /**
+ * Page which to print from.
+ */
+ private int fFrom;
+ /**
+ * Page which to print to.
+ */
+ private int fTo;
+ /**
+ * Flag for enabling multi-selection.
+ */
+ private boolean fMultiSelection = false;
+ /**
+ * Flag for enabling area selection.
+ */
+ private boolean fAreaSelection = false;
+ /**
+ * Flag for printing all.
+ */
+ private boolean fPrintAll;
+ /**
+ * Flag for printing current page only.
+ */
+ private boolean fPrintCurrent;
+ /**
+ * Flag for printing a selection of pages.
+ */
+ private boolean fPrintSelection;
+ /**
+ * Flag for printing a range of pages.
+ */
+ private boolean fPrintRange;
+ /**
+ * Number of selected rows
+ */
+ private int fNbRows;
+ /**
+ * Number of selected lines
+ */
+ private int fNbLines;
+ /**
+ * The zoom factor.
+ */
+ private float fZoomFactor;
+ /**
+ * The printer data reference.
+ */
+ private PrinterData fPrinterData;
+ /**
+ * The diagram tooltip to show if necessary.
+ */
+ private DiagramToolTip fToolTip = null;
+ /**
+ * Label for current selection.
+ */
+ private Label fCurrentSelection;
+ /**
+ * The shell reference.
+ */
+ private Shell fShell;
+ /**
+ * Button to open printer dialog from OS.
+ */
+ private Button fPrinterDialog;
+ /**
+ * Flag for showing print button.
+ */
+ private boolean fShowPrintButton;
+ /**
+ * Test value
+ */
+ private int fTest = 3;
+ /**
+ * Parent wizard page if used as wizard
+ */
+ private WizardPage fParentWizardPage = null;
+ /**
+ * Reference to parent print dialog.
+ */
+ private SDPrintDialog fParentDialog = null;
+
+ // ------------------------------------------------------------------------
+ // Helper Class
+ // ------------------------------------------------------------------------
+ /**
+ * Local sequence diagram widget used to display overview of sequence diagram to print.
+ * @version 1.0
+ */
+ private class LocalSD extends SDWidget {
+
+ /**
+ * Constructor
+ * @param c Parent composite
+ * @param s Style bits
+ */
+ public LocalSD(Composite c, int s) {
+ super(c, s);
+ }
+
+ @Override
+ public int getContentsHeight() {
+ if (fSdView.getContentsHeight() > fSdView.getContentsHeight()) {
+ return (int) (fSdView.getVisibleHeight() / (float) fTest / fSdView.getZoomValue());
+ }
+ return super.getContentsHeight();
+ }
+
+ @Override
+ public int getContentsWidth() {
+ if (fSdView.getVisibleWidth() > fSdView.getContentsWidth()) {
+ return (int) (fSdView.getVisibleWidth() / (float) fTest / fSdView.getZoomValue());
+ }
+ return super.getContentsWidth();
+ }
+
+ @Override
+ protected void contentsMouseHover(MouseEvent event) {
+ }
+
+ /**
+ * Creates page selection images.
+ *
+ * @param img - Overview image
+ * @param width -The width value
+ * @param stepX - Step X
+ * @param height - Height value
+ * @param stepY - Step Y
+ * @return new image
+ */
+ protected Image createPagesSelectionImages(Image img, int width, float stepX, int height, float stepY) {
+
+ Image over = new Image(super.getShell().getDisplay(), img.getImageData());
+
+ for (int pageIndex = 0; pageIndex < fPagesList.length; pageIndex++) {
+
+ int pageNum = fPagesList[pageIndex];
+
+ if (getPagesForSelection() > 0 && pageNum > 0) {
+ int line = pageNum / getNbRow();
+ int row = pageNum % getNbRow();
+ if (row != 0) {
+ line++;
+ } else {
+ row = getNbRow();
+ }
+
+ line--;
+ row--;
+
+ Image toDel = over;
+ if (fOverviewCanvas.isFocusControl()) {
+ over = new Image(super.getShell().getDisplay(), drawRegionSelected(toDel, new Rectangle(contentsToViewX((int) (row * stepX * fOverviewCanvas.getZoomValue())), contentsToViewY((int) (line * stepY * fOverviewCanvas.getZoomValue())),
+ ((int) (stepX * fOverviewCanvas.getZoomValue())), ((int) (stepY * fOverviewCanvas.getZoomValue()))), new RGB(0, 0, 128)));
+ } else {
+ over = new Image(super.getShell().getDisplay(), drawRegionSelected(toDel, new Rectangle(contentsToViewX((int) (row * stepX * fOverviewCanvas.getZoomValue())), contentsToViewY((int) (line * stepY * fOverviewCanvas.getZoomValue())),
+ ((int) (stepX * fOverviewCanvas.getZoomValue())), ((int) (stepY * fOverviewCanvas.getZoomValue()))), new RGB(221, 208, 200)));
+ }
+ toDel.dispose();
+ }
+ }
+
+ Arrays.sort(fPagesList);
+ int pos = Arrays.binarySearch(fPagesList, fPageNum);
+ if ((pos < 0) && (getPagesForSelection() > 0 && fPageNum > 0)) {
+ int line = fPageNum / getNbRow();
+ int row = fPageNum % getNbRow();
+ if (row != 0) {
+ line++;
+ } else {
+ row = getNbRow();
+ }
+
+ line--;
+ row--;
+
+ Image toDel = over;
+ over = new Image(super.getShell().getDisplay(), drawRegionSelected(toDel, new Rectangle(contentsToViewX((int) (row * stepX * fOverviewCanvas.getZoomValue())), contentsToViewY((int) (line * stepY * fOverviewCanvas.getZoomValue())),
+ ((int) (stepX * fOverviewCanvas.getZoomValue())), ((int) (stepY * fOverviewCanvas.getZoomValue()))), new RGB(221, 208, 200)));
+ toDel.dispose();
+ }
+
+ GC imGC2 = new GC(over);
+ imGC2.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
+ NGC imGC = new NGC(fOverviewCanvas, imGC2);
+ for (int i = 0, x = 0; x <= width && stepX > 0; i++, x = (int) (i * stepX)) {
+ imGC.drawLine(x, 0, x, height);
+ }
+
+ for (int j = 0, y = 0; y <= height && stepY > 0; j++, y = (int) (j * stepY)) {
+ imGC.drawLine(0, y, width, y);
+ }
+
+ imGC2.dispose();
+ imGC.dispose();
+ return over;
+ }
+
+ @Override
+ protected void drawContents(GC gc, int clipx, int clipy, int clipw, int cliph) {
+
+ Image dbuffer = getDrawBuffer();
+ computeStepXY();
+ Image d;
+
+ int lw = (int) (getContentsWidth() / getZoomValue());
+ if (getContentsWidth() < getVisibleWidth()) {
+ lw = (int) (getVisibleWidth() / getZoomValue());
+ }
+
+ int lh = (int) (getContentsHeight() / getZoomValue());
+ if (getContentsHeight() < getVisibleHeight()) {
+ lh = (int) (getVisibleHeight() / getZoomValue());
+ }
+ d = createPagesSelectionImages(dbuffer, lw, fStepX, lh, fStepY);
+
+ if (!isEnabled()) {
+ Image toDel = d;
+ d = new Image(super.getShell().getDisplay(), drawRegionSelected(d, new Rectangle(0, 0, lw, lh), new RGB(221, 208, 200)));
+ toDel.dispose();
+ }
+
+ Rectangle area = getClientArea();
+ int w = d.getBounds().width;
+ int h = d.getBounds().height;
+ gc.drawImage(d, 0, 0, w, h, 0, 0, area.width, area.height);
+
+ fTotalPages.setText(Integer.valueOf(maxNumOfPages()).toString());
+ displayPageNum();
+ dbuffer.dispose();
+ d.dispose();
+ gc.dispose();
+ }
+
+ @Override
+ protected void keyPressedEvent(KeyEvent e) {
+ if (e.keyCode == SWT.CTRL) {
+ fMultiSelection = true;
+ }
+ if (e.keyCode == SWT.SHIFT) {
+ fAreaSelection = true;
+ }
+ if (e.keyCode == SWT.ARROW_DOWN) {
+ if (fPageNum + getNbRow() <= maxNumOfPages()) {
+ fPageNum += getNbRow();
+ }
+ int line = fPageNum / getNbRow();
+ int row = fPageNum % getNbRow();
+ if (row == 0) {
+ line--;
+ }
+ if ((line + 1) * fStepY > (fOverviewCanvas.getContentsY() + fOverviewCanvas.getVisibleHeight()) / fOverviewCanvas.getZoomValue()) {
+ fOverviewCanvas.scrollBy(0, (int) (fStepY * fOverviewCanvas.getZoomValue()));
+ }
+ }
+ if (e.keyCode == SWT.ARROW_UP) {
+ if (fPageNum - getNbRow() > 0) {
+ fPageNum -= getNbRow();
+ }
+ int line = fPageNum / getNbRow();
+ int row = fPageNum % getNbRow();
+ if (row == 0) {
+ line--;
+ }
+ if ((line) * fStepY <= fOverviewCanvas.getContentsY() / fOverviewCanvas.getZoomValue()) {
+ fOverviewCanvas.scrollBy(0, -(int) (fStepY * fOverviewCanvas.getZoomValue()));
+ }
+ }
+ if (e.keyCode == SWT.ARROW_LEFT) {
+ if ((fPageNum - 2) / getNbRow() == (fPageNum - 1) / getNbRow() && fPageNum > 1) {
+ fPageNum--;
+ }
+ int row = fPageNum % getNbRow();
+ if ((row - 1) * fStepX < (fOverviewCanvas.getContentsX()) / fOverviewCanvas.getZoomValue()) {
+ fOverviewCanvas.scrollBy(-(int) (fStepX * fOverviewCanvas.getZoomValue()), 0);
+ }
+ }
+ if (e.keyCode == SWT.ARROW_RIGHT) {
+ if ((fPageNum - 1) / getNbRow() == fPageNum / getNbRow()) {
+ fPageNum++;
+ }
+ int row = fPageNum % getNbRow();
+ if (row == 0) {
+ row = getNbRow();
+ }
+ if ((row) * fStepX > (fOverviewCanvas.getContentsX() + fOverviewCanvas.getVisibleWidth()) / fOverviewCanvas.getZoomValue()) {
+ fOverviewCanvas.scrollBy((int) (fStepX * fOverviewCanvas.getZoomValue()), 0);
+ }
+ }
+
+ if (e.keyCode == 32 && fPageNum > -1) {
+ Arrays.sort(fPagesList);
+ int pos = Arrays.binarySearch(fPagesList, fPageNum);
+ if (pos < 0) {
+ addToPagesList(fPageNum);
+ } else {
+ removeFromPagesList(fPageNum);
+ }
+ }
+
+ if (!fAreaSelection && !fMultiSelection) {
+ fFirstPage = fPageNum;
+ fPagesList = new int[1];
+ fPagesList[0] = fPageNum;
+ } else if ((fPageNum != -1) && (fAreaSelection) && (fFirstPage != -1)) {
+ fPagesList = new int[0];
+ int line1 = fFirstPage / getNbRow();
+ int row1 = fFirstPage % getNbRow();
+ if (row1 != 0) {
+ line1++;
+ } else {
+ row1 = getNbRow();
+ }
+
+ int line2 = fPageNum / getNbRow();
+ int row2 = fPageNum % getNbRow();
+ if (row2 != 0) {
+ line2++;
+ } else {
+ row2 = getNbRow();
+ }
+
+ int temp;
+ if (line1 > line2) {
+ temp = line2;
+ line2 = line1;
+ line1 = temp;
+ }
+
+ if (row1 > row2) {
+ temp = row2;
+ row2 = row1;
+ row1 = temp;
+ }
+
+ for (int i = row1 - 1; i < row2; i++) {
+ for (int j = line1 - 1; j < line2; j++) {
+ addToPagesList(i + j * getNbRow() + 1);
+ }
+ }
+ }
+ displayPageNum();
+ fOverviewCanvas.redraw();
+ }
+
+ @Override
+ protected void keyReleasedEvent(KeyEvent e) {
+ if (e.keyCode == SWT.CTRL) {
+ fMultiSelection = false;
+ }
+ if (e.keyCode == SWT.SHIFT) {
+ fAreaSelection = false;
+ }
+ }
+
+ @Override
+ protected void contentsMouseDownEvent(MouseEvent event) {
+
+ computeStepXY();
+ int x1 = (int) ((event.x / fOverviewCanvas.getZoomValue()) / fStepX);
+ int x2 = (int) ((event.y / fOverviewCanvas.getZoomValue()) / fStepY);
+
+ int oldPage = fPageNum;
+
+ fPageNum = x1 + x2 * getNbRow() + 1;
+
+ if (fPageNum > maxNumOfPages()) {
+ fPageNum = oldPage;
+ return;
+ }
+
+ if (!fAreaSelection) {
+ fFirstPage = fPageNum;
+ }
+
+ if ((fPageNum != -1) && (fMultiSelection)) {
+ Arrays.sort(fPagesList);
+ int pos = Arrays.binarySearch(fPagesList, fPageNum);
+ if (pos < 0) {
+ addToPagesList(fPageNum);
+ } else {
+ removeFromPagesList(fPageNum);
+ }
+ } else if ((fPageNum != -1) && (fAreaSelection) && (fFirstPage != -1)) {
+
+ fPagesList = new int[0];
+
+ int line1 = fFirstPage / getNbRow();
+ int row1 = fFirstPage % getNbRow();
+ if (row1 != 0) {
+ line1++;
+ } else {
+ row1 = getNbRow();
+ }
+
+ int line2 = fPageNum / getNbRow();
+ int row2 = fPageNum % getNbRow();
+ if (row2 != 0) {
+ line2++;
+ } else {
+ row2 = getNbRow();
+ }
+
+ int temp;
+ if (line1 > line2) {
+ temp = line2;
+ line2 = line1;
+ line1 = temp;
+ }
+
+ if (row1 > row2) {
+ temp = row2;
+ row2 = row1;
+ row1 = temp;
+ }
+
+ for (int i = row1 - 1; i < row2; i++) {
+ for (int j = line1 - 1; j < line2; j++) {
+ addToPagesList(i + j * getNbRow() + 1);
+ }
+ }
+ } else {
+ fPagesList = new int[1];
+ fPagesList[0] = fPageNum;
+ }
+ if ((event.stateMask & SWT.CTRL) != 0) {
+ fMultiSelection = true;
+ }
+ displayPageNum();
+ redraw();
+ }
+
+ @Override
+ protected void contentsMouseMoveEvent(MouseEvent e) {
+ fToolTip.hideToolTip();
+ }
+
+ @Override
+ public void resizeContents(int w, int h) {
+ super.resizeContents(w, h);
+ }
+
+ }
+
+ /**
+ * A traverse listener implementation.
+ */
+ protected static class LocalTraverseListener implements TraverseListener {
+ @Override
+ public void keyTraversed(TraverseEvent e) {
+ if ((e.detail == SWT.TRAVERSE_TAB_NEXT) || (e.detail == SWT.TRAVERSE_TAB_PREVIOUS)) {
+ e.doit = true;
+ }
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor
+ *
+ * @param shell
+ * The shell reference
+ * @param sdWidget
+ * The sequence diagram widget reference
+ */
+ public SDPrintDialogUI(Shell shell, SDWidget sdWidget) {
+ this(shell, sdWidget, false);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param shell
+ * The shell reference
+ * @param sdWidget
+ * The sequence diagram widget reference
+ * @param showPrintBtn
+ * Flag for showing print buttons
+ */
+ public SDPrintDialogUI(Shell shell, SDWidget sdWidget, boolean showPrintBtn) {
+ fShell = shell;
+ fSdView = sdWidget;
+ fShowPrintButton = showPrintBtn;
+
+ fPrinterData = Printer.getDefaultPrinterData();
+ if (fPrinterData != null) {
+ fPrinterData.scope = PrinterData.SELECTION;
+ }
+
+ fPagesList = new int[0];
+
+ fSelectionListener = new SelectionListener() {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (fUseCurrentZoom.getSelection()) {
+ fHorPagesNum.setEnabled(false);
+ fVertPagesNum.setEnabled(false);
+ }
+ if (fSetHPagesNumber.getSelection()) {
+ fHorPagesNum.setEnabled(true);
+ fVertPagesNum.setEnabled(false);
+ if (fCurrentPage.getSelection()) {
+ fCurrentPage.setSelection(false);
+ fAllPages.setSelection(true);
+ }
+ if ("".equals(fHorPagesNum.getText())) { //$NON-NLS-1$
+ fHorPagesNum.setText("1"); //$NON-NLS-1$
+ }
+ }
+ if (fSetVPagesNumber.getSelection()) {
+ fHorPagesNum.setEnabled(false);
+ fVertPagesNum.setEnabled(true);
+ if (fCurrentPage.getSelection()) {
+ fCurrentPage.setSelection(false);
+ fAllPages.setSelection(true);
+ }
+ if ("".equals(fVertPagesNum.getText())) { //$NON-NLS-1$
+ fVertPagesNum.setText("1"); //$NON-NLS-1$
+ }
+ }
+ if (fCurrentPage.getSelection() || fAllPages.getSelection() || fPageList.getSelection()) {
+ fFromPage.setEnabled(false);
+ fToPage.setEnabled(false);
+ } else {
+ fFromPage.setEnabled(true);
+ fToPage.setEnabled(true);
+ }
+
+ fCurrentPage.setEnabled(fUseCurrentZoom.getSelection());
+ fOverviewCanvas.setEnabled(fPageList.getSelection());
+ if (fOverviewCanvas.isEnabled() && (e.widget == fUseCurrentZoom || e.widget == fSetHPagesNumber || e.widget == fSetVPagesNumber)) {
+ fPagesList = new int[1];
+ fPagesList[0] = 1;
+ fPageNum = 1;
+ fFirstPage = 1;
+ } else if ((fOverviewCanvas.isEnabled() && (e.widget == fPageList)) &&
+ (fPagesList == null || fPagesList.length <= 0)) {
+
+ fPagesList = new int[1];
+ fPagesList[0] = 1;
+ fPageNum = 1;
+ fFirstPage = 1;
+ }
+ computeStepXY();
+ fTotalPages.setText(Integer.valueOf(maxNumOfPages()).toString());
+ fOverviewCanvas.redraw();
+ fOverviewCanvas.update();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ fPagesList = new int[0];
+ computeStepXY();
+ fOverviewCanvas.redraw();
+ }
+
+ };
+
+ fModifyListener = new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ fPagesList = new int[0];
+ computeStepXY();
+ fTotalPages.setText(Integer.valueOf(maxNumOfPages()).toString());
+ fOverviewCanvas.redraw();
+ }
+
+ };
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Creates new grid data object.
+ *
+ * @param span horizontal span.
+ * @return grid data
+ */
+ protected GridData newGridData(int span) {
+ GridData data = new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = span;
+ return data;
+ }
+
+ /**
+ * Creates the dialog area.
+ *
+ * @param parent The parent composite
+ * @return dialog control
+ */
+ public Control createDialogArea(Composite parent) {
+
+ GridLayout parentLayout = new GridLayout();
+ parentLayout.numColumns = 6;
+ parent.setLayout(parentLayout);
+
+ Group g1 = new Group(parent, SWT.SHADOW_NONE);
+ g1.setText(Messages.SequenceDiagram_ZoomOption);
+ g1.setLayoutData(newGridData(3));
+ GridLayout g1layout = new GridLayout();
+ g1layout.numColumns = 2;
+ g1.setLayout(g1layout);
+
+ fUseCurrentZoom = new Button(g1, SWT.RADIO);
+ fUseCurrentZoom.setText(Messages.SequenceDiagram_UseCurrentZoom);
+ fUseCurrentZoom.setLayoutData(newGridData(2));
+ fUseCurrentZoom.addSelectionListener(fSelectionListener);
+
+ fSetHPagesNumber = new Button(g1, SWT.RADIO);
+ fSetHPagesNumber.setText(Messages.SequenceDiagram_NumberOfHorizontalPages);
+ fSetHPagesNumber.setLayoutData(newGridData(1));
+ fSetHPagesNumber.addSelectionListener(fSelectionListener);
+
+ fHorPagesNum = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fHorPagesNum.addModifyListener(fModifyListener);
+
+ fSetVPagesNumber = new Button(g1, SWT.RADIO);
+ fSetVPagesNumber.setText(Messages.SequenceDiagram_NumberOfVerticalPages);
+ fSetVPagesNumber.setLayoutData(newGridData(1));
+ fSetVPagesNumber.addSelectionListener(fSelectionListener);
+
+ fVertPagesNum = new Text(g1, SWT.SINGLE | SWT.BORDER);
+ fVertPagesNum.addModifyListener(fModifyListener);
+
+ Label nbTotal = new Label(g1, SWT.SHADOW_NONE | SWT.RIGHT);
+ nbTotal.setText(Messages.TotalNumberOfPages);
+ // nbTotal.setLayoutData(newGridData(1));
+
+ fTotalPages = new Text(g1, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY);
+ // nbHV.addModifyListener(modifListener);
+
+ Group g2 = new Group(parent, SWT.SHADOW_NONE);
+ g2.setText(Messages.SequenceDiagram_Preview);
+ GridData data = new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL);
+ data.horizontalSpan = 3;
+ data.verticalSpan = 2;
+ g2.setLayoutData(data);
+ GridLayout g2layout = new GridLayout();
+ // g2layout.
+ g2layout.numColumns = 1;
+ // SVLayout g2layout = new SVLayout();
+ g2.setLayout(g2layout);
+
+ GridData data2 = new GridData(GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL);
+ data2.horizontalSpan = 1;
+ data2.verticalSpan = 1;
+
+ fOverviewCanvas = new LocalSD(g2, SWT.NO_BACKGROUND);
+ GridData seqDiagLayoutData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
+ fOverviewCanvas.setLayoutData(seqDiagLayoutData);
+ // overviewCanvas.resizeContents(100,100);
+ if (fSdView.getContentsWidth() < fSdView.getVisibleWidth() && fSdView.getContentsHeight() < fSdView.getVisibleHeight()) {
+ fTest = 3;
+ } else {
+ fTest = 10;
+ }
+ fOverviewCanvas.setFrame(fSdView.getFrame(), true);
+ fOverviewCanvas.setZoomValue((float) 1 / fTest);
+ fOverviewCanvas.setCornerControl(null);
+ seqDiagLayoutData.widthHint = fOverviewCanvas.getContentsWidth() / fTest;
+ seqDiagLayoutData.widthHint = fOverviewCanvas.getFrame().getWidth() / fTest + 15;
+
+ if (fSdView.getVisibleWidth() < fSdView.getContentsWidth()) {
+ seqDiagLayoutData.widthHint = fOverviewCanvas.getContentsWidth() / fTest;
+ if (seqDiagLayoutData.widthHint > Display.getDefault().getClientArea().width / 4) {
+ seqDiagLayoutData.widthHint = Display.getDefault().getClientArea().width / 4;
+ }
+ } else {
+ seqDiagLayoutData.widthHint = fOverviewCanvas.getFrame().getWidth() / fTest + 15;
+ }
+
+ if (fSdView.getVisibleHeight() < fSdView.getContentsHeight()) {
+ seqDiagLayoutData.heightHint = fOverviewCanvas.getContentsHeight() / fTest;
+ if (seqDiagLayoutData.heightHint > Display.getDefault().getClientArea().width / 4) {
+ seqDiagLayoutData.heightHint = Display.getDefault().getClientArea().width / 4;
+ }
+ } else {
+ seqDiagLayoutData.heightHint = fOverviewCanvas.getFrame().getHeight() / fTest;
+ }
+
+ fOverviewCanvas.setEnabled(false);
+
+ fCurrentSelection = new Label(g2, SWT.SHADOW_NONE | SWT.LEFT);
+ fCurrentSelection.setLayoutData(newGridData(1));
+
+ Group g3 = new Group(parent, SWT.SHADOW_NONE);
+ g3.setText(Messages.SequenceDiagram_PrintRange);
+ g3.setLayoutData(newGridData(3));
+ GridLayout g3layout = new GridLayout();
+ g3layout.numColumns = 4;
+ g3.setLayout(g3layout);
+
+ fAllPages = new Button(g3, SWT.RADIO);
+ fAllPages.setText(Messages.SequenceDiagram_AllPages);
+ fAllPages.setLayoutData(newGridData(4));
+ fAllPages.addSelectionListener(fSelectionListener);
+
+ fCurrentPage = new Button(g3, SWT.RADIO);
+ fCurrentPage.setText(Messages.SequenceDiagram_CurrentView);
+ fCurrentPage.setLayoutData(newGridData(4));
+ fCurrentPage.setEnabled(true);
+ fCurrentPage.setSelection(true);
+ fCurrentPage.addSelectionListener(fSelectionListener);
+
+ fPageList = new Button(g3, SWT.RADIO);
+ fPageList.setText(Messages.SequenceDiagram_SelectedPages);
+ fPageList.setLayoutData(newGridData(4));
+ fPageList.addSelectionListener(fSelectionListener);
+
+ fPageRange = new Button(g3, SWT.RADIO);
+ fPageRange.setText(Messages.SequenceDiagram_FromPage);
+ fPageRange.setLayoutData(newGridData(1));
+ fPageRange.addSelectionListener(fSelectionListener);
+
+ fFromPage = new Text(g3, SWT.SINGLE | SWT.BORDER);
+
+ Label labelTo = new Label(g3, SWT.CENTER);
+ labelTo.setText(Messages.SequenceDiagram_to);
+
+ fToPage = new Text(g3, SWT.SINGLE | SWT.BORDER);
+
+ fToolTip = new DiagramToolTip(fOverviewCanvas);
+
+ fOverviewCanvas.getViewControl().addMouseTrackListener(new MouseTrackListener() {
+ @Override
+ public void mouseEnter(MouseEvent e) {
+ fToolTip.hideToolTip();
+ }
+
+ @Override
+ public void mouseExit(MouseEvent e) {
+ fToolTip.hideToolTip();
+ }
+
+ @Override
+ public void mouseHover(MouseEvent e) {
+ int x1 = (int) (fOverviewCanvas.viewToContentsX(e.x) / fOverviewCanvas.getZoomValue() / fStepX);
+ int x2 = (int) (fOverviewCanvas.viewToContentsY(e.y) / fOverviewCanvas.getZoomValue() / fStepY);
+ int num = x1 + x2 * getNbRow() + 1;
+ if (num > maxNumOfPages()) {
+ return;
+ }
+ if (num > 0) {
+ fToolTip.showToolTip(String.valueOf(num));
+ displayPageNum();
+ } else {
+ fCurrentSelection.setText("");//$NON-NLS-1$
+ fToolTip.hideToolTip();
+ }
+ }
+
+ });
+
+ fOverviewCanvas.addTraverseListener(new LocalTraverseListener());
+
+ fOverviewCanvas.addFocusListener(new FocusListener() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ fOverviewCanvas.redraw();
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ fOverviewCanvas.redraw();
+ }
+ });
+
+ if (fShowPrintButton) {
+ Composite printerDlg = new Composite(parent, SWT.NONE);
+ data = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
+ data.horizontalSpan = 6;
+ parentLayout = new GridLayout();
+ parentLayout.numColumns = 2;
+ printerDlg.setLayout(parentLayout);
+ printerDlg.setLayoutData(data);
+
+ Label label = new Label(printerDlg, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false));
+ fPrinterDialog = new Button(printerDlg, SWT.PUSH);
+ fPrinterDialog.setText(Messages.SequenceDiagram_Printer);
+
+ fPrinterDialog.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ printButtonSelected();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+
+ });
+ }
+
+ updatePrinterStatus();
+
+ return parent;
+ }
+
+ /**
+ * Get number of pages for selection.
+ * @return number of pages for selection.
+ */
+ public int getPagesForSelection() {
+ return fNbPages;
+ }
+
+ /**
+ * Handler for when the OK button is pressed
+ *
+ * @return True if the operation was successful, false if there was an error
+ */
+ public boolean okPressed() {
+ fPrintAll = fAllPages.getSelection();
+ fPrintCurrent = fCurrentPage.getSelection();
+ fPrintSelection = fPageList.getSelection();
+ fPrintRange = fPageRange.getSelection();
+ try {
+ if (fPrintRange) {
+ fFrom = Integer.valueOf(fFromPage.getText()).intValue();
+ fTo = Integer.valueOf(fToPage.getText()).intValue();
+ if (fFrom > maxNumOfPages() || fTo > maxNumOfPages() || fFrom <= 0 || fTo <= 0) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_InvalidRange);
+ return false;
+ }
+ } else if (fSetHPagesNumber.getSelection() && fNbPages <= 0) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_InvalidNbHorizontal);
+ return false;
+ } else if (fSetVPagesNumber.getSelection() && fNbPages <= 0) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_InvalidNbVertical);
+ return false;
+ } else if (fPrintSelection && getPageList().length <= 0) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_NoPageSelected);
+ return false;
+ }
+
+ } catch (Exception e) {
+ MessageDialog.openError(getShell(), Messages.SequenceDiagram_Error, Messages.SequenceDiagram_InvalidRange);
+ fFrom = 0;
+ fTo = 0;
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Draws region that was selected
+ * @param img The corresponding image
+ * @param r The selected rectangle.
+ * @param color The color to use for selection
+ * @return image data reference
+ */
+ public ImageData drawRegionSelected(Image img, Rectangle r, RGB color) {
+ ImageData id = img.getImageData();
+ for (int a = 0; a < r.width && r.x + a < id.width; a++) {
+ for (int b = 0; b < r.height && r.y + b < id.height; b++) {
+ int index = id.getPixel(r.x + a, r.y + b);
+ RGB rgb = id.palette.getRGB(index);
+ rgb = combine(color, rgb);
+ id.setPixel(r.x + a, r.y + b, id.palette.getPixel(rgb));
+ }
+ }
+ return id;
+ }
+
+ /**
+ * Combines two RGB colors.
+ * @param front The front color
+ * @param back The back color
+ * @return new RGB color
+ */
+ public static RGB combine(RGB front, RGB back) {
+ int _af = 128;
+ int _ab = 200;
+
+ double af = (_af) / 255.0;
+ double rf = front.red;
+ double gf = front.green;
+ double bf = front.blue;
+
+ double ab = (_ab) / 255.0;
+ double rb = back.red;
+ double gb = back.green;
+ double bb = back.blue;
+
+ double k = (1.0 - af) * ab;
+ int r = (int) ((af * rf + k * rb));
+ int g = (int) ((af * gf + k * gb));
+ int b = (int) ((af * bf + k * bb));
+
+ return new RGB(r, g, b);
+ }
+
+ /**
+ * Computes value for X coordinates step and Y coordinates step.
+ */
+ protected void computeStepXY() {
+ float cw = fOverviewCanvas.getContentsWidth() / fOverviewCanvas.getZoomValue();
+ float ch = fOverviewCanvas.getContentsHeight() / fOverviewCanvas.getZoomValue();
+ try {
+ if (fPrinterData == null) {
+ fStepX = 0;
+ fStepY = 0;
+ fNbPages = 0;
+ fZoomFactor = 0;
+ } else {
+ Printer printer = new Printer(fPrinterData);
+ if (fSetHPagesNumber.getSelection()) {
+ fNbPages = Integer.valueOf(fHorPagesNum.getText()).intValue();
+ float z1 = fSdView.getContentsWidth() / cw;
+ float z2 = printer.getClientArea().width / ((float) fSdView.getContentsWidth() / fNbPages);
+
+ fStepY = printer.getClientArea().height / z1 / z2;
+ fStepX = cw / fNbPages;
+ } else if (fSetVPagesNumber.getSelection()) {
+ fNbPages = Integer.valueOf(fVertPagesNum.getText()).intValue();
+ float z1 = fSdView.getContentsHeight() / ch;
+ float z2 = printer.getClientArea().height / ((float) fSdView.getContentsHeight() / fNbPages);
+ fStepX = printer.getClientArea().width / z1 / z2;
+ fStepY = ch / fNbPages;
+ } else {
+ float z1 = fSdView.getContentsWidth() / (cw);
+ fStepX = fSdView.getVisibleWidth() / z1;
+ fNbPages = Math.round(cw / fStepX);
+ if (fNbPages == 0) {
+ fNbPages = 1;
+ }
+ int pw = printer.getClientArea().width;
+ int ph = printer.getClientArea().height;
+ float z2 = pw / ((float) fSdView.getContentsWidth() / fNbPages);
+ fStepY = ph / z1 / z2;
+ }
+ }
+ } catch (NumberFormatException e) {
+ fStepX = fStepY = fNbPages = 0;
+ fZoomFactor = 0;
+ }
+ sTX = fStepX * (fSdView.getContentsWidth() / cw);
+ sTY = fStepY * (fSdView.getContentsHeight() / ch);
+ float rat = 1;
+ if ((fSdView.getVisibleWidth() > fSdView.getContentsWidth()) && (fSetVPagesNumber.getSelection() || fSetHPagesNumber.getSelection())) {
+ rat = (float) fSdView.getVisibleWidth() / (float) fSdView.getContentsWidth();
+ }
+ fZoomFactor = (fOverviewCanvas.getContentsWidth() / cw) / fOverviewCanvas.getZoomFactor() * rat;
+ }
+
+ /**
+ * Returns the pages list.
+ *
+ * @return the pages list.
+ */
+ public int[] getPageList() {
+ return Arrays.copyOf(fPagesList, fPagesList.length);
+ }
+
+ /**
+ * Adds a page to pages list.
+ *
+ * @param num
+ * The number of the the new page
+ */
+ public void addToPagesList(int num) {
+ int temp[] = new int[fPagesList.length + 1];
+ System.arraycopy(fPagesList, 0, temp, 0, fPagesList.length);
+ temp[temp.length - 1] = num;
+ fPagesList = new int[temp.length];
+ System.arraycopy(temp, 0, fPagesList, 0, temp.length);
+ }
+
+ /**
+ * Removes a page from the pages list.
+ *
+ * @param num
+ * The number of the page to remove
+ */
+ public void removeFromPagesList(int num) {
+ int pos = Arrays.binarySearch(fPagesList, num);
+ int temp[] = new int[fPagesList.length - 1];
+ System.arraycopy(fPagesList, 0, temp, 0, pos);
+ System.arraycopy(fPagesList, pos + 1, temp, pos, fPagesList.length - pos - 1);
+ fPagesList = new int[temp.length];
+ System.arraycopy(temp, 0, fPagesList, 0, temp.length);
+ }
+
+ /**
+ * Returns the maximum number of pages.
+ *
+ * @return maximum number of pages.
+ */
+ public int maxNumOfPages() {
+ return (getNbRow() * getNbLines());
+ }
+
+ /**
+ * Returns the number of rows.
+ *
+ * @return number of rows.
+ */
+ public int getNbRow() {
+ if (!fSetHPagesNumber.isDisposed()) {
+ int cw = (int) (fOverviewCanvas.getContentsWidth() / fOverviewCanvas.getZoomValue());
+ int row = 1;
+ if (fStepX != 0) {
+ row = (int) (cw / fStepX);
+ if (fSetHPagesNumber.getSelection()) {
+ row = Math.round(cw / fStepX);
+ } else if ((cw % fStepX != 0)) {
+ row++;
+ }
+ }
+ fNbRows = row;
+ }
+ return fNbRows;
+ }
+
+ /**
+ * Returns the number of lines.
+ *
+ * @return number of lines
+ */
+ public int getNbLines() {
+ if (!fSetVPagesNumber.isDisposed()) {
+ int ch = (int) (fOverviewCanvas.getContentsHeight() / fOverviewCanvas.getZoomValue());
+ int line = 1;
+ if (fStepY != 0) {
+ line = (int) (ch / fStepY);
+ if (fSetVPagesNumber.getSelection()) {
+ line = Math.round(ch / fStepY);
+ } else if (ch % fStepY != 0) {
+ line++;
+ }
+ }
+ fNbLines = line;
+ }
+ return fNbLines;
+ }
+
+ /**
+ * Returns whether to print all pages or not.
+ *
+ * @return <code>true</code> for all pages else <code>false</code>.
+ */
+ public boolean printAll() {
+ return fPrintAll;
+ }
+
+ /**
+ * Returns whether to print only current page
+ *
+ * @return <code>true</code> for current page only else <code>false</code>..
+ */
+ public boolean printCurrent() {
+ return fPrintCurrent;
+ }
+
+ /**
+ * Returns whether to print selected pages.
+ *
+ * @return <code>true</code> for selected pages only else <code>false</code>.
+ */
+ public boolean printSelection() {
+ return fPrintSelection;
+ }
+
+ /**
+ * Returns whether to print range of pages.
+ *
+ * @return <code>true</code> for range of pages only else <code>false</code>.
+ */
+ public boolean printRange() {
+ return fPrintRange;
+ }
+
+ /**
+ * Returns the step in X direction.
+ *
+ * @return step in X direction
+ */
+ public float getStepX() {
+ return sTX;
+ }
+
+ /**
+ * Returns the step in Y direction.
+ *
+ * @return step in Y direction
+ */
+ public float getStepY() {
+ return sTY;
+ }
+
+ /**
+ * Returns the zoom factor
+ *
+ * @return zoom factor
+ */
+ public float getZoomFactor() {
+ return fZoomFactor;
+ }
+
+ /**
+ * Returns the printer data reference.
+ *
+ * @return printer data reference
+ */
+ public PrinterData getPrinterData() {
+ return fPrinterData;
+ }
+
+ /**
+ * Returns the page number to start printing from.
+ *
+ * @return page number to start printing from
+ */
+ public int getFrom() {
+ return fFrom;
+ }
+
+ /**
+ * Returns the page number to print to.
+ *
+ * @return page number to print to
+ */
+ public int getTo() {
+ return fTo;
+ }
+
+ /**
+ * Displays current number of pages
+ */
+ protected void displayPageNum() {
+ if (fPageNum > 0) {
+ String message = MessageFormat.format(Messages.SequenceDiagram_Page, new Object[] { Integer.valueOf(fPageNum) });
+ fCurrentSelection.setText(message);
+ fCurrentSelection.getParent().layout();
+ }
+ }
+
+ /**
+ * Returns the shell reference.
+ *
+ * @return the shell reference.
+ */
+ public Shell getShell() {
+ return fShell;
+ }
+
+ /**
+ * Sets the shell.
+ *
+ * @param shell The shell reference.
+ */
+ public void setShell(Shell shell) {
+ fShell = shell;
+ }
+
+ /**
+ * Handle selection of print button.
+ */
+ public void printButtonSelected() {
+ PrintDialog printer = new PrintDialog(getShell());
+ if (fAllPages.getSelection()) {
+ printer.setScope(PrinterData.ALL_PAGES);
+ }
+ if (fCurrentPage.getSelection()) {
+ printer.setScope(PrinterData.SELECTION);
+ }
+ if (fPageList.getSelection()) {
+ printer.setScope(PrinterData.SELECTION);
+ }
+ if (fPageRange.getSelection()) {
+ printer.setScope(PrinterData.PAGE_RANGE);
+ fFrom = Integer.valueOf(fFromPage.getText()).intValue();
+ fTo = Integer.valueOf(fToPage.getText()).intValue();
+ printer.setStartPage(fFrom);
+ printer.setEndPage(fTo);
+ }
+
+ PrinterData newPrinterData = printer.open();
+ if (newPrinterData != null) {
+ fPrinterData = newPrinterData;
+ }
+ updatePrinterStatus();
+
+ if (printer.getScope() == PrinterData.ALL_PAGES) {
+ fAllPages.setSelection(true);
+ fCurrentPage.setSelection(false);
+ fPageList.setSelection(false);
+ fPageRange.setSelection(false);
+ fHorPagesNum.setEnabled(false);
+ fVertPagesNum.setEnabled(false);
+ }
+ if (printer.getScope() == PrinterData.PAGE_RANGE) {
+ fAllPages.setSelection(false);
+ fCurrentPage.setSelection(false);
+ fPageList.setSelection(false);
+ fPageRange.setSelection(true);
+ fFromPage.setEnabled(true);
+ fToPage.setEnabled(true);
+ fFromPage.setText((Integer.valueOf(printer.getStartPage())).toString());
+ fToPage.setText((Integer.valueOf(printer.getEndPage())).toString());
+ }
+ computeStepXY();
+ fOverviewCanvas.redraw();
+ }
+
+ /**
+ * Sets parent wizard page
+ *
+ * @param parent The parent wizard page
+ */
+ public void setParentWizardPage(WizardPage parent) {
+ fParentWizardPage = parent;
+ }
+
+ /**
+ * Sets the parent dialog box.
+ *
+ * @param parent The parent dialog box.
+ */
+ public void setParentDialog(SDPrintDialog parent) {
+ fParentDialog = parent;
+ }
+
+ /**
+ * Updates the printer status
+ */
+ protected void updatePrinterStatus() {
+ if (fParentWizardPage != null) {
+ // used in the wizard dialog
+ if (fPrinterData == null) {
+ // show error message and disable Finish button
+ fParentWizardPage.setErrorMessage(Messages.SequenceDiagram_NoPrinterSelected);
+ fParentWizardPage.setPageComplete(false);
+ } else {
+ // clear error message and enable Finish button
+ fParentWizardPage.setErrorMessage(null);
+ fParentWizardPage.setPageComplete(true);
+ }
+ } else if (fParentDialog != null) {
+ // used in the print dialog
+ if (fPrinterData == null) {
+ // show error message and disable OK button
+ fParentDialog.setErrorMessage(Messages.SequenceDiagram_NoPrinterSelected);
+ fParentDialog.setPageComplete(false);
+ } else {
+ // clear error message and enable OK button
+ fParentDialog.setErrorMessage(null);
+ fParentDialog.setPageComplete(true);
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SearchFilterDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SearchFilterDialog.java
new file mode 100755
index 0000000000..3a283402e6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/SearchFilterDialog.java
@@ -0,0 +1,451 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.DialogSettings;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessageReturn;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Stop;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessageReturn;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFindProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDGraphNodeSupporter;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * This is the common dialog to define Find and/or Filter Criteria(s)
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class SearchFilterDialog extends Dialog {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The find criteria property name
+ */
+ protected static final String FIND_CRITERIA = "findCriteria"; //$NON-NLS-1$
+ /**
+ * The find expression list property name
+ */
+ protected static final String FIND_EXPRESSION_LIST = "findExpressionList"; //$NON-NLS-1$
+ /**
+ * The filter criteria poperty name
+ */
+ protected static final String FILTER_CRITERIA = "filterCriteria"; //$NON-NLS-1$
+ /**
+ * The filter expression list property name
+ */
+ protected static final String FILTER_EXPRESSION_LIST = "filterExpressionList"; //$NON-NLS-1$
+ /**
+ * The maximum number of expressions stored.
+ */
+ protected static final int MAX_EXPRESSION_LIST = 7;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The sequence diagram view reference.
+ */
+ private final SDView fSdView;
+
+ /**
+ * The tab with the controls for a Criteria
+ */
+ private final TabFolder fTabFolder = null;
+
+ /**
+ * The Criteria updated by this dialog
+ */
+ private Criteria fCriteria = null;
+
+ /**
+ * The find/filter provider telling which graph nodes are supported
+ */
+ private final ISDGraphNodeSupporter fProvider;
+
+ /**
+ * The okText is the text for the Ok button and title is the title of the
+ * dialog.<br>
+ * Both depend (okText and title (below)) on the usage that is done of this
+ * dialog (find or filter).
+ */
+ private String fOkText;
+
+ /**
+ * The title is the title of the dialog.<br>
+ * Both depend (okText and title) on the usage that is done of this dialog
+ * (find or filter).
+ */
+ private String fTitle;
+
+ /**
+ * List of string expressions that have been searched already
+ */
+ private String[] fExpressionList;
+
+ /**
+ * find is true if the dialog is for the find feature and false for filter
+ * feature
+ */
+ private boolean fIsFind;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Standard constructor
+ *
+ * @param view
+ * A sequence diagram view reference
+ * @param provider
+ * A graph node supporter provider
+ * @param filter
+ * A flag to indicate filtering (true) or finding (false)
+ * @param style
+ * Style bits
+ */
+ public SearchFilterDialog(SDView view, ISDGraphNodeSupporter provider, boolean filter, int style) {
+ super(view.getSDWidget().getShell());
+ setShellStyle(SWT.DIALOG_TRIM | style);
+ fProvider = provider;
+ fSdView = view;
+ fIsFind = !filter;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public Control createDialogArea(Composite arg0) {
+ if (fIsFind) {
+ fExpressionList = Activator.getDefault().getDialogSettings().getArray(FIND_EXPRESSION_LIST);
+ } else {
+ fExpressionList = Activator.getDefault().getDialogSettings().getArray(FILTER_EXPRESSION_LIST);
+ }
+ if (fExpressionList == null) {
+ fExpressionList = new String[0];
+ }
+ return new TabContents(arg0, fProvider, getButton(IDialogConstants.OK_ID), fExpressionList);
+ }
+
+ /**
+ * Open the dialog box
+ */
+ @Override
+ public int open() {
+ create();
+
+ if (fCriteria == null) {
+ loadCriteria();
+ }
+
+ if (fCriteria == null) {
+ fCriteria = new Criteria();
+ fCriteria.setLifeLineSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.LIFELINE));
+ fCriteria.setSyncMessageSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGE));
+ fCriteria.setSyncMessageReturnSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGERETURN));
+ fCriteria.setAsyncMessageSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGE));
+ fCriteria.setAsyncMessageReturnSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGERETURN));
+ fCriteria.setStopSelected(fProvider.isNodeSupported(ISDGraphNodeSupporter.STOP));
+ }
+ copyFromCriteria(fCriteria);
+
+ if (fOkText != null) {
+ getButton(IDialogConstants.OK_ID).setText(fOkText);
+ } else {
+ getButton(IDialogConstants.OK_ID).setText(Messages.SequenceDiagram_Find);
+ }
+
+ if (fIsFind) {
+ getButton(IDialogConstants.CANCEL_ID).setText(Messages.SequenceDiagram_Close);
+ }
+
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ ((TabContents) getDialogArea()).setOkButton(okButton);
+ if (fCriteria == null || !((fCriteria.getExpression() != null && !fCriteria.getExpression().equals("")) && //$NON-NLS-1$
+ (fCriteria.isAsyncMessageReturnSelected() || fCriteria.isAsyncMessageSelected() || fCriteria.isLifeLineSelected() || fCriteria.isStopSelected() || fCriteria.isSyncMessageReturnSelected() || fCriteria.isSyncMessageSelected()))) {
+ okButton.setEnabled(false);
+ }
+
+ if (fTitle != null) {
+ getShell().setText(fTitle);
+ } else {
+ getShell().setText(Messages.SequenceDiagram_SequenceDiagramFind);
+ }
+
+ getShell().pack();
+ getShell().setLocation(getShell().getDisplay().getCursorLocation());
+
+ fCriteria = null;
+ return super.open();
+ }
+
+ /**
+ * Loads criteria from the dialog settings which are saved in the workspace.
+ */
+ protected void loadCriteria() {
+
+ String CRITERIA = FIND_CRITERIA;
+ if (!fIsFind) {
+ CRITERIA = FILTER_CRITERIA;
+ }
+
+ DialogSettings section = (DialogSettings) Activator.getDefault().getDialogSettings().getSection(CRITERIA);
+ List<GraphNode> selection = fSdView.getSDWidget().getSelection();
+ if ((selection == null || selection.size() != 1) || (!fIsFind)) {
+ if (section != null) {
+ fCriteria = new Criteria();
+ fCriteria.load(section);
+ }
+ } else {
+ GraphNode gn = selection.get(0);
+ fCriteria = new Criteria();
+ fCriteria.setExpression(gn.getName());
+ fCriteria.setCaseSenstiveSelected(true);
+ if (gn instanceof Lifeline && fProvider.isNodeSupported(ISDGraphNodeSupporter.LIFELINE)) {
+ fCriteria.setLifeLineSelected(true);
+ } else if (gn instanceof SyncMessageReturn && fProvider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGERETURN)) {
+ fCriteria.setSyncMessageReturnSelected(true);
+ } else if ((gn instanceof SyncMessageReturn || gn instanceof SyncMessage) && fProvider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGE)) {
+ fCriteria.setSyncMessageSelected(true);
+ } else if (gn instanceof AsyncMessageReturn && fProvider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGERETURN)) {
+ fCriteria.setAsyncMessageReturnSelected(true);
+ } else if ((gn instanceof AsyncMessageReturn || gn instanceof AsyncMessage) && fProvider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGE)) {
+ fCriteria.setAsyncMessageSelected(true);
+ } else if (gn instanceof Stop && fProvider.isNodeSupported(ISDGraphNodeSupporter.STOP)) {
+ fCriteria.setStopSelected(true);
+ }
+ }
+ }
+
+ /**
+ * Called when the dialog box ok button is pressed and calls back the
+ * appropriate action provider (ISDFilterProvider or ISDFindProvider).
+ */
+ @Override
+ public void okPressed() {
+ copyToCriteria();
+ if (!fIsFind) {
+ saveCriteria();
+ super.close(); // Filter is modal
+ }
+ if ((fProvider != null) && (fProvider instanceof ISDFindProvider) && fIsFind) {
+ boolean result = ((ISDFindProvider) fProvider).find(fCriteria);
+ TabContents content = getTabContents();
+ content.setResult(result);
+ }
+ }
+
+ @Override
+ public void cancelPressed() {
+ if (fIsFind) {
+ copyToCriteria();
+ if (fProvider instanceof ISDFindProvider) {
+ ((ISDFindProvider) fProvider).cancel();
+ }
+ saveCriteria();
+ }
+ super.cancelPressed();
+ }
+
+ /**
+ * Saves the criteria to the dialog settings within the workspace.
+ */
+ public void saveCriteria() {
+ String CRITERIA = FIND_CRITERIA;
+ String EXPRESSION_LIST = FIND_EXPRESSION_LIST;
+ if (!fIsFind) {
+ CRITERIA = FILTER_CRITERIA;
+ EXPRESSION_LIST = FILTER_EXPRESSION_LIST;
+ }
+ DialogSettings settings = (DialogSettings) Activator.getDefault().getDialogSettings();
+ DialogSettings section = (DialogSettings) settings.getSection(CRITERIA);
+ if (section == null) {
+ section = (DialogSettings) settings.addNewSection(CRITERIA);
+ }
+ fCriteria.save(section);
+
+ if (fCriteria.getExpression().length() > 0) {
+ ArrayList<String> list = new ArrayList<>();
+ for (int i = 0; i < fExpressionList.length; i++) {
+ list.add(fExpressionList[i]);
+ }
+ // Remove the used expression if one from the dropdown list
+ list.remove(fCriteria.getExpression());
+ // Put the new expression at the beginning
+ list.add(0, fCriteria.getExpression());
+ // Fill in the expressionList, truncating to MAX_EXPRESSION_LIST
+ int size = Math.min(list.size(), MAX_EXPRESSION_LIST);
+ String[] temp = new String[size];
+ for (int i = 0; i < size; i++) {
+ temp[i] = list.get(i);
+ }
+ fExpressionList = temp;
+ settings.put(EXPRESSION_LIST, fExpressionList);
+ }
+ }
+
+ /**
+ * Returns the criteria
+ *
+ * @return the criteria
+ */
+ public Criteria getCriteria() {
+ return fCriteria;
+ }
+
+ /**
+ * Sets the criteria.
+ *
+ * @param criteria
+ * the criteria to set.
+ */
+ public void setCriteria(Criteria criteria) {
+ fCriteria = criteria;
+ }
+
+ /**
+ * Get the current end-user settings from the dialog to a Criteria
+ */
+ public void copyToCriteria() {
+ fCriteria = new Criteria();
+ TabContents content = getTabContents();
+ fCriteria.setLifeLineSelected(content.isLifelineButtonSelected());
+ fCriteria.setSyncMessageSelected(content.isSynMessageButtonSelected());
+ fCriteria.setSyncMessageReturnSelected(content.isSynMessageReturnButtonSelected());
+ fCriteria.setAsyncMessageSelected(content.isAsynMessageButtonSelected());
+ fCriteria.setAsyncMessageReturnSelected(content.isAsynMessageReturnButtonSelected());
+ fCriteria.setStopSelected(content.isStopButtonSelected());
+ fCriteria.setCaseSenstiveSelected(content.isCaseSensitiveSelected());
+ fCriteria.setExpression(content.getSearchText());
+ }
+
+ /**
+ * Returns the tab content reference.
+ *
+ * @return the tab content
+ */
+ protected TabContents getTabContents() {
+ TabContents content = null;
+ if (fTabFolder == null) {
+ content = (TabContents) getDialogArea();
+ } else {
+ content = (TabContents) fTabFolder.getSelection()[0].getControl();
+ }
+ return content;
+ }
+
+ /**
+ * Initialize the dialog with the settings of an existing Criteria<br>
+ * Criteria must not be null and the TabContents must have been created
+ *
+ * @param from
+ * the criteria to copy from
+ */
+ public void copyFromCriteria(Criteria from) {
+ TabContents content = getTabContents();
+ content.setLifelineButtonSelection(from.isLifeLineSelected());
+ content.setSynMessageButtonSelection(from.isSyncMessageSelected());
+ content.setSynMessageReturnButtonSelection(from.isSyncMessageReturnSelected());
+ content.setAsynMessageButtonSelection(from.isAsyncMessageSelected());
+ content.setAsynMessageReturnButtonSelection(from.isSyncMessageReturnSelected());
+ content.setStopButtonSelection(from.isStopSelected());
+ content.setCaseSensitiveSelection(from.isCaseSenstiveSelected());
+ if (from.getExpression() != null) {
+ content.setSearchText(from.getExpression());
+ }
+ }
+
+ /**
+ * Sets the text to be used for the ok button
+ *
+ * @param okText
+ * text to set
+ */
+ public void setOkText(String okText) {
+ fOkText = okText;
+ }
+
+ /**
+ * Sets the title to be used for the dialog box.
+ *
+ * @param title
+ * The title to set
+ */
+ public void setTitle(String title) {
+ fTitle = title;
+ }
+
+ /**
+ * Gets the text to be used for the ok button
+ *
+ * @return the text to be used for the ok button
+ * @since 2.0
+ */
+ public String getOkText() {
+ return fOkText;
+ }
+
+ /**
+ * Sets the IsFind flag (true for find, else for filter)
+ *
+ * @param flag value to set
+ * @since 2.0
+ */
+ protected void setIsFind(boolean flag) {
+ fIsFind = flag;
+ }
+
+ /**
+ * Gets the title to be used for the dialog box.
+ *
+ * @return the title to be used for the dialog box.
+ * @since 2.0
+ */
+ public String getTitle() {
+ return fTitle;
+ }
+
+ /**
+ * Gets the IsFind flag (true for find, else for filter)
+ *
+ * @return true for find, else for filter
+ * @since 2.0
+ */
+ protected boolean isFind() {
+ return fIsFind;
+ }
+
+
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/TabContents.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/TabContents.java
new file mode 100755
index 0000000000..3b5f98b090
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/dialogs/TabContents.java
@@ -0,0 +1,476 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDGraphNodeSupporter;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Class implementation contains the controls that allows to create or update a find or filter Criteria.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class TabContents extends Composite {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The button for lifelines.
+ */
+ private Button fLifelineButton;
+ /**
+ * The button for stops.
+ */
+ private Button fStopButton = null;
+ /**
+ * The button for synchronous messages
+ */
+ private Button fSynMessageButton = null;
+ /**
+ * The button for synchronous return messages
+ */
+ private Button fSynMessageReturnButton = null;
+ /**
+ * The button for asynchronous messages
+ */
+ private Button fAsynMessageButton = null;
+ /**
+ * The button for asynchronous return messages
+ */
+ private Button fAsynMessageReturnButton = null;
+ /**
+ * The search text combo box.
+ */
+ private Combo fSearchText = null;
+ /**
+ * The button for case sensitive expressions.
+ */
+ private Button fCaseSensitive = null;
+ /**
+ * The label for the result string.
+ */
+ private Label fResult = null;
+ /**
+ * The button for notifying parent about valid data.
+ */
+ private Button fParentOkButton = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Creates the dialog contents
+ *
+ * @param parent the parent widget
+ * @param provider the provider which handle the action
+ * @param okButton of the dialog (to be enabled/disabled)
+ * @param expressionList list of strings already searched for
+ */
+ public TabContents(Composite parent, ISDGraphNodeSupporter provider, Button okButton, String[] expressionList) {
+ super(parent, SWT.NONE);
+ fParentOkButton = okButton;
+ setLayout(new GridLayout());
+
+ GraphNodeTypeListener graphNodeTypeListener = new GraphNodeTypeListener();
+ ExpressionListener expressionListener = new ExpressionListener();
+
+ // Inform the user how to fill the string to search
+ Label searchTitle = new Label(this, SWT.LEFT);
+ searchTitle.setText(Messages.SequenceDiagram_MatchingString);
+ Composite searchPart = new Composite(this, SWT.NONE);
+ GridData searchPartData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
+ GridLayout searchPartLayout = new GridLayout();
+ searchPartLayout.numColumns = 2;
+ searchPart.setLayout(searchPartLayout);
+ searchPart.setLayoutData(searchPartData);
+
+ // Create the user string input area
+ fSearchText = new Combo(searchPart, SWT.DROP_DOWN);
+ GridData comboData = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ /*
+ * GridData tabLayoutData2 = new GridData(GridData.HORIZONTAL_ALIGN_FILL| GridData.VERTICAL_ALIGN_FILL);
+ */
+ fSearchText.setLayoutData(comboData);
+ if (expressionList != null) {
+ for (int i = 0; i < expressionList.length; i++) {
+ fSearchText.add(expressionList[i]);
+ }
+ }
+ fSearchText.addModifyListener(expressionListener);
+
+ // Create the case sensitive check button
+ fCaseSensitive = new Button(searchPart, SWT.CHECK);
+ fCaseSensitive.setText(Messages.SequenceDiagram_CaseSensitive);
+
+ // Create the group for searched graph node kind selection
+ Group kindSelection = new Group(this, SWT.SHADOW_NONE);
+ kindSelection.setText(Messages.SequenceDiagram_SearchFor);
+ // kindSelection.setLayoutData(tabLayoutData2);
+ GridLayout kindSelectionLayout = new GridLayout();
+ kindSelectionLayout.numColumns = 1;
+ kindSelection.setLayout(kindSelectionLayout);
+ GridData kindSelectionData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
+ kindSelection.setLayoutData(kindSelectionData);
+
+ // Create the lifeline check button
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.LIFELINE)) {
+ fLifelineButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.LIFELINE, null);
+ if (nodeName != null) {
+ fLifelineButton.setText(nodeName);
+ } else {
+ fLifelineButton.setText(Messages.SequenceDiagram_Lifeline);
+ }
+ fLifelineButton.setEnabled(true);
+ fLifelineButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.STOP)) {
+ // Create the stop check button
+ fStopButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.STOP, null);
+ if (nodeName != null) {
+ fStopButton.setText(nodeName);
+ } else {
+ fStopButton.setText(Messages.SequenceDiagram_Stop);
+ }
+
+ fStopButton.setEnabled(true);
+ fStopButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGE)) {
+ // Create the synchronous message check button
+ fSynMessageButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.SYNCMESSAGE, null);
+ if (nodeName != null) {
+ fSynMessageButton.setText(nodeName);
+ } else {
+ fSynMessageButton.setText(Messages.SequenceDiagram_SynchronousMessage);
+ }
+ fSynMessageButton.setEnabled(true);
+ fSynMessageButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.SYNCMESSAGERETURN)) {
+ // Create the synchronous message return check button
+ fSynMessageReturnButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.SYNCMESSAGERETURN, null);
+ if (nodeName != null) {
+ fSynMessageReturnButton.setText(nodeName);
+ } else {
+ fSynMessageReturnButton.setText(Messages.SequenceDiagram_SynchronousMessageReturn);
+ }
+ fSynMessageReturnButton.setEnabled(true);
+ fSynMessageReturnButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGE)) {
+ // Create the asynchronous message check button
+ fAsynMessageButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.ASYNCMESSAGE, null);
+ if (nodeName != null) {
+ fAsynMessageButton.setText(nodeName);
+ } else {
+ fAsynMessageButton.setText(Messages.SequenceDiagram_AsynchronousMessage);
+ }
+ fAsynMessageButton.setEnabled(true);
+ fAsynMessageButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ if (provider != null && provider.isNodeSupported(ISDGraphNodeSupporter.ASYNCMESSAGERETURN)) {
+ // Create the asynchronous message return check button
+ fAsynMessageReturnButton = new Button(kindSelection, SWT.CHECK);
+ String nodeName = provider.getNodeName(ISDGraphNodeSupporter.ASYNCMESSAGERETURN, null);
+ if (nodeName != null) {
+ fAsynMessageReturnButton.setText(nodeName);
+ } else {
+ fAsynMessageReturnButton.setText(Messages.SequenceDiagram_AsynchronousMessageReturn);
+ }
+ fAsynMessageReturnButton.setEnabled(true);
+ fAsynMessageReturnButton.addSelectionListener(graphNodeTypeListener);
+ }
+
+ fResult = new Label(this, SWT.LEFT);
+ fResult.setText(Messages.SequenceDiagram_StringNotFound);
+ fResult.setVisible(false);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Set result text visibility
+ * @param found <code>true</code> for found (enable visibility) else false
+ */
+ public void setResult(boolean found) {
+ fResult.setVisible(!found);
+ }
+
+ /**
+ * Updates parent OK button based on input data.
+ */
+ public void updateOkButton() {
+ if (fParentOkButton == null) {
+ return;
+ }
+ boolean enabled = (fSearchText.getText() != null && !fSearchText.getText().equals("")) && //$NON-NLS-1$
+ (isLifelineButtonSelected() || isStopButtonSelected() || isSynMessageButtonSelected() || isSynMessageReturnButtonSelected() || isAsynMessageButtonSelected() || isAsynMessageReturnButtonSelected());
+ fParentOkButton.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the parent OK button reference.
+ *
+ * @param okButton The parent OK button
+ */
+ public void setOkButton(Button okButton) {
+ fParentOkButton = okButton;
+ }
+
+ /**
+ * Returns the asynchronous message check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isAsynMessageButtonSelected() {
+ if (fAsynMessageButton != null) {
+ return fAsynMessageButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the asynchronous message return check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isAsynMessageReturnButtonSelected() {
+ if (fAsynMessageReturnButton != null) {
+ return fAsynMessageReturnButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the case sensitive check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isCaseSensitiveSelected() {
+ if (fCaseSensitive != null) {
+ return fCaseSensitive.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the lifeline check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isLifelineButtonSelected() {
+ if (fLifelineButton != null) {
+ return fLifelineButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the user input string
+ *
+ * @return the string to search for
+ */
+ public String getSearchText() {
+ return fSearchText.getText();
+ }
+
+ /**
+ * Returns the stop check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isStopButtonSelected() {
+ if (fStopButton != null) {
+ return fStopButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the synchronous message check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isSynMessageButtonSelected() {
+ if (fSynMessageButton != null) {
+ return fSynMessageButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the synchronous message return check button state
+ *
+ * @return true if check, false otherwise
+ */
+ public boolean isSynMessageReturnButtonSelected() {
+ if (fSynMessageReturnButton != null) {
+ return fSynMessageReturnButton.getSelection();
+ }
+ return false;
+ }
+
+ /**
+ * Set the asynchronous message check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setAsynMessageButtonSelection(boolean state) {
+ if (fAsynMessageButton != null) {
+ fAsynMessageButton.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the asynchronous message return check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setAsynMessageReturnButtonSelection(boolean state) {
+ if (fAsynMessageReturnButton != null) {
+ fAsynMessageReturnButton.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the case sensitive check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setCaseSensitiveSelection(boolean state) {
+ if (fCaseSensitive != null) {
+ fCaseSensitive.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the lifeline check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setLifelineButtonSelection(boolean state) {
+ if (fLifelineButton != null) {
+ fLifelineButton.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the user input string
+ *
+ * @param text
+ * The search text
+ */
+ public void setSearchText(String text) {
+ fSearchText.setText(text);
+ }
+
+ /**
+ * Set the stop check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setStopButtonSelection(boolean state) {
+ if (fStopButton != null) {
+ fStopButton.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the synchronous message check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setSynMessageButtonSelection(boolean state) {
+ if (fSynMessageButton != null) {
+ fSynMessageButton.setSelection(state);
+ }
+ }
+
+ /**
+ * Set the synchronous message return check button state
+ *
+ * @param state
+ * The new state to set
+ */
+ public void setSynMessageReturnButtonSelection(boolean state) {
+ if (fSynMessageReturnButton != null) {
+ fSynMessageReturnButton.setSelection(state);
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Helper classes
+ // ------------------------------------------------------------------------
+
+ /**
+ * Selection listener implementation for graph node types.
+ * @version 1.0
+ */
+ protected class GraphNodeTypeListener implements SelectionListener {
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // Nothing to do
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateOkButton();
+ }
+ }
+
+ /**
+ * Modify listener implementation for the expression field.
+ *
+ * @version 1.0
+ */
+ protected class ExpressionListener implements ModifyListener {
+ @Override
+ public void modifyText(ModifyEvent e) {
+ updateOkButton();
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IColor.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IColor.java
new file mode 100755
index 0000000000..2b5e2e1bf7
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IColor.java
@@ -0,0 +1,36 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings;
+
+/**
+ * Interface for handling a color resource.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface IColor {
+
+ /**
+ * Returns the contained color. Returned object must be an instance of org.eclipse.swt.graphics.Color if used with
+ * the org.eclipse.linuxtools.tmf.ui.views.uml2sd.NGC graphical context
+ *
+ * @return the color
+ */
+ Object getColor();
+
+ /**
+ * Disposes the color
+ */
+ void dispose();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IFont.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IFont.java
new file mode 100755
index 0000000000..c2196e06af
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IFont.java
@@ -0,0 +1,36 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings;
+
+/**
+ * Interface for handling a font resource.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface IFont {
+
+ /**
+ * Returns the contained font. Returned object must be an instance of org.eclipse.swt.graphics.Font if used with the
+ * org.eclipse.linuxtools.tmf.ui.views.uml2sd.NGC graphical context
+ *
+ * @return the font
+ */
+ Object getFont();
+
+ /**
+ * Disposes the font
+ */
+ void dispose();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IGC.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IGC.java
new file mode 100755
index 0000000000..c26bb5ceed
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IGC.java
@@ -0,0 +1,375 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings;
+
+/**
+ * Interface for a graphical context.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface IGC {
+
+ /**
+ * Set the current line style
+ *
+ * @param style the new line style
+ */
+ void setLineStyle(int style);
+
+ /**
+ * Returns current the line style used in the graphical context
+ *
+ * @return the current line style
+ */
+ int getLineStyle();
+
+ /**
+ * Returns the contents x coordinate that is at the upper left corner of the view
+ *
+ * @return the contents x coordinate
+ */
+ int getContentsX();
+
+ /**
+ * Returns the contents y coordinate that is at the upper left corner of the view
+ *
+ * @return the contents y coordinate
+ */
+ int getContentsY();
+
+ /**
+ * Returns the contents visible width
+ *
+ * @return the contents width
+ */
+ int getVisibleWidth();
+
+ /**
+ * Returns the contents visible height
+ *
+ * @return the contents height
+ */
+ int getVisibleHeight();
+
+ /**
+ * Translates the given contents x coordinate into view x coordinate
+ *
+ * @param x the x coordinate to translate
+ * @return the corresponding view x coordinate
+ */
+ int contentsToViewX(int x);
+
+ /**
+ * Translates the given contents y coordinate into view y coordinate
+ *
+ * @param y the y coordinate to translate
+ * @return the corresponding view y coordinate
+ */
+ int contentsToViewY(int y);
+
+ /**
+ * Draws a line, using the foreground color, between the points (x1, y1) and (x2, y2).
+ *
+ * @param x1 the first point's x coordinate
+ * @param y1 the first point's y coordinate
+ * @param x2 the second point's x coordinate
+ * @param y2 the second point's y coordinate
+ */
+ void drawLine(int x1, int y1, int x2, int y2);
+
+ /**
+ * Draws the outline of the rectangle specified by the arguments, using the receiver's foreground color. The left
+ * and right edges of the rectangle are at x and x + width. The top and bottom edges are at y and y + height.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ */
+ void drawRectangle(int x, int y, int width, int height);
+
+ /**
+ * Draws a rectangle, based on the specified arguments, which has the appearance of the platform's focus rectangle
+ * if the platform supports such a notion, and otherwise draws a simple rectangle in the receiver's foreground
+ * color.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ */
+ void drawFocus(int x, int y, int width, int height);
+
+ /**
+ * Fills the interior of the closed polygon which is defined by the specified array of integer coordinates, using
+ * the receiver's background color. The array contains alternating x and y values which are considered to represent
+ * points which are the vertices of the polygon. Lines are drawn between each consecutive pair, and between the
+ * first pair and last pair in the array.
+ *
+ * @param points an array of alternating x and y values which are the vertices of the polygon
+ */
+ void fillPolygon(int[] points);
+
+ /**
+ * Draws the closed polygon which is defined by the specified array of integer coordinates, using the receiver's
+ * foreground color. The array contains alternating x and y values which are considered to represent points which
+ * are the vertices of the polygon. Lines are drawn between each consecutive pair, and between the first pair and
+ * last pair in the array.
+ *
+ * @param points an array of alternating x and y values which are the vertices of the polygon
+ */
+ void drawPolygon(int[] points);
+
+ /**
+ * Fills the interior of the rectangle specified by the arguments, using the receiver's background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ */
+ void fillRectangle(int x, int y, int width, int height);
+
+ /**
+ * Fills the interior of the specified rectangle with a gradient sweeping from left to right or top to bottom
+ * progressing from the graphical context gradient color to its background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled, may be negative (inverts direction of gradient if
+ * horizontal)
+ * @param height the height of the rectangle to be filled, may be negative (inverts direction of gradient if
+ * horizontal)
+ * @param vertical if true sweeps from top to bottom, else sweeps from left to right
+ */
+ void fillGradientRectangle(int x, int y, int width, int height, boolean vertical);
+
+ /**
+ * Returns the given string width in pixels
+ *
+ * @param name the string
+ * @return the string width
+ */
+ int textExtent(String name);
+
+ /**
+ * Draws the given string, using the receiver's current font and foreground color. Tab expansion and carriage return
+ * processing are performed. If trans is true, then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param trans if true the background will be transparent, otherwise it will be opaque
+ */
+ void drawText(String string, int x, int y, boolean trans);
+
+ /**
+ * Draws the given string, using the receiver's current font and foreground color. Tab expansion and carriage return
+ * processing are performed. The background of the rectangular area where the text is being drawn will be filled
+ * with the receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ */
+ void drawText(String string, int x, int y);
+
+ /**
+ * Fills the interior of an oval, within the specified rectangular area, with the receiver's background color.
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be filled
+ * @param y the y coordinate of the upper left corner of the oval to be filled
+ * @param width the width of the oval to be filled
+ * @param height the width of the oval to be filled
+ */
+ void fillOval(int x, int y, int width, int height);
+
+ /**
+ * Returns current the background color used in the graphical context
+ *
+ * @return the background color
+ */
+ IColor getBackground();
+
+ /**
+ * Returns current the background color used in the graphical context
+ *
+ * @return the background color
+ */
+ IColor getForeground();
+
+ /**
+ * Set the graphical context foreground color
+ *
+ * @param color the foreground color
+ */
+ void setBackground(IColor color);
+
+ /**
+ * Set the graphical context background color
+ *
+ * @param color the background color
+ */
+ void setForeground(IColor color);
+
+ /**
+ * Set the color to use when filling regions using gradient. The color will progess from the given color to the
+ * current background color
+ *
+ * @param color the gardiient color to use
+ */
+ void setGradientColor(IColor color);
+
+ /**
+ * Set the line width to use for drawing
+ *
+ * @param width the line width
+ */
+ void setLineWidth(int width);
+
+ /**
+ * Returns the current graphical context line width used for drawing
+ *
+ * @return the line width
+ */
+ int getLineWidth();
+
+ /**
+ * Returns the LineDotD style constant
+ *
+ * @return the constant value
+ */
+ int getLineDotStyle();
+
+ /**
+ * Returns the LineDash style constant
+ *
+ * @return the constant
+ */
+ int getLineDashStyle();
+
+ /**
+ * Returns the LineSolid style constant
+ *
+ * @return the constant
+ */
+ int getLineSolidStyle();
+
+ /**
+ * Draws the given string centered into the given rectangle. If the string cannot fit in the rectangle area, the
+ * string is truncated. If trans is true, then the background of the rectangular area where the text is being drawn
+ * will not be modified, otherwise it will be filled with the receiver's background color.
+ *
+ * @param name the string to draw
+ * @param x the x coordinate of the rectangle to draw the string
+ * @param y the y coordinate of the rectangle to draw the string
+ * @param width the width of the rectangle to draw the string
+ * @param height the height of the rectangle to draw the string
+ * @param trans if true the background will be transparent, otherwise it will be opaque
+ */
+ void drawTextTruncatedCentred(String name, int x, int y, int width, int height, boolean trans);
+
+ /**
+ * Draws the given string into the given rectangle (left justify) If the string cannot fit in the rectangle area,
+ * the string is truncated. If trans is true, then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the receiver's background color.
+ *
+ * @param name The text to put in the rectangle
+ * @param x the x coordinate of the rectangle to draw the string
+ * @param y the y coordinate of the rectangle to draw the string
+ * @param width the width of the rectangle to draw the string
+ * @param height the height of the rectangle to draw the string
+ * @param trans if true the background will be transparent, otherwise it will be opaque
+ */
+ void drawTextTruncated(String name, int x, int y, int width, int height, boolean trans);
+
+ /**
+ * Copies a the source image into a (potentially different sized) rectangular area in the graphical context. If the
+ * source image has smaller sizes, then the source area will be stretched to fit the destination area as it is
+ * copied.
+ *
+ * @param image the image to draw
+ * @param x the x coordinate in the destination to copy to
+ * @param y the y coordinate in the destination to copy to
+ * @param maxWith the width in pixels of the destination rectangle
+ * @param maxHeight the height in pixels of the destination rectangle
+ */
+ void drawImage(IImage image, int x, int y, int maxWith, int maxHeight);
+
+ /**
+ * Draws the outline of a circular or elliptical arc within the specified rectangular area. The resulting arc begins
+ * at startAngle and extends for arcAngle degrees, using the current color. Angles are interpreted such that 0
+ * degrees is at the 3 o'clock position. A positive value indicates a counter-clockwise rotation while a negative
+ * value indicates a clockwise rotation. The center of the arc is the center of the rectangle whose origin is (x, y)
+ * and whose size is specified by the width and height arguments. The resulting arc covers an area width + 1 pixels
+ * wide by height + 1 pixels tall.
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be drawn
+ * @param y the y coordinate of the upper-left corner of the arc to be drawn
+ * @param width the width of the arc to be drawn
+ * @param height the height of the arc to be drawn
+ * @param startAngle the beginning angle
+ * @param endAngle the ending angle
+ */
+ void drawArc(int x, int y, int width, int height, int startAngle, int endAngle);
+
+ /**
+ * Set the current font used in the graphical context
+ *
+ * @param font the font to use
+ */
+ void setFont(IFont font);
+
+ /**
+ * Returns the font height given font
+ *
+ * @param font The font to check for
+ * @return the the font height
+ */
+ int getFontHeight(IFont font);
+
+ /**
+ * Returns the average character width for the given font
+ *
+ * @param font The font to check for
+ * @return the average width
+ */
+ int getFontWidth(IFont font);
+
+ /**
+ * Creates a color with the given RGB values
+ *
+ * @param r the red component
+ * @param g the green component
+ * @param b the blue component
+ * @return the color
+ */
+ IColor createColor(int r, int g, int b);
+
+ /**
+ * Returns the zoom factor applied in both x and y directions when drawing
+ *
+ * @return the zoom factor
+ */
+ float getZoom();
+
+ /**
+ * Draws text with focus style.
+ *
+ * @param focus <code>true</code> if item has focus else <code>false</code>
+ */
+ void setDrawTextWithFocusStyle(boolean focus);
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IImage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IImage.java
new file mode 100755
index 0000000000..eac7ee28ff
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/IImage.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings;
+
+/**
+ * Interface for handling a image resource.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface IImage {
+
+ /**
+ * Returns the contained image. Returned object must be an instance of org.eclipse.swt.graphics.Image if used with
+ * the org.eclipse.linuxtools.tmf.ui.views.uml2sd.NGC graphical context
+ *
+ * @return the color
+ */
+ Object getImage();
+
+ /**
+ * Disposes the image
+ */
+ void dispose();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ColorImpl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ColorImpl.java
new file mode 100755
index 0000000000..25b5a689ac
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ColorImpl.java
@@ -0,0 +1,92 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+
+/**
+ * Default implementation of the IColor interface.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class ColorImpl implements IColor {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The color object.
+ */
+ private final Color fColor;
+ /**
+ * Flag to indicate that this object is managing the resource.
+ */
+ private boolean fManageColor = true;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor
+ *
+ * @param display The display to use
+ * @param r A value for red
+ * @param g A value for green
+ * @param b A value for blue
+ */
+ public ColorImpl(Display display, int r, int g, int b) {
+ fColor = new Color(display, r, g, b);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param color
+ * A color to copy
+ */
+ protected ColorImpl(Color color) {
+ fColor = color;
+ fManageColor = false;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns a system color.
+ *
+ * @param color The color ID
+ * @return a system color
+ */
+ public static ColorImpl getSystemColor(int color) {
+ return new ColorImpl(Display.getDefault().getSystemColor(color));
+ }
+
+ @Override
+ public Object getColor() {
+ return fColor;
+ }
+
+ @Override
+ public void dispose() {
+ if ((fColor != null) && (fManageColor)) {
+ fColor.dispose();
+ }
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/FontImpl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/FontImpl.java
new file mode 100755
index 0000000000..1b1cbcf890
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/FontImpl.java
@@ -0,0 +1,89 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl;
+
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IFont;
+
+/**
+ * Default implementation of the IFont interface.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class FontImpl implements IFont {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The font object
+ */
+ private final Font fFont;
+ /**
+ * Flag to indicate that this object is managing the resource.
+ */
+ protected boolean fManageFont = true;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor.
+ *
+ * @param display The display to use
+ * @param data A font data
+ */
+ public FontImpl(Display display, FontData data) {
+ fFont = new Font(display, data);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param value A font to copy.
+ */
+ protected FontImpl(Font value) {
+ fFont = value;
+ fManageFont = false;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns a font implementation based system font.
+ *
+ * @return a font implementation based system font.
+ */
+ public static FontImpl getSystemFont() {
+ return new FontImpl(Display.getDefault().getSystemFont());
+ }
+
+ @Override
+ public Object getFont() {
+ return fFont;
+ }
+
+ @Override
+ public void dispose() {
+ if (fFont != null) {
+ fFont.dispose();
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ImageImpl.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ImageImpl.java
new file mode 100755
index 0000000000..5637b88981
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/drawings/impl/ImageImpl.java
@@ -0,0 +1,105 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IImage;
+
+/**
+ * Default implementation of the IImage interface.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class ImageImpl implements IImage {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The image reference
+ */
+ private final Image fImage;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor.
+ *
+ * @param file A file name of image file.
+ */
+ public ImageImpl(String file) {
+ fImage = createResourceImage(file);
+ }
+
+ /**
+ * Copy constructor
+ *
+ * @param image THe image to copy
+ */
+ public ImageImpl(Image image) {
+ fImage = image;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Returns Image object from file name.
+ *
+ * @param name File name of image file
+ * @return image object or <code>null</code>
+ */
+ public Image getResourceImage(String name) {
+ return createResourceImage(name);
+ }
+
+ @Override
+ public Object getImage() {
+ return fImage;
+ }
+
+ @Override
+ public void dispose() {
+ if (fImage != null) {
+ fImage.dispose();
+ }
+ }
+
+ /**
+ * Returns Image object from file name.
+ *
+ * @param name File name of image file
+ * @return image object or <code>null</code>
+ */
+ private static Image createResourceImage(String name) {
+ try {
+ URL BASIC_URL = new URL("platform", "localhost", "plugin");//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ URL url = new URL(BASIC_URL, "plugin/org.eclipse.linuxtools.tmf.ui/icons/" + name);//$NON-NLS-1$
+ ImageDescriptor img = ImageDescriptor.createFromURL(url);
+ return img.createImage();
+ } catch (MalformedURLException e) {
+ Activator.getDefault().logError("Error opening image file", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/BaseSDAction.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/BaseSDAction.java
new file mode 100644
index 0000000000..e45fd20d28
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/BaseSDAction.java
@@ -0,0 +1,89 @@
+/**********************************************************************
+ * Copyright (c) 2013 Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.jface.action.Action;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+
+/**
+ * Base class for sequence diagram actions.
+ *
+ * @author Bernd Hufmann
+ * @since 2.0
+ */
+public class BaseSDAction extends Action {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The sequence diagram view reference.
+ */
+ private SDView fView = null;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public BaseSDAction() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view
+ * a sequence diagram view reference
+ */
+ public BaseSDAction(SDView view) {
+ super();
+ fView = view;
+ }
+
+ /**
+ * Constructor
+ * @param view
+ * a sequence diagram view reference
+ * @param text
+ * The action text
+ * @param style
+ * The style
+ */
+ protected BaseSDAction(SDView view, String text, int style) {
+ super(text, style);
+ fView = view;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Sets the active SD view.
+ *
+ * @param view The SD view.
+ */
+ public void setView(SDView view) {
+ fView = view;
+ }
+
+ /**
+ * Gets the active SD view.
+ *
+ * @return view The SD view.
+ * @since 2.0
+ */
+ public SDView getView() {
+ return fView;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ConfigureMinMax.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ConfigureMinMax.java
new file mode 100755
index 0000000000..21ee20f259
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ConfigureMinMax.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.MinMaxDialog;
+
+/**
+ * Action class implementation to configure minimum and maximum time range values.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class ConfigureMinMax extends BaseSDAction {
+
+ /**
+ * Constructor
+ * @param view
+ * the sequence diagram view reference
+ * @since 2.0
+ */
+ public ConfigureMinMax(SDView view) {
+ super(view);
+ }
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ @Override
+ public void run() {
+ if ((getView() != null) && (getView().getSDWidget() != null)) {
+ MinMaxDialog minMax = new MinMaxDialog(getView().getSite().getShell(), getView().getSDWidget());
+ minMax.open();
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/FirstPage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/FirstPage.java
new file mode 100644
index 0000000000..33476c7dc0
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/FirstPage.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation to move the focus to the first page of the whole sequence diagram.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class FirstPage extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.firstpage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ *
+ * @param view the view reference
+ */
+ public FirstPage(SDView view) {
+ super(view);
+ setText(Messages.SequenceDiagram_FirstPage);
+ setToolTipText(Messages.SequenceDiagram_GoToFirstPage);
+ setId(ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FIRST_PAGE));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if ((getView() == null) || (getView().getSDWidget()) == null) {
+ return;
+ }
+ if (getView().getSDPagingProvider() != null) {
+ getView().getSDPagingProvider().firstPage();
+ }
+ getView().updateCoolBar();
+ getView().getSDWidget().redraw();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/KeyBindingsManager.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/KeyBindingsManager.java
new file mode 100644
index 0000000000..c4e9c8d3ae
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/KeyBindingsManager.java
@@ -0,0 +1,302 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.IHandlerActivation;
+import org.eclipse.ui.handlers.IHandlerService;
+
+/**
+ * <p>
+ * Singleton class that manages key-bindings for certain commands across multiple sequence
+ * diagram view instances.
+ * </p>
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ *
+ */
+public class KeyBindingsManager {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The singleton instance.
+ */
+ private static KeyBindingsManager fInstance = null;
+ /**
+ * The list of view names.
+ */
+ private Set<String> fViews = new HashSet<>();
+ /**
+ * The list of activations Activations to store
+ */
+ private List<IHandlerActivation> fHandlerActivations = new ArrayList<>();
+ /**
+ * The action reference for moving to a message in view.
+ */
+ private MoveToMessage fGoToMessageForKeyBinding;
+ /**
+ * The action reference for opening the find dialog.
+ */
+ private OpenSDFindDialog fFindForKeyBinding;
+ /**
+ * The action reference for moving up in view.
+ */
+ private MoveSDUp fMoveUpForKeyBinding;
+ /**
+ * The action reference for moving down in view.
+ */
+ private MoveSDDown fMoveDownForKeyBinding;
+ /**
+ * The action reference for moving left in view.
+ */
+ private MoveSDLeft fMoveLeftForKeyBinding;
+ /**
+ * The action reference for moving right in view.
+ */
+ private MoveSDRight fMoveRightForKeyBinding;
+ /**
+ * The action reference for showing node start.
+ */
+ private ShowNodeStart fShowNodeStartForKeyBinding;
+ /**
+ * The action reference for showing node end.
+ */
+ private ShowNodeEnd fShowNodeEndForKeyBinding;
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ */
+ protected KeyBindingsManager() {
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ /**
+ * Returns the KeyBindingsManager singleton instance.
+ *
+ * @return the KeyBindingsManager singleton instance
+ */
+ public static synchronized KeyBindingsManager getInstance() {
+ if (fInstance == null) {
+ fInstance = new KeyBindingsManager();
+ }
+ return fInstance;
+ }
+
+ /**
+ * Adds a view list of managed view list.
+ *
+ * @param viewId Id of SD view to add and to manage
+ */
+ public void add(String viewId) {
+
+ if (fViews.isEmpty()) {
+ initialize();
+ }
+
+ if(!fViews.contains(viewId)) {
+ fViews.add(viewId);
+ }
+ }
+
+ /**
+ * Removes a view from managed view list
+ *
+ * @param viewId Id of SD view to remove
+ */
+ public void remove(String viewId) {
+ if (fViews.contains(viewId)) {
+ fViews.remove(viewId);
+ }
+ if (fViews.isEmpty()) {
+ dispose();
+ }
+ }
+
+ /*
+ * Initialized the KeyBindingsManager.
+ */
+ private void initialize() {
+ fGoToMessageForKeyBinding = new MoveToMessage();
+ IHandlerService service = (IHandlerService) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(IHandlerService.class);
+ AbstractHandler handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fGoToMessageForKeyBinding.run();
+ return null;
+ }
+ };
+ IHandlerActivation activation = service.activateHandler(fGoToMessageForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fMoveUpForKeyBinding = new MoveSDUp();
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fMoveUpForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fMoveUpForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fMoveDownForKeyBinding = new MoveSDDown();
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fMoveDownForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fMoveDownForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fMoveLeftForKeyBinding = new MoveSDLeft();
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fMoveLeftForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fMoveLeftForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fMoveRightForKeyBinding = new MoveSDRight();
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fMoveRightForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fMoveRightForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fFindForKeyBinding = new OpenSDFindDialog();
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fFindForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fFindForKeyBinding.getActionDefinitionId(), handler);
+ fFindForKeyBinding.setEnabled(false);
+ fHandlerActivations.add(activation);
+
+ fShowNodeStartForKeyBinding = new ShowNodeStart();
+ fShowNodeStartForKeyBinding.setText(Messages.SequenceDiagram_ShowNodeStart);
+
+ fShowNodeStartForKeyBinding.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeStart");//$NON-NLS-1$
+ fShowNodeStartForKeyBinding.setActionDefinitionId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeStart");//$NON-NLS-1$
+
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fShowNodeStartForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fShowNodeStartForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ fShowNodeEndForKeyBinding = new ShowNodeEnd();
+ fShowNodeEndForKeyBinding.setText(Messages.SequenceDiagram_ShowNodeEnd);
+ fShowNodeEndForKeyBinding.setId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeEnd");//$NON-NLS-1$
+ fShowNodeEndForKeyBinding.setActionDefinitionId("org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ShowNodeEnd");//$NON-NLS-1$
+
+ handler = new AbstractHandler() {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ fShowNodeEndForKeyBinding.run();
+ return null;
+ }
+ };
+ activation = service.activateHandler(fShowNodeEndForKeyBinding.getActionDefinitionId(), handler);
+ fHandlerActivations.add(activation);
+
+ }
+
+ /*
+ * Disposes the KeyBindingsManager
+ */
+ private void dispose() {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (window == null) {
+ //During Eclipse shutdown the active workbench window is null
+ return;
+ }
+ IHandlerService service = (IHandlerService) window.getService(IHandlerService.class);
+ for(IHandlerActivation activation : fHandlerActivations) {
+ service.deactivateHandler(activation);
+ }
+
+ fGoToMessageForKeyBinding = null;
+ fFindForKeyBinding = null;
+ fMoveUpForKeyBinding = null;
+ fMoveDownForKeyBinding = null;
+ fMoveLeftForKeyBinding = null;
+ fMoveRightForKeyBinding = null;
+ fShowNodeStartForKeyBinding = null;
+ fShowNodeEndForKeyBinding = null;
+ }
+
+ /**
+ * Set the view in all supported actions
+ *
+ * @param view to set in global actions
+ */
+ public void setSdView(SDView view) {
+ if (!fViews.isEmpty()) {
+ fGoToMessageForKeyBinding.setView(view);
+ fFindForKeyBinding.setView(view);
+ fMoveUpForKeyBinding.setView(view);
+ fMoveDownForKeyBinding.setView(view);
+ fMoveLeftForKeyBinding.setView(view);
+ fMoveRightForKeyBinding.setView(view);
+ fShowNodeStartForKeyBinding.setView(view);
+ fShowNodeEndForKeyBinding.setView(view);
+ }
+ }
+
+ /**
+ * Enable / disable find action
+ *
+ * @param enabled <code>true</code> for enabling else <code>false</code>
+ */
+ public void setFindEnabled(boolean enabled) {
+ if (fFindForKeyBinding != null) {
+ fFindForKeyBinding.setEnabled(enabled);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/LastPage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/LastPage.java
new file mode 100644
index 0000000000..4dacc9f7ff
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/LastPage.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation to move the focus to the last page of the whole sequence diagram.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class LastPage extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.lastpage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param view the view reference
+ */
+ public LastPage(SDView view) {
+ super(view);
+ setText(Messages.SequenceDiagram_LastPage);
+ setToolTipText(Messages.SequenceDiagram_GoToLastPage);
+ setId(ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_LAST_PAGE));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if ((getView() == null) || (getView().getSDWidget()) == null) {
+ return;
+ }
+ if (getView().getSDPagingProvider() != null) {
+ getView().getSDPagingProvider().lastPage();
+ }
+ getView().updateCoolBar();
+ getView().getSDWidget().redraw();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDDown.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDDown.java
new file mode 100755
index 0000000000..44f965d3ce
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDDown.java
@@ -0,0 +1,70 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+
+/**
+ * Action class implementation to move down in the sequence diagram view within a page.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class MoveSDDown extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.MoveSDDown"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public MoveSDDown() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view a sequence diagram view reference
+ */
+ public MoveSDDown(SDView view) {
+ super(view);
+ setId(ID);
+ setActionDefinitionId(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget viewer = getView().getSDWidget();
+ if (viewer != null) {
+ viewer.scrollBy(0, +viewer.getVisibleHeight());
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDLeft.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDLeft.java
new file mode 100755
index 0000000000..1ce3220436
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDLeft.java
@@ -0,0 +1,72 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+
+/**
+ * Action class implementation to move left in the sequence diagram view within a page.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class MoveSDLeft extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.MoveSDLeft"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public MoveSDLeft(){
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view a sequence diagram view reference
+ */
+ public MoveSDLeft(SDView view) {
+ super(view);
+ setId(ID);
+ setActionDefinitionId(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget viewer = getView().getSDWidget();
+ if (viewer != null) {
+ viewer.scrollBy(-viewer.getVisibleWidth(), 0);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDRight.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDRight.java
new file mode 100755
index 0000000000..ce2a3cec7f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDRight.java
@@ -0,0 +1,73 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+
+/**
+ * Action class implementation to move right in the sequence diagram view within a page.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+
+public class MoveSDRight extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.MoveSDRight"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public MoveSDRight() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view a sequence diagram view reference
+ */
+ public MoveSDRight(SDView view) {
+ super(view);
+ setId(ID);
+ setActionDefinitionId(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget viewer = getView().getSDWidget();
+ if (viewer != null) {
+ viewer.scrollBy(+viewer.getVisibleWidth(), 0);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDUp.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDUp.java
new file mode 100755
index 0000000000..f10c1dd16f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveSDUp.java
@@ -0,0 +1,71 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+
+/**
+ * Action class implementation to move up in the sequence diagram view within a
+ * page.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class MoveSDUp extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.MoveSDUp"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public MoveSDUp() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view a sequence diagram view reference
+ */
+ public MoveSDUp(SDView view) {
+ super(view);
+ setId(ID);
+ setActionDefinitionId(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+ SDWidget viewer = getView().getSDWidget();
+
+ if (viewer != null) {
+ viewer.scrollBy(0, -viewer.getVisibleHeight());
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveToMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveToMessage.java
new file mode 100755
index 0000000000..2b8438eea6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/MoveToMessage.java
@@ -0,0 +1,113 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.BaseMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessageReturn;
+
+/**
+ * Action Class implementation to move to selected message
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class MoveToMessage extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.GoToMessage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default Constructor
+ */
+ public MoveToMessage() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view a sequence diagram view reference
+ */
+ public MoveToMessage(SDView view) {
+ super(view);
+ setId(ID);
+ setActionDefinitionId(ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SEARCH_MATCH));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget sdWidget = getView().getSDWidget();
+
+ if (sdWidget == null) {
+ return;
+ }
+
+ ISelectionProvider selProvider = sdWidget.getSelectionProvider();
+ ISelection sel = selProvider.getSelection();
+ Object selectedNode = null;
+ Iterator<Object> it = ((StructuredSelection) sel).iterator();
+ while (it.hasNext()) {
+ Object node = it.next();
+ if (node instanceof BaseMessage) {
+ selectedNode = node;
+ }
+ }
+
+ if (selectedNode == null) {
+ return;
+ }
+
+ if (selectedNode instanceof SyncMessageReturn) {
+ GraphNode node = ((SyncMessageReturn) selectedNode).getMessage();
+ sdWidget.clearSelection();
+ sdWidget.addSelection(node);
+ sdWidget.ensureVisible(node);
+ sdWidget.redraw();
+ } else if (selectedNode instanceof SyncMessage) {
+ GraphNode node = ((SyncMessage) selectedNode).getMessageReturn();
+ sdWidget.clearSelection();
+ sdWidget.addSelection(node);
+ sdWidget.ensureVisible(node);
+ sdWidget.redraw();
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/NextPage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/NextPage.java
new file mode 100755
index 0000000000..2518ab9e5e
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/NextPage.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation to move the focus to the next page of the whole sequence diagram.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class NextPage extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.nextpage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ *
+ * @param view the view reference
+ */
+ public NextPage(SDView view) {
+ super(view);
+ setText(Messages.SequenceDiagram_NextPage);
+ setToolTipText(Messages.SequenceDiagram_GoToNextPage);
+ setId(ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NEXT_PAGE));
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if ((getView() == null) || (getView().getSDWidget()) == null) {
+ return;
+ }
+ if (getView().getSDPagingProvider() != null) {
+ getView().getSDPagingProvider().nextPage();
+ }
+ getView().updateCoolBar();
+ getView().getSDWidget().redraw();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFiltersDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFiltersDialog.java
new file mode 100755
index 0000000000..7afaf6f5cf
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFiltersDialog.java
@@ -0,0 +1,75 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.FilterListDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation for 'Filtering' of messages/lifelines.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class OpenSDFiltersDialog extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.sdFilters"; //$NON-NLS-1$
+
+ /**
+ * The filter provider reference
+ */
+ private final ISDFilterProvider fProvider;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Constructor
+ *
+ * @param view
+ * The view reference
+ * @param provider
+ * The provider
+ */
+ public OpenSDFiltersDialog(SDView view, ISDFilterProvider provider) {
+ super(view);
+ setText(Messages.SequenceDiagram_HidePatterns);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_FILTERS));
+ setId(ID);
+ setToolTipText(Messages.SequenceDiagram_HidePatterns);
+ fProvider = provider;
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+ FilterListDialog dialog = new FilterListDialog(getView(), fProvider);
+ dialog.open();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFindDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFindDialog.java
new file mode 100755
index 0000000000..0bfce393ca
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDFindDialog.java
@@ -0,0 +1,93 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.SearchFilterDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation for 'Finding' of messages/lifelines.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class OpenSDFindDialog extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.sdFind"; //$NON-NLS-1$
+
+ /**
+ * The action definition ID.
+ */
+ public static final String ACTION_DEFINITION_ID = "org.eclipse.ui.edit.findReplace"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public OpenSDFindDialog() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view The view reference
+ */
+ public OpenSDFindDialog(SDView view) {
+ super(view);
+ setText(Messages.SequenceDiagram_Find + "..."); //$NON-NLS-1$
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SEARCH_SEQ));
+ setId(ID);
+ setActionDefinitionId(ACTION_DEFINITION_ID);
+ setToolTipText(Messages.SequenceDiagram_Find + "..."); //$NON-NLS-1$
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+
+ // Disable action while search is ongoing
+ this.setEnabled(false);
+
+ try {
+ if ((getView().getExtendedFindProvider() != null) && (getView().getExtendedFindProvider().getFindAction() != null)) {
+ getView().getExtendedFindProvider().getFindAction().run();
+ } else if (getView().getSDFindProvider() != null) {
+ SearchFilterDialog dialog = new SearchFilterDialog(getView(), getView().getSDFindProvider(), false, SWT.NORMAL);
+ dialog.open();
+ }
+ } finally {
+ // Enable action after finishing the search
+ this.setEnabled(true);
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDPagesDialog.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDPagesDialog.java
new file mode 100755
index 0000000000..e7145f3252
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/OpenSDPagesDialog.java
@@ -0,0 +1,80 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.PagesDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDAdvancedPagingProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation for paging.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class OpenSDPagesDialog extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.sdPaging"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The advanced paging provider reference.
+ */
+ private final ISDAdvancedPagingProvider fProvider;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param view
+ * The view reference
+ * @param provider
+ * The provider
+ */
+ public OpenSDPagesDialog(SDView view, ISDAdvancedPagingProvider provider) {
+ super(view);
+ setText(Messages.SequenceDiagram_Pages);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_GOTO_PAGE));
+ setId(ID);
+ fProvider = provider;
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+ PagesDialog dialog = new PagesDialog(getView(), fProvider);
+ dialog.open();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/PrevPage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/PrevPage.java
new file mode 100755
index 0000000000..741d06f329
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/PrevPage.java
@@ -0,0 +1,70 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * Action class implementation to move the focus to the previous page of the whole sequence diagram.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class PrevPage extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.prevpage"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ *
+ * @param view the view reference
+ */
+ public PrevPage(SDView view) {
+ super(view);
+ setText(Messages.SequenceDiagram_PreviousPage);
+ setToolTipText(Messages.SequenceDiagram_GoToPreviousPage);
+ setId(ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_PREV_PAGE));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if ((getView() == null) || (getView().getSDWidget()) == null) {
+ return;
+ }
+ if (getView().getSDPagingProvider() != null) {
+ getView().getSDPagingProvider().prevPage();
+ }
+ getView().updateCoolBar();
+ getView().getSDWidget().redraw();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Print.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Print.java
new file mode 100755
index 0000000000..433d4d4e03
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Print.java
@@ -0,0 +1,60 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+
+/**
+ * Action class implementation for 'Printing'.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class Print extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * The action ID.
+ */
+ public static final String ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.print"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ *
+ * @param view The view reference
+ */
+ public Print(SDView view) {
+ super(view);
+ setId(ID);
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if ((getView() == null) || getView().getSDWidget() == null){
+ return;
+ }
+
+ getView().getSDWidget().print();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeEnd.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeEnd.java
new file mode 100755
index 0000000000..901bba59c7
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeEnd.java
@@ -0,0 +1,89 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+
+/**
+ * Action class implementation to show end of a graph node.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class ShowNodeEnd extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public ShowNodeEnd() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view The sequence diagram view reference
+ * @since 2.0
+ */
+ public ShowNodeEnd(SDView view) {
+ super(view);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NODE_END));
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget sdWidget = getView().getSDWidget();
+
+ if (sdWidget == null) {
+ return;
+ }
+
+ ISelectionProvider selProvider = sdWidget.getSelectionProvider();
+ ISelection sel = selProvider.getSelection();
+ Object selectedNode = null;
+
+ Iterator<Object> it = ((StructuredSelection) sel).iterator();
+ while (it.hasNext()) {
+ selectedNode = it.next();
+ }
+
+ if (selectedNode != null) {
+ GraphNode node = (GraphNode) selectedNode;
+ if ((node.getX() + node.getWidth()) * sdWidget.getZoomFactor() < sdWidget.getContentsX() + sdWidget.getVisibleWidth() / 2) {
+ sdWidget.ensureVisible(Math.round((node.getX() + node.getWidth()) * sdWidget.getZoomFactor()) - sdWidget.getVisibleWidth() / 2, Math.round((node.getY() + node.getHeight()) * sdWidget.getZoomFactor()));
+ } else {
+ sdWidget.ensureVisible(Math.round((node.getX() + node.getWidth()) * sdWidget.getZoomFactor() + sdWidget.getVisibleWidth() / (float) 2), Math.round((node.getY() + node.getHeight()) * sdWidget.getZoomFactor()));
+ }
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeStart.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeStart.java
new file mode 100755
index 0000000000..7c3ca150b6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/ShowNodeStart.java
@@ -0,0 +1,89 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import java.util.Iterator;
+
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+
+/**
+ * Action class implementation to show end of a graph node.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class ShowNodeStart extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default constructor
+ */
+ public ShowNodeStart() {
+ this(null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param view
+ * The sequence diagram view reference
+ * @since 2.0
+ */
+ public ShowNodeStart(SDView view) {
+ super(view);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_NODE_START));
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+ if (getView() == null) {
+ return;
+ }
+
+ SDWidget sdWidget = getView().getSDWidget();
+
+ if (sdWidget == null) {
+ return;
+ }
+
+ ISelectionProvider selProvider = sdWidget.getSelectionProvider();
+ ISelection sel = selProvider.getSelection();
+ Object selectedNode = null;
+ Iterator<Object> it = ((StructuredSelection) sel).iterator();
+ while (it.hasNext()) {
+ selectedNode = it.next();
+ }
+ if (selectedNode != null) {
+ GraphNode node = (GraphNode) selectedNode;
+ if (node.getX() * sdWidget.getZoomFactor() < sdWidget.getContentsX() + sdWidget.getVisibleWidth() / 2) {
+ sdWidget.ensureVisible(Math.round(node.getX() * sdWidget.getZoomFactor() - sdWidget.getVisibleWidth() / (float) 2), Math.round(node.getY() * sdWidget.getZoomFactor()));
+ } else {
+ sdWidget.ensureVisible(Math.round(node.getX() * sdWidget.getZoomFactor() + sdWidget.getVisibleWidth() / (float) 2), Math.round(node.getY() * sdWidget.getZoomFactor()));
+ }
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Zoom.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Zoom.java
new file mode 100755
index 0000000000..5a7ee0c668
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/Zoom.java
@@ -0,0 +1,239 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers;
+
+import org.eclipse.jface.action.ActionContributionItem;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.action.IContributionItem;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.ITmfImageConstants;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDWidget;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IActionBars;
+
+/**
+ * Action class implementation for zooming in, out or reset of zoom.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class Zoom extends BaseSDAction {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The Action ID for zooming in.
+ */
+ public static final String ZOOM_IN_ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ZoomInCoolBar"; //$NON-NLS-1$
+ /**
+ * The Action ID for zooming out.
+ */
+ public static final String ZOOM_OUT_ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ZoomOutCoolBar"; //$NON-NLS-1$
+ /**
+ * The Action ID for reset zooming.
+ */
+ public static final String RESET_ZOOM_ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.ResetZoom"; //$NON-NLS-1$
+ /**
+ * The Action ID for no zoominf.
+ */
+ public static final String NO_ZOOM_ID = "org.eclipse.linuxtools.tmf.ui.views.uml2sd.handlers.NoZoom"; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * Flag to indicate last zoom in.
+ */
+ private boolean fLastZoomIn = false;
+ /**
+ * Flag to indicate last zoom out.
+ */
+ private boolean fLastZoomOut = false;
+ /**
+ * The cursor used when zooming in.
+ */
+ private final Cursor fZoomInCursor;
+ /**
+ * The cursor used when zooming out.
+ */
+ private final Cursor fZoomOutCursor;
+
+ /**
+ * The different zoom actions
+ */
+ public static enum ZoomType {
+ /** No zoom information */
+ ZOOM_NONE,
+ /** Zoom in */
+ ZOOM_IN,
+ /** Zoom out */
+ ZOOM_OUT,
+ /** Reset to the default zoom level */
+ ZOOM_RESET
+ }
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Constructor
+ * @param view The view reference
+ * @param type The type of zoom.
+ */
+ public Zoom(SDView view, ZoomType type) {
+ super(view, "", AS_RADIO_BUTTON); //$NON-NLS-1$
+
+ // Pre-create zooming cursors
+ fZoomInCursor = new Cursor(Display.getCurrent(),
+ Activator.getDefault().getImageFromImageRegistry(ITmfImageConstants.IMG_UI_ZOOM_IN).getImageData(),
+ Activator.getDefault().getImageFromImageRegistry(ITmfImageConstants.IMG_UI_ZOOM).getImageData(), 0, 0);
+
+ fZoomOutCursor = new Cursor(Display.getCurrent(),
+ Activator.getDefault().getImageFromImageRegistry(ITmfImageConstants.IMG_UI_ZOOM_OUT).getImageData(),
+ Activator.getDefault().getImageFromImageRegistry(ITmfImageConstants.IMG_UI_ZOOM).getImageData(), 0, 0);
+
+ switch (type) {
+ case ZOOM_IN:
+ setText(Messages.SequenceDiagram_ZoomIn);
+ setToolTipText(Messages.SequenceDiagram_ZoomInTheDiagram);
+ setId(ZOOM_IN_ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_IN_MENU));
+ break;
+
+ case ZOOM_OUT:
+ setText(Messages.SequenceDiagram_ZoomOut);
+ setToolTipText(Messages.SequenceDiagram_ZoomOutTheDiagram);
+ setId(ZOOM_OUT_ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_ZOOM_OUT_MENU));
+ break;
+
+ case ZOOM_RESET:
+ setText(Messages.SequenceDiagram_ResetZoomFactor);
+ setToolTipText(Messages.SequenceDiagram_ResetZoomFactor);
+ setId(RESET_ZOOM_ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_HOME_MENU));
+ break;
+
+ case ZOOM_NONE:
+ default:
+ setText(Messages.SequenceDiagram_Select);
+ setToolTipText(Messages.SequenceDiagram_Select);
+ setId(NO_ZOOM_ID);
+ setImageDescriptor(Activator.getDefault().getImageDescripterFromPath(ITmfImageConstants.IMG_UI_SELECT_MENU));
+ break;
+ }
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public void run() {
+
+ if ((getView() == null) || (getView().getSDWidget() == null)) {
+ return;
+ }
+
+ SDWidget viewer = getView().getSDWidget();
+
+ if (getId().equals(ZOOM_OUT_ID)) {
+ // Eclipse 3.0 M7 workaround
+ if (fLastZoomOut == isChecked()) {
+ setChecked(!isChecked());
+ }
+
+ viewer.setZoomOutMode(isChecked());
+ fLastZoomOut = isChecked();
+ if (isChecked()) {
+ viewer.setCursor(fZoomOutCursor);
+ setActionChecked(NO_ZOOM_ID, false);
+ } else {
+ viewer.setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_ARROW));
+ setActionChecked(NO_ZOOM_ID, true);
+ }
+ } else if (getId().equals(ZOOM_IN_ID)) {
+ // Eclipse 3.0 M7 workaround
+ if (fLastZoomIn == isChecked()) {
+ setChecked(!isChecked());
+ }
+
+ viewer.setZoomInMode(isChecked());
+ fLastZoomIn = isChecked();
+ if (isChecked()) {
+ viewer.setCursor(fZoomInCursor);
+ setActionChecked(NO_ZOOM_ID, false);
+ } else {
+ viewer.setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_ARROW));
+ setActionChecked(NO_ZOOM_ID, true);
+ }
+ } else if (getId().equals(RESET_ZOOM_ID)) {
+ viewer.resetZoomFactor();
+
+ // The reset action is a radio button only to uncheck the zoom in and out button
+ // when it is clicked. This avoid adding code to do it manually
+ // We only have to force it to false every time
+ setChecked(false);
+ setActionChecked(NO_ZOOM_ID, true);
+ } else if (getId().equals(NO_ZOOM_ID)) {
+ setChecked(true);
+ viewer.setZoomInMode(false);
+ viewer.setZoomInMode(false);
+ viewer.setCursor(new Cursor(Display.getDefault(), SWT.CURSOR_ARROW));
+ }
+ }
+
+ /**
+ * Set action check state of a view action for a given action ID.
+ *
+ * @param id The action ID
+ * @param checked true to check the action, false to uncheck the action
+ */
+ protected void setActionChecked(String id, boolean checked) {
+ if (getView() != null) {
+ IActionBars bar = getView().getViewSite().getActionBars();
+ if (bar == null) {
+ return;
+ }
+ IToolBarManager barManager = bar.getToolBarManager();
+ if (barManager == null) {
+ return;
+ }
+ IContributionItem nextPage = barManager.find(id);
+ if (nextPage instanceof ActionContributionItem) {
+ IAction action = ((ActionContributionItem) nextPage).getAction();
+ if (action != null) {
+ action.setChecked(checked);
+ }
+ }
+ }
+ }
+
+ /**
+ * Dispose the action and its resources
+ *
+ * @since 3.2
+ */
+ public void dispose() {
+ fZoomInCursor.dispose();
+ fZoomOutCursor.dispose();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFilterProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFilterProvider.java
new file mode 100755
index 0000000000..3e8ee59fa7
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFilterProvider.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.jface.action.Action;
+
+/**
+ * Interface for providing an extended filter provider.
+ *
+ * Sequence Diagram loaders which implement this interface provide the action for filtering the sequence diagram.<br>
+ *
+ * Action provider are associated to a Sequence Diagram view by calling <code>SDView.setExtendedFilterProvider</code><br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface IExtendedFilterProvider {
+
+ /**
+ * Returns a filter action implementation.
+ *
+ * @return a filter action implementation
+ */
+ Action getFilterAction();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFindProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFindProvider.java
new file mode 100755
index 0000000000..aa471c2fa3
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/IExtendedFindProvider.java
@@ -0,0 +1,38 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.jface.action.Action;
+
+/**
+ * Interface for providing an extended find provider.
+ *
+ * Sequence Diagram loaders which implement this interface provide an action for finding in the sequence diagram.
+ *
+ * Action provider are associated to a Sequence Diagram view by calling <code>SDView.setExtendedFindProvider()</code>.<br>
+ *
+ * Note that either provider implementing ISDFindProvider or IExtendedFindProvider can be active in the SDView.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface IExtendedFindProvider {
+
+ /**
+ * Returns an extended find action.
+ *
+ * @return an extended find action
+ */
+ Action getFindAction();
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDAdvancedPagingProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDAdvancedPagingProvider.java
new file mode 100755
index 0000000000..45014914cd
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDAdvancedPagingProvider.java
@@ -0,0 +1,51 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+/**
+ * Interface for providing an extended find provider.
+ *
+ * An advanced paging provider is able to compute number of pages, and to display the number of items it treats on each
+ * page and for total counts.<br>
+ * An item can be a message, a node or anything meaningful from loader standpoint.<br>
+ * Items are only here for information to the user.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ISDAdvancedPagingProvider extends ISDPagingProvider {
+
+ /**
+ * Returns the current page.
+ *
+ * @return the current page the loader is dealing with. <b>Note</b> that first page has the 0 index (indexes are from
+ * 0 to pagesCount()-1).
+ */
+ int currentPage();
+
+ /**
+ * Returns the number of pages.
+ *
+ * @return number of pages the loader is dealing with
+ */
+ int pagesCount();
+
+ /**
+ * Instructs a load of the &lt;pageNumber_&gt;<i>th</i> page.<br>
+ * <b>Note</b> that first page has the index 0 (indexes are from 0 to pagesCount()-1).
+ *
+ * @param pageNumber index of the page to load
+ */
+ void pageNumberChanged(int pageNumber);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDCollapseProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDCollapseProvider.java
new file mode 100755
index 0000000000..29d0fa6c87
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDCollapseProvider.java
@@ -0,0 +1,36 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+
+/**
+ * Interface for providing a collapse provider.
+ *
+ * Sequence diagram loaders which want to support Drag and Drop collapsing in the sequence diagram must implement this
+ * interface and register this implementation using <code>SDView.setCollapsingProvider();</code>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ISDCollapseProvider {
+
+ /**
+ * Called back when the sequence diagram is requesting 2 lifelines collapsing
+ *
+ * @param lifeline1 - One of the lifeline to collapse
+ * @param lifeline2 - The other lifeline to collapse with
+ */
+ void collapseTwoLifelines(Lifeline lifeline1, Lifeline lifeline2);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDExtendedActionBarProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDExtendedActionBarProvider.java
new file mode 100755
index 0000000000..1ebd1aecb6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDExtendedActionBarProvider.java
@@ -0,0 +1,37 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2012 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.ui.IActionBars;
+
+/**
+ * Interface for providing an extended action bar provider.
+ *
+ * Sequence Diagram loaders which implement this interface provide their own action to the action bar.
+ *
+ * Action provider are associated to a Sequence Diagram SDWidget calling SDViewer.setExtendedActionBarProvider()
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ISDExtendedActionBarProvider {
+
+ /**
+ * The caller is supposed to add its own actions in the cool bar and the drop-down menu.<br>
+ * See examples in SDView.createCoolbarContent().
+ *
+ * @param bar the bar
+ */
+ void supplementCoolbarContent(IActionBars bar);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFilterProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFilterProvider.java
new file mode 100755
index 0000000000..feb721f605
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFilterProvider.java
@@ -0,0 +1,43 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import java.util.List;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.FilterCriteria;
+
+/**
+ * Interface for providing a filter provider.
+ *
+ * Sequence Diagram loaders which implement this class provide the actions filtering the sequence diagram.<br>
+ * This interface also allow the implementor to set which graph nodes are supporting filtering (thanks to
+ * ISDGraphNodeSupporter extension).<br>
+ *
+ * Action provider are associated to a Sequence Diagram view by calling <code>SDView.setSDFilterProvider</code><br>
+ *
+ * Filters to be applied to be managed by the loader in an ArrayList of FilterCriteria.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ISDFilterProvider extends ISDGraphNodeSupporter {
+
+ /**
+ * Called when the Filter dialog box OK button is pressed
+ *
+ * @param filters user selection made in the dialog box
+ * @return true if the filter applied
+ */
+ boolean filter(List<FilterCriteria> filters);
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFindProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFindProvider.java
new file mode 100755
index 0000000000..e279d5fc8f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDFindProvider.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.Criteria;
+
+/**
+ * Interface for providing a find provider.
+ *
+ * Sequence Diagram loaders which implement this class provide the actions for finding the sequence diagram. This
+ * interface also allow the implementor to set which action/feature are supported.<br>
+ *
+ * Action provider are associated to a Sequence Diagram view by calling <code>SDView.setSDFindProvider()</code>.<br>
+ *
+ * Note that either provider implementing ISDFindProvider or IExtendedFindProvider can be active in the SDView.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface ISDFindProvider extends ISDGraphNodeSupporter {
+
+ /**
+ * Called when the Find dialog box OK button is pressed
+ *
+ * @param toApply user selection made in the dialog box
+ * @return true if the find got a non empty result
+ */
+ boolean find(Criteria toApply);
+
+ /**
+ * Called when dialog is closed
+ */
+ void cancel();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDGraphNodeSupporter.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDGraphNodeSupporter.java
new file mode 100755
index 0000000000..52e5f61bd5
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDGraphNodeSupporter.java
@@ -0,0 +1,83 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+/**
+ * Interface for providing a graph node supporter.
+ *
+ * Sequence Diagram loaders which implement this class provide the actions for finding or filtering the sequence
+ * diagram. This interface also allow the implementor to set which action/feature are supported
+ *
+ * Action provider are associated to a Sequence Diagram SDWidget calling <code>SDViewer.setSDFindProvider()</code> or
+ * <code>SDViewer.setSDFilterProvider()</code>.
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface ISDGraphNodeSupporter {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Lifeline support ID
+ */
+ static int LIFELINE = 0;
+ /**
+ * Synchronous message support ID
+ */
+ static int SYNCMESSAGE = 1;
+ /**
+ * Synchronous message return support ID
+ */
+ static int SYNCMESSAGERETURN = 2;
+ /**
+ * Asynchronous message support ID
+ */
+ static int ASYNCMESSAGE = 3;
+ /**
+ * Asynchronous message return support ID
+ */
+ static int ASYNCMESSAGERETURN = 4;
+ /**
+ * Stop support ID
+ */
+ static int STOP = 5;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * Return true to enable this options, false otherwise
+ *
+ * @param nodeType
+ * The integer value matching the type of the node
+ * @return true to enable this options, false otherwise
+ */
+ boolean isNodeSupported(int nodeType);
+
+ /**
+ * Return the name to use in dialogs Not called if isNodeSupported return
+ * false
+ *
+ * @param nodeType
+ * The integer value matching the type of the node
+ * @param loaderClassName
+ * The name of the loader class
+ * @return the name to use in dialogs
+ */
+ String getNodeName(int nodeType, String loaderClassName);
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPagingProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPagingProvider.java
new file mode 100755
index 0000000000..1c32c0c5f9
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPagingProvider.java
@@ -0,0 +1,61 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+/**
+ * Paging provider interface.
+ *
+ * Sequence Diagram loaders which implement this class provide the actions for sequence diagram page navigation.<br>
+ *
+ * Action provider are associated to a Sequence Diagram view by calling <code>SDView.setSDPagingProvider()</code>.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public interface ISDPagingProvider {
+
+ /**
+ * Return true to enable the next page button in the coolBar, false otherwise
+ *
+ * @return true if a next page exists false otherwise
+ */
+ boolean hasNextPage();
+
+ /**
+ * Return true to enable the previous page button in the coolBar, false otherwise
+ *
+ * @return true if a previous page exists false otherwise
+ */
+ boolean hasPrevPage();
+
+ /**
+ * Called back when next page button is pressed in the coolBar
+ */
+ void nextPage();
+
+ /**
+ * Called back when previous page button is pressed in the coolBar
+ */
+ void prevPage();
+
+ /**
+ * Called back when first page button is pressed in the coolBar
+ */
+ void firstPage();
+
+ /**
+ * Called back when last page button is pressed in the coolBar
+ */
+ void lastPage();
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPropertiesProvider.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPropertiesProvider.java
new file mode 100755
index 0000000000..19f5d728f2
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/handlers/provider/ISDPropertiesProvider.java
@@ -0,0 +1,35 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider;
+
+import org.eclipse.ui.views.properties.IPropertySheetPage;
+
+/**
+ * Interface for providing sequence diagram property.
+ *
+ * Contract for loaders that want to provide information in the properties view.
+ *
+ * @version 1.0
+ * @author sveyrier
+
+ */
+public interface ISDPropertiesProvider {
+
+ /**
+ * Returns the IPropertySheetEntry that will fill in the properties view
+ *
+ * @return the property sheet entry
+ */
+ IPropertySheetPage getPropertySheetEntry();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/IUml2SDLoader.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/IUml2SDLoader.java
new file mode 100755
index 0000000000..68a1c7fb09
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/IUml2SDLoader.java
@@ -0,0 +1,46 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.load;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+
+/**
+ * The interface all UML2SD loaders must implement.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface IUml2SDLoader {
+
+ /**
+ * Set the viewer object to the loader that has been reloaded at the beginning
+ * of a new workbench session
+ *
+ * @param viewer The sequence diagram view
+ */
+ void setViewer(SDView viewer);
+
+ /**
+ * Returns title string for the UML2SD View when this loader is the one
+ *
+ * @return the string convenient for this loader
+ */
+ String getTitleString();
+
+ /**
+ * When another loader becomes the one the previous one is replaced It's time clean-up
+ * if needed (listeners to be removed for example)
+ */
+ void dispose();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/LoadersManager.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/LoadersManager.java
new file mode 100644
index 0000000000..7c9b6726cd
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/load/LoadersManager.java
@@ -0,0 +1,397 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.load;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Manager class for the UML2SD extension point.
+ *
+ * @version 1.0
+ * @author sveyrier
+ * @author Bernd Hufmann
+ */
+public class LoadersManager {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * The loader tag for the extension point.
+ */
+ public static final String LOADER_TAG = "uml2SDLoader"; //$NON-NLS-1$
+ /**
+ * The loader prefix.
+ */
+ public static final String LOADER_PREFIX = LOADER_TAG + "."; //$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The LoadersManager singleton instance.
+ */
+ private static LoadersManager fLoadersManager;
+
+ /**
+ * Map for caching information (view ID to loader class)
+ */
+ private Map<String, IUml2SDLoader> fViewLoaderMap = new HashMap<>();
+ /**
+ * Map for caching information (view ID to list of configuration elements)
+ */
+ private Map<String, ArrayList<IConfigurationElement>> fViewLoadersList = new HashMap<>();
+
+ // ------------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------------
+ /**
+ * This should not be used by the clients
+ */
+ protected LoadersManager() {
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+ /**
+ * A static method to get the manager instance.
+ *
+ * @return the manager instance
+ */
+ public static synchronized LoadersManager getInstance() {
+ if (fLoadersManager == null) {
+ fLoadersManager = new LoadersManager();
+ }
+ return fLoadersManager;
+ }
+
+ /**
+ * Creates a loader instance and associate it to the view. It requires
+ * that the loader-view-association was created by an eclipse extension.
+ *
+ * @param className The name of the class to create an instance from
+ * @param view The UML2 Sequence Diagram view instance
+ * @return The created loader
+ */
+ public IUml2SDLoader createLoader(String className, SDView view) {
+
+ // Safety check
+ if (view == null) {
+ return null;
+ }
+
+ String viewId = view.getViewSite().getId();
+
+ // Get loaders from all extensions for given view
+ List<IConfigurationElement> loaderElements = getLoaderConfigurationElements(viewId);
+ IConfigurationElement ce = getLoaderConfigurationElement(className, loaderElements);
+
+ if (ce != null) {
+ // Assign a loader instance to this view
+ createLoaderForView(viewId, ce);
+ IUml2SDLoader loader = fViewLoaderMap.get(viewId);
+ if (loader != null) {
+ loader.setViewer(view);
+ return loader;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Sets the loader to null for this view, a kind of clean-up while disposing.
+ *
+ * @param viewId the id of the view
+ */
+ public void resetLoader(String viewId) {
+ IUml2SDLoader loader = fViewLoaderMap.get(viewId);
+ if (loader != null) {
+ loader.dispose();
+ }
+ fViewLoaderMap.put(viewId, null);
+ }
+
+ /**
+ * Returns the loader in use in given Sequence Diagram View
+ *
+ * @param viewId The Sequence Diagram viewId.
+ * @return the current loader if any - null otherwise
+ */
+ public IUml2SDLoader getCurrentLoader(String viewId) {
+ return getCurrentLoader(viewId, null);
+ }
+
+ /**
+ * Returns the loader in use in this Sequence Diagram View
+ *
+ * @param viewId The Sequence Diagram viewId
+ * @param view The Sequence Diagram view (if known). Use null to reference the primary SD View.
+ * @return the current loader if any - null otherwise
+ */
+ public IUml2SDLoader getCurrentLoader(String viewId, SDView view) {
+ if (viewId == null) {
+ return null;
+ }
+
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ // During Eclipse shutdown the active workbench window is null
+ if (window == null) {
+ return null;
+ }
+
+ IWorkbenchPage persp = window.getActivePage();
+
+ SDView sdView = view;
+
+ try {
+ // Search the view corresponding to the viewId
+ if (sdView == null) {
+ IViewReference viewref = persp.findViewReference(viewId);
+ if (viewref != null) {
+ sdView = (SDView) viewref.getView(false);
+ }
+
+ if (sdView == null) {
+ // no corresponding view exists -> return null for the loader
+ return null;
+ }
+ }
+
+ // Return the loader corresponding to that view (if any)
+ IUml2SDLoader loader = fViewLoaderMap.get(viewId);
+ if (loader == null) {
+ createLastLoaderIfAny(viewId);
+ loader = fViewLoaderMap.get(viewId);
+ }
+
+ return loader;
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error getting loader class", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Returns the loader class name that have been saved last time.
+ *
+ * @param viewId The view this loader belongs to
+ * @return the class name of the saved loader
+ */
+ public String getSavedLoader(String viewId) {
+ IPreferenceStore p = Activator.getDefault().getPreferenceStore();
+ return p.getString(LOADER_PREFIX + viewId);
+ }
+
+ /**
+ * Saves the last loader in order to reload it on next session.
+ *
+ * @param id
+ * Standalone ID of the loader
+ * @param id2
+ * Suffix ID of the loader
+ */
+ public void saveLastLoader(String id, String id2) {
+ IPreferenceStore p = Activator.getDefault().getPreferenceStore();
+ p.setValue(LOADER_PREFIX + id2, id);
+ }
+
+ /**
+ * Changes the current unique loader to the given secondary viewId.
+ *
+ * @param loader The current loader
+ * @param id the view secondary id or null
+ */
+ private void setCurrentLoader(IUml2SDLoader loader, String id) {
+ if (id == null) {
+ return;
+ }
+
+ // Get the loader in use
+ IUml2SDLoader currentLoader = fViewLoaderMap.get(id);
+
+ if ((currentLoader != null) && (currentLoader != loader)) {
+ if (loader != null) {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ // During Eclipse shutdown the active workbench window is null
+ if (window == null) {
+ return;
+ }
+ IWorkbenchPage persp = window.getActivePage();
+ try {
+ // Search view corresponding to the viewId
+ SDView sdview = null;
+ IViewReference viewref = persp.findViewReference(id);
+ if (viewref != null) {
+ sdview = (SDView) viewref.getView(false);
+ }
+
+ // Make everything clean for the new loader
+ if (sdview != null) {
+ sdview.resetProviders();
+ }
+
+ } catch (Exception e) {
+ Activator.getDefault().logError("Error setting current loader class", e); //$NON-NLS-1$
+ }
+ }
+ // The old loader is going to be kicked
+ currentLoader.dispose();
+ }
+
+ // Replace the current loader by the new one in the map
+ fViewLoaderMap.put(id, loader);
+
+ // Store this loader in the preferences to be able to restore it when the workbench will be re-launched
+ if (loader != null) {
+ saveLastLoader(loader.getClass().getName(), id);
+ }
+ }
+
+ /**
+ * Creates the last loader and saves it. If not last is not available, it creates
+ * and saves the default loader, else no loader is created.
+ *
+ * @param viewId The view ID.
+ */
+ private void createLastLoaderIfAny(String viewId) {
+ // Get saved loader from preferences
+ String loaderName = getSavedLoader(viewId);
+
+ // Get loaders from all extensions for given view
+ List<IConfigurationElement> loaderElements = getLoaderConfigurationElements(viewId);
+ IConfigurationElement ce = getLoaderConfigurationElement(loaderName, loaderElements);
+
+ if (ce == null) {
+ ce = getDefaultLoader(loaderElements);
+ }
+
+ if (ce != null) {
+ createLoaderForView(viewId, ce);
+ }
+ }
+
+ /**
+ * Gets a list of loader configuration elements from the extension point registry for a given view.
+ * @param viewId The view ID
+ * @return List of extension point configuration elements.
+ */
+ private List<IConfigurationElement> getLoaderConfigurationElements(String viewId) {
+ List<IConfigurationElement> list = fViewLoadersList.get(viewId);
+ if (list != null) {
+ return list;
+ }
+
+ ArrayList<IConfigurationElement> ret = new ArrayList<>();
+ IExtensionPoint iep = Platform.getExtensionRegistry().getExtensionPoint(Activator.PLUGIN_ID, LOADER_TAG);
+ if (iep == null) {
+ return ret;
+ }
+
+ IExtension[] ie = iep.getExtensions();
+ if (ie == null) {
+ return ret;
+ }
+
+ for (int i = 0; i < ie.length; i++) {
+ IConfigurationElement c[] = ie[i].getConfigurationElements();
+ for (int j = 0; j < c.length; j++) {
+ if (viewId.equals(c[j].getAttribute("view"))) { //$NON-NLS-1$
+ ret.add(c[j]);
+ }
+ }
+ }
+ fViewLoadersList.put(viewId, ret);
+ return ret;
+ }
+
+ /**
+ * Returns the loader configuration element for given loader class name and for the given
+ * list of configuration elements, if available else null.
+ *
+ * @param loaderClassName The loader class name.
+ * @param loaderElements The list of loader configuration elements
+ * @return Extension point configuration element
+ */
+ private static IConfigurationElement getLoaderConfigurationElement(
+ String loaderClassName, List<IConfigurationElement> loaderElements) {
+ if (loaderClassName != null && loaderClassName.length() > 0) {
+ // Find configuration element corresponding to the saved loader
+ for (Iterator<IConfigurationElement> i = loaderElements.iterator(); i.hasNext();) {
+ IConfigurationElement ce = i.next();
+ if (ce.getAttribute("class").equals(loaderClassName)) { //$NON-NLS-1$
+ return ce;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the loader configuration element for the given list of configuration elements, if available else null.
+ * Note that if multiple default loaders are defined it selects the first one
+
+ * @param loaderElements The list of loader configuration elements
+ * @return The default extension point configuration element.
+ */
+ private static IConfigurationElement getDefaultLoader(
+ List<IConfigurationElement> loaderElements) {
+ // Look for a default loader
+ for (Iterator<IConfigurationElement> i = loaderElements.iterator(); i.hasNext();) {
+ IConfigurationElement ce = i.next();
+ if (Boolean.valueOf(ce.getAttribute("default")).booleanValue()) { //$NON-NLS-1$
+ return ce;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Creates an instance of the loader class for a given extension point configuration element and
+ * also sets it as current loader for the given view.
+ *
+ * @param viewId The view ID.
+ * @param ce The extension point configuration element
+ */
+ private void createLoaderForView(String viewId, IConfigurationElement ce) {
+ try {
+ Object obj = ce.createExecutableExtension("class"); //$NON-NLS-1$
+ IUml2SDLoader l = (IUml2SDLoader) obj;
+ if (viewId != null) {
+ setCurrentLoader(l, viewId);
+ }
+ } catch (CoreException e4) {
+ Activator.getDefault().logError("Error 'uml2SDLoader' Extension point", e4); //$NON-NLS-1$
+ } catch (Exception e5) {
+ Activator.getDefault().logError("Error 'uml2SDLoader' Extension point", e5); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/Messages.java
new file mode 100644
index 0000000000..95a2928483
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/Messages.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2013 Ericsson.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.loader;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages related to the sequence diagram loader
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.uml2sd.loader.messages"; //$NON-NLS-1$
+ public static String TmfUml2SDSyncLoader_ViewName;
+ public static String TmfUml2SDSyncLoader_CategoryLifeline;
+ public static String TmfUml2SDSyncLoader_CategoryMessage;
+ public static String TmfUml2SDSyncLoader_FrameName;
+ public static String TmfUml2SDSyncLoader_SearchJobDescrition;
+ public static String TmfUml2SDSyncLoader_SearchNotFound;
+
+ /** @since 2.0 */
+ public static String TmfUml2SDSyncLoader_EventTypeSend;
+ /** @since 2.0 */
+ public static String TmfUml2SDSyncLoader_EventTypeReceive;
+ /** @since 2.0 */
+ public static String TmfUml2SDSyncLoader_FieldSender;
+ /** @since 2.0 */
+ public static String TmfUml2SDSyncLoader_FieldReceiver;
+ /** @since 2.0 */
+ public static String TmfUml2SDSyncLoader_FieldSignal;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfAsyncMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfAsyncMessage.java
new file mode 100644
index 0000000000..5c59b96030
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfAsyncMessage.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.loader;
+
+import org.eclipse.tracecompass.tmf.core.uml2sd.ITmfAsyncSequenceDiagramEvent;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
+
+/**
+ * <p>
+ * Extends AsyncMessage class to provide additional information about the trace event.
+ * </p>
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class TmfAsyncMessage extends AsyncMessage implements ITmfAsyncSequenceDiagramEvent {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * A asynchronous sequence diagram event implementation
+ */
+ private ITmfAsyncSequenceDiagramEvent fSdEvent;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param sdEvent The asynchronous sequence diagram event implementation
+ * @param eventOccurrence The event index
+ */
+ public TmfAsyncMessage(ITmfAsyncSequenceDiagramEvent sdEvent, int eventOccurrence) {
+ this.fSdEvent = sdEvent;
+ setEventOccurrence(eventOccurrence);
+ setName(sdEvent.getName());
+ setStartTime(sdEvent.getStartTime());
+ setEndTime(sdEvent.getEndTime());
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public String getSender() {
+ return fSdEvent.getSender();
+ }
+
+ @Override
+ public String getReceiver() {
+ return fSdEvent.getReceiver();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfSyncMessage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfSyncMessage.java
new file mode 100644
index 0000000000..aec9f5fe4f
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfSyncMessage.java
@@ -0,0 +1,68 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.loader;
+
+import org.eclipse.tracecompass.tmf.core.uml2sd.ITmfSyncSequenceDiagramEvent;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+
+
+/**
+ * <p>
+ * Extends SyncMessage class to provide additional information about the trace event.
+ * </p>
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class TmfSyncMessage extends SyncMessage implements ITmfSyncSequenceDiagramEvent {
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * A synchronous sequence diagram event implementation
+ */
+ private ITmfSyncSequenceDiagramEvent fSdEvent;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Standard constructor
+ *
+ * @param sdEvent The synchronous sequence diagram event implementation
+ * @param eventOccurrence The event index
+ */
+ public TmfSyncMessage(ITmfSyncSequenceDiagramEvent sdEvent, int eventOccurrence) {
+ this.fSdEvent = sdEvent;
+ setEventOccurrence(eventOccurrence);
+ setName(sdEvent.getName());
+ setTime(sdEvent.getStartTime());
+ }
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public String getSender() {
+ return fSdEvent.getSender();
+ }
+
+ @Override
+ public String getReceiver() {
+ return fSdEvent.getReceiver();
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfUml2SDSyncLoader.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfUml2SDSyncLoader.java
new file mode 100644
index 0000000000..61ab61ebe6
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/TmfUml2SDSyncLoader.java
@@ -0,0 +1,1485 @@
+/**********************************************************************
+ * Copyright (c) 2011, 2013 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License v1.0 which
+ * accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Bernd Hufmann - Initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.loader;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.locks.ReentrantLock;
+
+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.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.core.component.TmfComponent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
+import org.eclipse.tracecompass.tmf.core.event.ITmfEventField;
+import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
+import org.eclipse.tracecompass.tmf.core.signal.TmfRangeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTimeSynchSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceClosedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceOpenedSignal;
+import org.eclipse.tracecompass.tmf.core.signal.TmfTraceSelectedSignal;
+import org.eclipse.tracecompass.tmf.core.timestamp.ITmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
+import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimestamp;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+import org.eclipse.tracecompass.tmf.core.uml2sd.ITmfSyncSequenceDiagramEvent;
+import org.eclipse.tracecompass.tmf.core.uml2sd.TmfSyncSequenceDiagramEvent;
+import org.eclipse.tracecompass.tmf.ui.editors.ITmfTraceEditor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.SDView;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Frame;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.Lifeline;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.Criteria;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.FilterCriteria;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.dialogs.FilterListDialog;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDAdvancedPagingProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFilterProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDFindProvider;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.handlers.provider.ISDGraphNodeSupporter;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.load.IUml2SDLoader;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.progress.IProgressConstants;
+
+/**
+ * <p>
+ * This class is a reference implementation of the
+ * <code>org.eclipse.linuxtools.tmf.ui.Uml2SDLoader</code> extension point. It
+ * provides a Sequence Diagram loader for a user space trace with specific trace
+ * content for sending and receiving signals between components. I also includes
+ * a default implementation for the <code>ITmfEvent</code> parsing.
+ * </p>
+ *
+ * The class <code>TmfUml2SDSyncLoader</code> analyzes events from type
+ * <code>ITmfEvent</code> and creates events type
+ * <code>ITmfSyncSequenceDiagramEvent</code> if the <code>ITmfEvent</code>
+ * contains all relevant information. The analysis checks that the event type
+ * strings contains either string SEND or RECEIVE. If event type matches these
+ * key words, the analyzer will look for strings sender, receiver and signal in
+ * the event fields of type <code>ITmfEventField</code>. If all the data is
+ * found a sequence diagram event from can be created. Note that Sync Messages
+ * are assumed, which means start and end time are the same. <br>
+ * <br>
+ * The parsing of the <code>ITmfEvent</code> is done in the method
+ * <code>getSequnceDiagramEvent()</code> of class
+ * <code>TmfUml2SDSyncLoader</code>. By extending the class
+ * <code>TmfUml2SDSyncLoader</code> and overwriting
+ * <code>getSequnceDiagramEvent()</code> a customized parsing algorithm can be
+ * implemented.<br>
+ * <br>
+ * Note that combined traces of multiple components, that contain the trace
+ * information about the same interactions are not supported in the class
+ * <code>TmfUml2SDSyncLoader</code>.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ */
+public class TmfUml2SDSyncLoader extends TmfComponent implements IUml2SDLoader, ISDFindProvider, ISDFilterProvider, ISDAdvancedPagingProvider, ISelectionListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Default title name.
+ */
+ protected static final String TITLE = Messages.TmfUml2SDSyncLoader_ViewName;
+
+ /**
+ * Maximum number of messages per page.
+ */
+ protected static final int MAX_NUM_OF_MSG = 10000;
+
+ private static final int INDEXING_THREAD_SLEEP_VALUE = 100;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ // Experiment attributes
+ /**
+ * The TMF trace reference.
+ * @since 2.0
+ */
+ protected ITmfTrace fTrace = null;
+ /**
+ * The current indexing event request.
+ */
+ protected ITmfEventRequest fIndexRequest = null;
+ /**
+ * The current request to fill a page.
+ */
+ protected ITmfEventRequest fPageRequest = null;
+ /**
+ * Flag whether the time range signal was sent by this loader class or not
+ */
+ protected volatile boolean fIsSignalSent = false;
+
+ // The view and event attributes
+ /**
+ * The sequence diagram view reference.
+ */
+ protected SDView fView = null;
+ /**
+ * The current sequence diagram frame reference.
+ */
+ protected Frame fFrame = null;
+ /**
+ * The list of sequence diagram events of current page.
+ */
+ protected List<ITmfSyncSequenceDiagramEvent> fEvents = new ArrayList<>();
+
+ // Checkpoint and page attributes
+ /**
+ * The checkpoints of the whole sequence diagram trace (i.e. start time stamp of each page)
+ */
+ protected List<TmfTimeRange> fCheckPoints = new ArrayList<>(MAX_NUM_OF_MSG);
+ /**
+ * The current page displayed.
+ */
+ protected volatile int fCurrentPage = 0;
+ /**
+ * The current time selected.
+ */
+ protected ITmfTimestamp fCurrentTime = null;
+ /**
+ * Flag to specify that selection of message is done by selection or by signal.
+ */
+ protected volatile boolean fIsSelect = false;
+
+ // Search attributes
+ /**
+ * The job for searching across pages.
+ */
+ protected SearchJob fFindJob = null;
+ /**
+ * List of found nodes within a page.
+ */
+ protected List<GraphNode> fFindResults = new ArrayList<>();
+ /**
+ * The current find criteria reference
+ */
+ protected Criteria fFindCriteria = null;
+ /**
+ * The current find index within the list of found nodes (<code>fFindeResults</code> within a page.
+ */
+ protected volatile int fCurrentFindIndex = 0;
+
+ // Filter attributes
+ /**
+ * The list of active filters.
+ */
+ protected List<FilterCriteria> fFilterCriteria = null;
+
+ // Thread synchronization
+ /**
+ * The synchronization lock.
+ */
+ protected ReentrantLock fLock = new ReentrantLock();
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+ /**
+ * Default constructor
+ */
+ public TmfUml2SDSyncLoader() {
+ super(TITLE);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param name Name of loader
+ */
+ public TmfUml2SDSyncLoader(String name) {
+ super(name);
+ }
+
+ // ------------------------------------------------------------------------
+ // Operations
+ // ------------------------------------------------------------------------
+
+ /**
+ * Returns the current time if available else null.
+ *
+ * @return the current time if available else null
+ * @since 2.0
+ */
+ public ITmfTimestamp getCurrentTime() {
+ fLock.lock();
+ try {
+ if (fCurrentTime != null) {
+ return fCurrentTime;
+ }
+ return null;
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Waits for the page request to be completed
+ */
+ public void waitForCompletion() {
+ fLock.lock();
+ ITmfEventRequest request = fPageRequest;
+ fLock.unlock();
+ if (request != null) {
+ try {
+ request.waitForCompletion();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Handler for the trace opened signal.
+ * @param signal The trace opened signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceOpened(TmfTraceOpenedSignal signal) {
+ fTrace = signal.getTrace();
+ loadTrace();
+ }
+
+
+ /**
+ * Signal handler for the trace selected signal.
+ *
+ * Spawns a request to index the trace (checkpoints creation) as well as it fills
+ * the first page.
+ *
+ * @param signal The trace selected signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceSelected(TmfTraceSelectedSignal signal) {
+ // Update the trace reference
+ ITmfTrace trace = signal.getTrace();
+ if (!trace.equals(fTrace)) {
+ fTrace = trace;
+ }
+ loadTrace();
+ }
+
+ /**
+ * Method for loading the current selected trace into the view.
+ * Sub-class need to override this method to add the view specific implementation.
+ * @since 2.0
+ */
+ protected void loadTrace() {
+ ITmfEventRequest indexRequest = null;
+ fLock.lock();
+
+ try {
+ final Job job = new IndexingJob("Indexing " + getName() + "..."); //$NON-NLS-1$ //$NON-NLS-2$
+ job.setUser(false);
+ job.schedule();
+
+ indexRequest = fIndexRequest;
+
+ cancelOngoingRequests();
+
+ TmfTimeRange window = TmfTimeRange.ETERNITY;
+
+ fIndexRequest = new TmfEventRequest(ITmfEvent.class, window, 0,
+ ITmfEventRequest.ALL_DATA, ITmfEventRequest.ExecutionType.BACKGROUND) {
+
+ private ITmfTimestamp fFirstTime = null;
+ private ITmfTimestamp fLastTime = null;
+ private int fNbSeqEvents = 0;
+ private final List<ITmfSyncSequenceDiagramEvent> fSdEvents = new ArrayList<>(MAX_NUM_OF_MSG);
+
+ @Override
+ public void handleData(ITmfEvent event) {
+ super.handleData(event);
+
+ ITmfSyncSequenceDiagramEvent sdEvent = getSequenceDiagramEvent(event);
+
+ if (sdEvent != null) {
+ ++fNbSeqEvents;
+
+ if (fFirstTime == null) {
+ fFirstTime = event.getTimestamp();
+ }
+
+ fLastTime = event.getTimestamp();
+
+ if ((fNbSeqEvents % MAX_NUM_OF_MSG) == 0) {
+ fLock.lock();
+ try {
+ fCheckPoints.add(new TmfTimeRange(fFirstTime, fLastTime));
+ if (fView != null) {
+ fView.updateCoolBar();
+ }
+ } finally {
+ fLock.unlock();
+ }
+ fFirstTime = null;
+
+ }
+
+ if (fNbSeqEvents > MAX_NUM_OF_MSG) {
+ // page is full
+ return;
+ }
+
+ fSdEvents.add(sdEvent);
+
+ if (fNbSeqEvents == MAX_NUM_OF_MSG) {
+ fillCurrentPage(fSdEvents);
+ }
+ }
+ }
+
+ @Override
+ public void handleSuccess() {
+ if ((fFirstTime != null) && (fLastTime != null)) {
+
+ fLock.lock();
+ try {
+ fCheckPoints.add(new TmfTimeRange(fFirstTime, fLastTime));
+ if (fView != null) {
+ fView.updateCoolBar();
+ }
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ if (fNbSeqEvents <= MAX_NUM_OF_MSG) {
+ fillCurrentPage(fSdEvents);
+ }
+
+ super.handleSuccess();
+ }
+
+ @Override
+ public void handleCompleted() {
+ if (fEvents.isEmpty()) {
+ fFrame = new Frame();
+ // make sure that view is not null when setting frame
+ SDView sdView;
+ fLock.lock();
+ try {
+ sdView = fView;
+ } finally {
+ fLock.unlock();
+ }
+ if (sdView != null) {
+ sdView.setFrameSync(fFrame);
+ }
+ }
+ super.handleCompleted();
+ job.cancel();
+ }
+ };
+
+ } finally {
+ fLock.unlock();
+ }
+ if (indexRequest != null && !indexRequest.isCompleted()) {
+ indexRequest.cancel();
+ }
+ resetLoader();
+ fTrace.sendRequest(fIndexRequest);
+ }
+
+ /**
+ * Signal handler for the trace closed signal.
+ *
+ * @param signal The trace closed signal
+ * @since 2.0
+ */
+ @TmfSignalHandler
+ public void traceClosed(TmfTraceClosedSignal signal) {
+ if (signal.getTrace() != fTrace) {
+ return;
+ }
+ ITmfEventRequest indexRequest = null;
+ fLock.lock();
+ try {
+ indexRequest = fIndexRequest;
+ fIndexRequest = null;
+
+ cancelOngoingRequests();
+
+ if (fFilterCriteria != null) {
+ fFilterCriteria.clear();
+ }
+
+ FilterListDialog.deactivateSavedGlobalFilters();
+ } finally {
+ fTrace = null;
+ fLock.unlock();
+ }
+ if (indexRequest != null && !indexRequest.isCompleted()) {
+ indexRequest.cancel();
+ }
+
+ resetLoader();
+ }
+
+ /**
+ * Moves to the page that contains the time provided by the signal. The messages will be selected
+ * if the provided time is the time of a message.
+ *
+ * @param signal The Time synch signal.
+ */
+ @TmfSignalHandler
+ public void synchToTime(TmfTimeSynchSignal signal) {
+ fLock.lock();
+ try {
+ if ((signal.getSource() != this) && (fFrame != null) && (fCheckPoints.size() > 0)) {
+ fCurrentTime = signal.getBeginTime();
+ fIsSelect = true;
+ moveToMessage();
+ }
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Moves to the page that contains the current time provided by signal.
+ * No message will be selected however the focus will be set to the message
+ * if the provided time is the time of a message.
+ *
+ * @param signal The time range sync signal
+ */
+ @TmfSignalHandler
+ public void synchToTimeRange(TmfRangeSynchSignal signal) {
+ fLock.lock();
+ try {
+ if ((signal.getSource() != this) && (fFrame != null) && !fIsSignalSent && (fCheckPoints.size() > 0)) {
+ TmfTimeRange newTimeRange = signal.getCurrentRange();
+
+ fIsSelect = false;
+ fCurrentTime = newTimeRange.getStartTime();
+
+ moveToMessage();
+ }
+ } finally {
+ fLock.unlock();
+ }
+
+ }
+
+ @Override
+ public void setViewer(SDView viewer) {
+
+ fLock.lock();
+ try {
+ fView = viewer;
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().addPostSelectionListener(this);
+ fView.setSDFindProvider(this);
+ fView.setSDPagingProvider(this);
+ fView.setSDFilterProvider(this);
+
+ resetLoader();
+ IEditorPart editor = fView.getSite().getPage().getActiveEditor();
+ if (editor instanceof ITmfTraceEditor) {
+ ITmfTrace trace = ((ITmfTraceEditor) editor).getTrace();
+ if (trace != null) {
+ traceSelected(new TmfTraceSelectedSignal(this, trace));
+ }
+ }
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public String getTitleString() {
+ return getName();
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ ITmfEventRequest indexRequest = null;
+ fLock.lock();
+ try {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ // During Eclipse shutdown the active workbench window is null
+ if (window != null) {
+ window.getSelectionService().removePostSelectionListener(this);
+ }
+
+ indexRequest = fIndexRequest;
+ fIndexRequest = null;
+ cancelOngoingRequests();
+
+ fView.setSDFindProvider(null);
+ fView.setSDPagingProvider(null);
+ fView.setSDFilterProvider(null);
+ fView = null;
+ } finally {
+ fLock.unlock();
+ }
+ if (indexRequest != null && !indexRequest.isCompleted()) {
+ indexRequest.cancel();
+ }
+ }
+
+ @Override
+ public boolean isNodeSupported(int nodeType) {
+ switch (nodeType) {
+ case ISDGraphNodeSupporter.LIFELINE:
+ case ISDGraphNodeSupporter.SYNCMESSAGE:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public String getNodeName(int nodeType, String loaderClassName) {
+ switch (nodeType) {
+ case ISDGraphNodeSupporter.LIFELINE:
+ return Messages.TmfUml2SDSyncLoader_CategoryLifeline;
+ case ISDGraphNodeSupporter.SYNCMESSAGE:
+ return Messages.TmfUml2SDSyncLoader_CategoryMessage;
+ default:
+ break;
+ }
+ return ""; //$NON-NLS-1$
+ }
+
+ @Override
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ ISelection sel = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
+ if ((sel != null) && (sel instanceof StructuredSelection)) {
+ StructuredSelection stSel = (StructuredSelection) sel;
+ if (stSel.getFirstElement() instanceof TmfSyncMessage) {
+ TmfSyncMessage syncMsg = ((TmfSyncMessage) stSel.getFirstElement());
+ broadcast(new TmfTimeSynchSignal(this, syncMsg.getStartTime()));
+ }
+ }
+ }
+
+ @Override
+ public boolean find(Criteria toSearch) {
+ fLock.lock();
+ try {
+ if (fFrame == null) {
+ return false;
+ }
+
+ if ((fFindResults == null) || (fFindCriteria == null) || !fFindCriteria.compareTo(toSearch)) {
+ fFindResults = new CopyOnWriteArrayList<>();
+ fFindCriteria = toSearch;
+ if (fFindCriteria.isLifeLineSelected()) {
+ for (int i = 0; i < fFrame.lifeLinesCount(); i++) {
+ if (fFindCriteria.matches(fFrame.getLifeline(i).getName())) {
+ fFindResults.add(fFrame.getLifeline(i));
+ }
+ }
+ }
+
+ ArrayList<GraphNode> msgs = new ArrayList<>();
+ if (fFindCriteria.isSyncMessageSelected()) {
+ for (int i = 0; i < fFrame.syncMessageCount(); i++) {
+ if (fFindCriteria.matches(fFrame.getSyncMessage(i).getName())) {
+ msgs.add(fFrame.getSyncMessage(i));
+ }
+ }
+ }
+
+ if (!msgs.isEmpty()) {
+ fFindResults.addAll(msgs);
+ }
+
+ List<GraphNode> selection = fView.getSDWidget().getSelection();
+ if ((selection != null) && (selection.size() == 1)) {
+ fCurrentFindIndex = fFindResults.indexOf(selection.get(0)) + 1;
+ } else {
+ fCurrentFindIndex = 0;
+ }
+ } else {
+ fCurrentFindIndex++;
+ }
+
+ if (fFindResults.size() > fCurrentFindIndex) {
+ GraphNode current = fFindResults.get(fCurrentFindIndex);
+ fView.getSDWidget().moveTo(current);
+ return true;
+ }
+ fFindResults = null;
+ fCurrentFindIndex =0;
+ return findInNextPages(fFindCriteria); // search in other page
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void cancel() {
+ cancelOngoingRequests();
+ }
+
+ @Override
+ public boolean filter(List<FilterCriteria> filters) {
+ fLock.lock();
+ try {
+ cancelOngoingRequests();
+
+ if (filters == null) {
+ fFilterCriteria = new ArrayList<>();
+ } else {
+ List<FilterCriteria> list = filters;
+ fFilterCriteria = new ArrayList<>(list);
+ }
+
+ fillCurrentPage(fEvents);
+
+ } finally {
+ fLock.unlock();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean hasNextPage() {
+ fLock.lock();
+ try {
+ int size = fCheckPoints.size();
+ if (size > 0) {
+ return fCurrentPage < (size - 1);
+ }
+ } finally {
+ fLock.unlock();
+ }
+ return false;
+ }
+
+ @Override
+ public boolean hasPrevPage() {
+ fLock.lock();
+ try {
+ return fCurrentPage > 0;
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void nextPage() {
+ fLock.lock();
+ try {
+ // Safety check
+ if (fCurrentPage >= (fCheckPoints.size() - 1)) {
+ return;
+ }
+
+ cancelOngoingRequests();
+ fCurrentTime = null;
+ fCurrentPage++;
+ moveToPage();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void prevPage() {
+ fLock.lock();
+ try {
+ // Safety check
+ if (fCurrentPage <= 0) {
+ return;
+ }
+
+ cancelOngoingRequests();
+ fCurrentTime = null;
+ fCurrentPage--;
+ moveToPage();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void firstPage() {
+ fLock.lock();
+ try {
+
+ cancelOngoingRequests();
+ fCurrentTime = null;
+ fCurrentPage = 0;
+ moveToPage();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void lastPage() {
+ fLock.lock();
+ try {
+ cancelOngoingRequests();
+ fCurrentTime = null;
+ fCurrentPage = fCheckPoints.size() - 1;
+ moveToPage();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public int currentPage() {
+ fLock.lock();
+ try {
+ return fCurrentPage;
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public int pagesCount() {
+ fLock.lock();
+ try {
+ return fCheckPoints.size();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void pageNumberChanged(int pagenNumber) {
+ int localPageNumber = pagenNumber;
+
+ fLock.lock();
+ try {
+ cancelOngoingRequests();
+
+ if (localPageNumber < 0) {
+ localPageNumber = 0;
+ }
+ int size = fCheckPoints.size();
+ if (localPageNumber > (size - 1)) {
+ localPageNumber = size - 1;
+ }
+ fCurrentPage = localPageNumber;
+ moveToPage();
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ @Override
+ public void broadcast(TmfSignal signal) {
+ fIsSignalSent = true;
+ super.broadcast(signal);
+ fIsSignalSent = false;
+ }
+
+ /**
+ * Cancels any ongoing find operation
+ */
+ protected void cancelOngoingRequests() {
+ fLock.lock();
+ ITmfEventRequest pageRequest = null;
+ try {
+ // Cancel the search thread
+ if (fFindJob != null) {
+ fFindJob.cancel();
+ }
+
+ fFindResults = null;
+ fFindCriteria = null;
+ fCurrentFindIndex = 0;
+
+ pageRequest = fPageRequest;
+ fPageRequest = null;
+ } finally {
+ fLock.unlock();
+ }
+ if (pageRequest != null && !pageRequest.isCompleted()) {
+ pageRequest.cancel();
+ }
+ }
+
+ /**
+ * Resets loader attributes
+ */
+ protected void resetLoader() {
+ fLock.lock();
+ try {
+ fCurrentTime = null;
+ fEvents.clear();
+ fCheckPoints.clear();
+ fCurrentPage = 0;
+ fCurrentFindIndex = 0;
+ fFindCriteria = null;
+ fFindResults = null;
+ fView.setFrameSync(new Frame());
+ fFrame = null;
+ }
+ finally {
+ fLock.unlock();
+ }
+
+ }
+
+ /**
+ * Fills current page with sequence diagram content.
+ *
+ * @param events sequence diagram events
+ */
+ protected void fillCurrentPage(List<ITmfSyncSequenceDiagramEvent> events) {
+
+ fLock.lock();
+ try {
+ fEvents = new ArrayList<>(events);
+ if (fView != null && !events.isEmpty()) {
+ fView.toggleWaitCursorAsync(true);
+ }
+ } finally {
+ fLock.unlock();
+ }
+
+ final Frame frame = new Frame();
+
+ if (!events.isEmpty()) {
+ Map<String, Lifeline> nodeToLifelineMap = new HashMap<>();
+
+ frame.setName(Messages.TmfUml2SDSyncLoader_FrameName);
+
+ for (int i = 0; i < events.size(); i++) {
+
+ ITmfSyncSequenceDiagramEvent sdEvent = events.get(i);
+
+ if ((nodeToLifelineMap.get(sdEvent.getSender()) == null) && (!filterLifeLine(sdEvent.getSender()))) {
+ Lifeline lifeline = new Lifeline();
+ lifeline.setName(sdEvent.getSender());
+ nodeToLifelineMap.put(sdEvent.getSender(), lifeline);
+ frame.addLifeLine(lifeline);
+ }
+
+ if ((nodeToLifelineMap.get(sdEvent.getReceiver()) == null) && (!filterLifeLine(sdEvent.getReceiver()))) {
+ Lifeline lifeline = new Lifeline();
+ lifeline.setName(sdEvent.getReceiver());
+ nodeToLifelineMap.put(sdEvent.getReceiver(), lifeline);
+ frame.addLifeLine(lifeline);
+ }
+ }
+
+ int eventOccurence = 1;
+
+ for (int i = 0; i < events.size(); i++) {
+ ITmfSyncSequenceDiagramEvent sdEvent = events.get(i);
+
+ // Check message filter
+ if (filterMessage(sdEvent)) {
+ continue;
+ }
+
+ // Set the message sender and receiver
+ Lifeline startLifeline = nodeToLifelineMap.get(sdEvent.getSender());
+ Lifeline endLifeline = nodeToLifelineMap.get(sdEvent.getReceiver());
+
+ // Check if any of the lifelines were filtered
+ if ((startLifeline == null) || (endLifeline == null)) {
+ continue;
+ }
+
+ int tmp = Math.max(startLifeline.getEventOccurrence(), endLifeline.getEventOccurrence());
+ eventOccurence = Math.max(eventOccurence, tmp);
+
+ startLifeline.setCurrentEventOccurrence(eventOccurence);
+ endLifeline.setCurrentEventOccurrence(eventOccurence);
+
+ TmfSyncMessage message = new TmfSyncMessage(sdEvent, eventOccurence++);
+
+ message.setStartLifeline(startLifeline);
+ message.setEndLifeline(endLifeline);
+
+ message.setTime(sdEvent.getStartTime());
+
+ // add the message to the frame
+ frame.addMessage(message);
+
+ }
+ fLock.lock();
+ try {
+ if (!fView.getSDWidget().isDisposed()) {
+ fView.getSDWidget().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+
+ fLock.lock();
+ try {
+ // check if view was disposed in the meanwhile
+ if ((fView != null) && (!fView.getSDWidget().isDisposed())) {
+ fFrame = frame;
+ fView.setFrame(fFrame);
+
+ if (fCurrentTime != null) {
+ moveToMessageInPage();
+ }
+
+ if (fFindCriteria != null) {
+ find(fFindCriteria);
+ }
+
+ fView.toggleWaitCursorAsync(false);
+ }
+ } finally {
+ fLock.unlock();
+ }
+
+ }
+ });
+ }
+ }
+ finally {
+ fLock.unlock();
+ }
+ }
+ }
+
+ /**
+ * Moves to a certain message defined by timestamp (across pages)
+ */
+ protected void moveToMessage() {
+ int page = 0;
+
+ fLock.lock();
+ try {
+ page = getPage(fCurrentTime);
+
+ if (page == fCurrentPage) {
+ moveToMessageInPage();
+ return;
+ }
+ fCurrentPage = page;
+ moveToPage(false);
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Moves to a certain message defined by timestamp in current page
+ */
+ protected void moveToMessageInPage() {
+ fLock.lock();
+ try {
+ if (!fView.getSDWidget().isDisposed()) {
+ // Check for GUI thread
+ if(Display.getCurrent() != null) {
+ // Already in GUI thread - execute directly
+ TmfSyncMessage prevMessage = null;
+ TmfSyncMessage syncMessage = null;
+ boolean isExactTime = false;
+ for (int i = 0; i < fFrame.syncMessageCount(); i++) {
+ if (fFrame.getSyncMessage(i) instanceof TmfSyncMessage) {
+ syncMessage = (TmfSyncMessage) fFrame.getSyncMessage(i);
+ if (syncMessage.getStartTime().compareTo(fCurrentTime, false) == 0) {
+ isExactTime = true;
+ break;
+ } else if ((syncMessage.getStartTime().compareTo(fCurrentTime, false) > 0) && (prevMessage != null)) {
+ syncMessage = prevMessage;
+ break;
+ }
+ prevMessage = syncMessage;
+ }
+ }
+ if (fIsSelect && isExactTime) {
+ fView.getSDWidget().moveTo(syncMessage);
+ }
+ else {
+ fView.getSDWidget().ensureVisible(syncMessage);
+ fView.getSDWidget().clearSelection();
+ fView.getSDWidget().redraw();
+ }
+ }
+ else {
+ // Not in GUI thread - queue action in GUI thread.
+ fView.getSDWidget().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ moveToMessageInPage();
+ }
+ });
+ }
+ }
+ }
+ finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Moves to a certain message defined by timestamp (across pages)
+ */
+ protected void moveToPage() {
+ moveToPage(true);
+ }
+
+ /**
+ * Moves to a certain page.
+ *
+ * @param notifyAll true to broadcast time range signal to other signal handlers else false
+ */
+ protected void moveToPage(boolean notifyAll) {
+
+ TmfTimeRange window = null;
+
+ fLock.lock();
+ try {
+ // Safety check
+ if (fCurrentPage > fCheckPoints.size()) {
+ return;
+ }
+ window = fCheckPoints.get(fCurrentPage);
+ } finally {
+ fLock.unlock();
+ }
+
+ if (window == null) {
+ window = TmfTimeRange.ETERNITY;
+ }
+
+ fPageRequest = new TmfEventRequest(ITmfEvent.class, window, 0,
+ ITmfEventRequest.ALL_DATA, ITmfEventRequest.ExecutionType.FOREGROUND) {
+ private final List<ITmfSyncSequenceDiagramEvent> fSdEvent = new ArrayList<>();
+
+ @Override
+ public void handleData(ITmfEvent event) {
+ super.handleData(event);
+
+ ITmfSyncSequenceDiagramEvent sdEvent = getSequenceDiagramEvent(event);
+
+ if (sdEvent != null) {
+ fSdEvent.add(sdEvent);
+ }
+ }
+
+ @Override
+ public void handleSuccess() {
+ fillCurrentPage(fSdEvent);
+ super.handleSuccess();
+ }
+
+ };
+
+ fTrace.sendRequest(fPageRequest);
+
+ if (notifyAll) {
+ TmfTimeRange timeRange = getSignalTimeRange(window.getStartTime());
+ broadcast(new TmfRangeSynchSignal(this, timeRange));
+ }
+ }
+
+ /**
+ * Gets page that contains timestamp
+ *
+ * @param time The timestamp
+ * @return page that contains the time
+ * @since 2.0
+ */
+ protected int getPage(ITmfTimestamp time) {
+ int page;
+ int size;
+ fLock.lock();
+ try {
+ size = fCheckPoints.size();
+ for (page = 0; page < size; page++) {
+ TmfTimeRange timeRange = fCheckPoints.get(page);
+ if (timeRange.getEndTime().compareTo(time, false) >= 0) {
+ break;
+ }
+ }
+ if (page >= size) {
+ page = size - 1;
+ }
+ return page;
+ } finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Background search in trace for expression in criteria.
+ *
+ * @param findCriteria The find criteria
+ * @return true if background request was started else false
+ */
+ protected boolean findInNextPages(Criteria findCriteria) {
+ fLock.lock();
+ try {
+ if (fFindJob != null) {
+ return true;
+ }
+
+ int nextPage = fCurrentPage + 1;
+
+ if ((nextPage) >= fCheckPoints.size()) {
+ // we are at the end
+ return false;
+ }
+
+ TmfTimeRange window = new TmfTimeRange(fCheckPoints.get(nextPage).getStartTime(), fCheckPoints.get(fCheckPoints.size()-1).getEndTime());
+ fFindJob = new SearchJob(findCriteria, window);
+ fFindJob.schedule();
+ fView.toggleWaitCursorAsync(true);
+ } finally {
+ fLock.unlock();
+ }
+ return true;
+ }
+
+ /**
+ * Gets time range for time range signal.
+ *
+ * @param startTime The start time of time range.
+ * @return the time range
+ * @since 2.0
+ */
+ protected TmfTimeRange getSignalTimeRange(ITmfTimestamp startTime) {
+ fLock.lock();
+ try {
+ TmfTimeRange currentRange = TmfTraceManager.getInstance().getCurrentRange();
+ long offset = fTrace == null ? 0 : currentRange.getEndTime().getDelta(currentRange.getStartTime()).normalize(0, startTime.getScale()).getValue();
+ TmfTimestamp initialEndOfWindow = new TmfTimestamp(startTime.getValue() + offset, startTime.getScale(), startTime.getPrecision());
+ return new TmfTimeRange(startTime, initialEndOfWindow);
+ }
+ finally {
+ fLock.unlock();
+ }
+ }
+
+ /**
+ * Checks if filter criteria matches the message name in given SD event.
+ *
+ * @param sdEvent The SD event to check
+ * @return true if match else false.
+ */
+ protected boolean filterMessage(ITmfSyncSequenceDiagramEvent sdEvent) {
+ fLock.lock();
+ try {
+ if (fFilterCriteria != null) {
+ for(FilterCriteria criteria : fFilterCriteria) {
+ if (criteria.isActive() && criteria.getCriteria().isSyncMessageSelected() && criteria.getCriteria().matches(sdEvent.getName())) {
+ return true;
+ }
+ }
+ }
+ } finally {
+ fLock.unlock();
+ }
+ return false;
+ }
+
+ /**
+ * Checks if filter criteria matches a lifeline name (sender or receiver) in given SD event.
+ *
+ * @param lifeline the message receiver
+ * @return true if match else false.
+ */
+ protected boolean filterLifeLine(String lifeline) {
+ fLock.lock();
+ try {
+ if (fFilterCriteria != null) {
+ for(FilterCriteria criteria : fFilterCriteria) {
+ if (criteria.isActive() && criteria.getCriteria().isLifeLineSelected() && criteria.getCriteria().matches(lifeline)) {
+ return true;
+ }
+ }
+ }
+ } finally {
+ fLock.unlock();
+ }
+ return false;
+ }
+
+ /**
+ * Job to search in trace for given time range.
+ */
+ protected class SearchJob extends Job {
+
+ /**
+ * The search event request.
+ */
+ protected final SearchEventRequest fSearchRequest;
+
+ /**
+ * Constructor
+ *
+ * @param findCriteria The search criteria
+ * @param window Time range to search in
+ * @since 2.0
+ */
+ public SearchJob(Criteria findCriteria, TmfTimeRange window) {
+ super(Messages.TmfUml2SDSyncLoader_SearchJobDescrition);
+ fSearchRequest = new SearchEventRequest(window, ITmfEventRequest.ALL_DATA,
+ ITmfEventRequest.ExecutionType.FOREGROUND, findCriteria);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fSearchRequest.setMonitor(monitor);
+
+ fTrace.sendRequest(fSearchRequest);
+
+ try {
+ fSearchRequest.waitForCompletion();
+ } catch (InterruptedException e) {
+ Activator.getDefault().logError("Search request interrupted!", e); //$NON-NLS-1$
+ }
+
+ IStatus status = Status.OK_STATUS;
+ if (fSearchRequest.isFound() && (fSearchRequest.getFoundTime() != null)) {
+ fCurrentTime = fSearchRequest.getFoundTime();
+
+ // Avoid double-selection. Selection will be done when calling find(criteria)
+ // after moving to relevant page
+ fIsSelect = false;
+ if (!fView.getSDWidget().isDisposed()) {
+ fView.getSDWidget().getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ moveToMessage();
+ }
+ });
+ }
+ }
+ else {
+ if (monitor.isCanceled()) {
+ status = Status.CANCEL_STATUS;
+ }
+ else {
+ // String was not found
+ status = new Status(IStatus.WARNING, Activator.PLUGIN_ID, Messages.TmfUml2SDSyncLoader_SearchNotFound);
+ }
+ setProperty(IProgressConstants.KEEP_PROPERTY, Boolean.TRUE);
+ }
+ monitor.done();
+
+ fLock.lock();
+ try {
+ fView.toggleWaitCursorAsync(false);
+ fFindJob = null;
+ } finally {
+ fLock.unlock();
+ }
+
+ return status;
+ }
+
+ @Override
+ protected void canceling() {
+ fSearchRequest.cancel();
+ fLock.lock();
+ try {
+ fFindJob = null;
+ } finally {
+ fLock.unlock();
+ }
+ }
+ }
+
+ /**
+ * TMF event request for searching within trace.
+ */
+ protected class SearchEventRequest extends TmfEventRequest {
+
+ /**
+ * The find criteria.
+ */
+ private final Criteria fCriteria;
+ /**
+ * A progress monitor
+ */
+ private IProgressMonitor fMonitor;
+ /**
+ * Flag to indicate that node was found according the criteria .
+ */
+ private boolean fIsFound = false;
+ /**
+ * Time stamp of found item.
+ */
+ private ITmfTimestamp fFoundTime = null;
+
+ /**
+ * Constructor
+ * @param range @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#TmfEventRequest(...)
+ * @param nbRequested @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#handleData(...)
+ * @param execType @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#handleData(...)
+ * @param criteria The search criteria
+ */
+ public SearchEventRequest(TmfTimeRange range, int nbRequested, ExecutionType execType, Criteria criteria) {
+ this(range, nbRequested, execType, criteria, null);
+ }
+
+ /**
+ * Constructor
+ * @param range @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#TmfEventRequest(...)
+ * @param nbRequested @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#TmfEventRequest(...)
+ * @param execType @see org.eclipse.linuxtools.tmf.request.TmfEventRequest#TmfEventRequest(...)
+ * @param criteria The search criteria
+ * @param monitor progress monitor
+ */
+ public SearchEventRequest(TmfTimeRange range, int nbRequested, ExecutionType execType, Criteria criteria, IProgressMonitor monitor) {
+ super(ITmfEvent.class, range, 0, nbRequested, execType);
+ fCriteria = new Criteria(criteria);
+ fMonitor = monitor;
+ }
+
+ @Override
+ public void handleData(ITmfEvent event) {
+ super.handleData(event);
+
+ if ((fMonitor!= null) && fMonitor.isCanceled()) {
+ super.cancel();
+ return;
+ }
+
+ ITmfSyncSequenceDiagramEvent sdEvent = getSequenceDiagramEvent(event);
+
+ if (sdEvent != null) {
+
+ if (fCriteria.isLifeLineSelected()) {
+ if (fCriteria.matches(sdEvent.getSender())) {
+ fFoundTime = event.getTimestamp();
+ fIsFound = true;
+ super.cancel();
+ }
+
+ if (fCriteria.matches(sdEvent.getReceiver())) {
+ fFoundTime = event.getTimestamp();
+ fIsFound = true;
+ super.cancel();
+ }
+ }
+
+ if (fCriteria.isSyncMessageSelected() && fCriteria.matches(sdEvent.getName())) {
+ fFoundTime = event.getTimestamp();
+ fIsFound = true;
+ super.cancel();
+ }
+ }
+ }
+
+ /**
+ * Set progress monitor.
+ *
+ * @param monitor The monitor to assign
+ */
+ public void setMonitor(IProgressMonitor monitor) {
+ fMonitor = monitor;
+ }
+
+ /**
+ * Check if find criteria was met.
+ *
+ * @return true if find criteria was met.
+ */
+ public boolean isFound() {
+ return fIsFound;
+ }
+
+ /**
+ * Returns timestamp of found time.
+ *
+ * @return timestamp of found time.
+ * @since 2.0
+ */
+ public ITmfTimestamp getFoundTime() {
+ return fFoundTime;
+ }
+ }
+
+ /**
+ * Job class to provide progress monitor feedback.
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ *
+ */
+ protected static class IndexingJob extends Job {
+
+ /**
+ * @param name The job name
+ */
+ public IndexingJob(String name) {
+ super(name);
+ }
+
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ while (!monitor.isCanceled()) {
+ try {
+ Thread.sleep(INDEXING_THREAD_SLEEP_VALUE);
+ } catch (InterruptedException e) {
+ return Status.OK_STATUS;
+ }
+ }
+ monitor.done();
+ return Status.OK_STATUS;
+ }
+ }
+
+
+ /**
+ * Returns sequence diagram event if details in given event are available else null.
+ *
+ * @param tmfEvent Event to parse for sequence diagram event details
+ * @return sequence diagram event if details are available else null
+ * @since 2.0
+ */
+ protected ITmfSyncSequenceDiagramEvent getSequenceDiagramEvent(ITmfEvent tmfEvent){
+ //type = .*RECEIVE.* or .*SEND.*
+ //content = sender:<sender name>:receiver:<receiver name>,signal:<signal name>
+ String eventType = tmfEvent.getType().toString();
+ if (eventType.contains(Messages.TmfUml2SDSyncLoader_EventTypeSend) || eventType.contains(Messages.TmfUml2SDSyncLoader_EventTypeReceive)) {
+ Object sender = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldSender);
+ Object receiver = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldReceiver);
+ Object name = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldSignal);
+ if ((sender instanceof ITmfEventField) && (receiver instanceof ITmfEventField) && (name instanceof ITmfEventField)) {
+ ITmfSyncSequenceDiagramEvent sdEvent = new TmfSyncSequenceDiagramEvent(tmfEvent,
+ ((ITmfEventField) sender).getValue().toString(),
+ ((ITmfEventField) receiver).getValue().toString(),
+ ((ITmfEventField) name).getValue().toString());
+
+ return sdEvent;
+ }
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/messages.properties
new file mode 100644
index 0000000000..359c257e24
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/loader/messages.properties
@@ -0,0 +1,22 @@
+###############################################################################
+# Copyright (c) 2011, 2013 Ericsson
+#
+# All rights reserved. This program and the accompanying materials are
+# made available under the terms of the Eclipse Public License v1.0 which
+# accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Bernd Hufmann - Initial API and implementation
+###############################################################################
+TmfUml2SDSyncLoader_ViewName=Component Interactions
+TmfUml2SDSyncLoader_CategoryLifeline=Lifeline
+TmfUml2SDSyncLoader_CategoryMessage=Interaction
+TmfUml2SDSyncLoader_FrameName=Sequence Diagram
+TmfUml2SDSyncLoader_SearchJobDescrition=Searching in sequence diagram ...
+TmfUml2SDSyncLoader_EventTypeSend=SEND
+TmfUml2SDSyncLoader_EventTypeReceive=RECEIVE
+TmfUml2SDSyncLoader_FieldSender=sender
+TmfUml2SDSyncLoader_FieldReceiver=receiver
+TmfUml2SDSyncLoader_FieldSignal=signal
+TmfUml2SDSyncLoader_SearchNotFound=String not found!
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/ISDPreferences.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/ISDPreferences.java
new file mode 100755
index 0000000000..eda1e24a1a
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/ISDPreferences.java
@@ -0,0 +1,147 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IFont;
+
+/**
+ * Interface for accessing sequence diagram preferences.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public interface ISDPreferences {
+
+ /**
+ * The link font with zoom preference name
+ */
+ static final String PREF_LINK_FONT = "PREF_LINK_FONT"; //$NON-NLS-1$
+ /**
+ * The exclude preference time preference name
+ */
+ static final String PREF_EXCLUDE_EXTERNAL_TIME = "PREF_EXCLUDE_EXTERNAL_TIME"; //$NON-NLS-1$
+ /**
+ * The use gradient color preferences name
+ */
+ static final String PREF_USE_GRADIENT = "PREF_USE_GRADIENT"; //$NON-NLS-1$
+ /**
+ * The lifeline spacing width preference name
+ */
+ static final String PREF_LIFELINE_WIDTH = "PREF_LIFELINE_WIDTH"; //$NON-NLS-1$
+ /**
+ * The time compression bar font preference name
+ */
+ static final String PREF_TIME_COMP = "PREF_TIME_COMP"; //$NON-NLS-1$
+ /**
+ * The lifeline font preference name
+ */
+ static final String PREF_LIFELINE = "PREF_LIFELINE"; //$NON-NLS-1$
+ /**
+ * The frame font preference name
+ */
+ static final String PREF_FRAME = "PREF_FRAME"; //$NON-NLS-1$
+ /**
+ * The frame name font preference name
+ */
+ static final String PREF_FRAME_NAME = "PREF_FRAME_NAME"; //$NON-NLS-1$
+ /**
+ * The execution occurrence font preference name
+ */
+ static final String PREF_EXEC = "PREF_EXEC"; //$NON-NLS-1$
+ /**
+ * The synchronous message font preference name
+ */
+ static final String PREF_SYNC_MESS = "PREF_SYNC_MESS"; //$NON-NLS-1$
+ /**
+ * The synchronous message return font preference name
+ */
+ static final String PREF_SYNC_MESS_RET = "PREF_SYNC_MESS_RET"; //$NON-NLS-1$
+ /**
+ * The asynchronous message font preference name
+ */
+ static final String PREF_ASYNC_MESS = "PREF_ASYNC_MESS"; //$NON-NLS-1$
+ /**
+ * The asynchronous message return font preference name
+ */
+ static final String PREF_ASYNC_MESS_RET = "PREF_ASYNC_MESS_RET"; //$NON-NLS-1$
+ /**
+ * The lifeline header font (header = the always visible part of a lifeline)
+ */
+ static final String PREF_LIFELINE_HEADER = "PREF_LIFELINE_HEADER"; //$NON-NLS-1$
+ /**
+ * The enable tooltip preference name
+ */
+ static final String PREF_TOOLTIP = "PREF_TOOLTIP"; //$NON-NLS-1$
+
+ /**
+ * Returns the background color for the given preference name (font preference name)
+ *
+ * @param prefId The preference name
+ * @return the color
+ */
+ IColor getBackGroundColor(String prefId);
+
+ /**
+ * Returns the foreground color for the given preference name (font preference name)
+ *
+ * @param prefId A preference name
+ * @return the color
+ */
+ IColor getForeGroundColor(String prefId);
+
+ /**
+ * Returns the font color for the given preference name (font preference name)
+ *
+ * @param prefId A preference name
+ * @return the color
+ */
+ IColor getFontColor(String prefId);
+
+ /**
+ * Returns the font for the given preference name
+ *
+ * @param prefId the preference name
+ * @return the font
+ */
+ IFont getFont(String prefId);
+
+ /**
+ * Returns the time compression bar selection color
+ *
+ * @return the time compression bar selection color
+ */
+ IColor getTimeCompressionSelectionColor();
+
+ /**
+ * Returns the background color used to draw selection
+ *
+ * @return the background color
+ */
+ IColor getBackGroundColorSelection();
+
+ /**
+ * Returns the foreground color used to draw selection
+ *
+ * @return the foreground color
+ */
+ IColor getForeGroundColorSelection();
+
+ /**
+ * Returns whether to use gradient color or not
+ *
+ * @return whether to use gradient color or not
+ */
+ boolean useGradienColor();
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewPref.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewPref.java
new file mode 100755
index 0000000000..59f4aaf5af
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewPref.java
@@ -0,0 +1,527 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.preference.PreferenceConverter;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IColor;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.IFont;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl.ColorImpl;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.drawings.impl.FontImpl;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+
+/**
+ * This is the Sequence Diagram preference handler. This class is responsible for accessing the current user preferences
+ * selection This class also provider getters for each modifiable preferences.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDViewPref implements ISDPreferences, IPropertyChangeListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Postfix string for background color property
+ */
+ public static final String BACK_COLOR_POSTFIX = "_BACK_COLOR";//$NON-NLS-1$
+ /**
+ * Postfix string for foreground color property
+ */
+ public static final String FORE_COLOR_POSTFIX = "_FORE_COLOR";//$NON-NLS-1$
+ /**
+ * Postfix string for text color property
+ */
+ public static final String TEXT_COLOR_POSTFIX = "_TEXT_COLOR";//$NON-NLS-1$
+ /**
+ * Array of preference names
+ */
+ private static final String[] FONT_LIST = { PREF_LIFELINE, PREF_EXEC, PREF_SYNC_MESS, PREF_SYNC_MESS_RET, PREF_ASYNC_MESS, PREF_ASYNC_MESS_RET, PREF_FRAME, PREF_LIFELINE_HEADER, PREF_FRAME_NAME };
+ /**
+ * A 2nd array of preference names
+ */
+ private static final String[] FONT_LIST2 = { Messages.SequenceDiagram_Lifeline, Messages.SequenceDiagram_ExecutionOccurrence, Messages.SequenceDiagram_SyncMessage, Messages.SequenceDiagram_SyncMessageReturn, Messages.SequenceDiagram_AsyncMessage, Messages.SequenceDiagram_AsyncMessageReturn, Messages.SequenceDiagram_Frame, Messages.SequenceDiagram_LifelineHeader, Messages.SequenceDiagram_FrameTitle };
+ /**
+ * Array of background color preference names
+ */
+ private static final String[] PREF_BACK_COLOR_LIST = { PREF_LIFELINE, PREF_EXEC, PREF_FRAME, PREF_LIFELINE_HEADER, PREF_FRAME_NAME };
+ /**
+ * Array of foreground color preference names
+ */
+ private static final String[] PREF_FORE_COLOR_LIST = { PREF_LIFELINE, PREF_EXEC, PREF_SYNC_MESS, PREF_SYNC_MESS_RET, PREF_ASYNC_MESS, PREF_ASYNC_MESS_RET, PREF_FRAME, PREF_LIFELINE_HEADER, PREF_FRAME_NAME };
+ /**
+ * Array of text color preference names
+ */
+ private static final String[] PREF_TEXT_COLOR_LIST = { PREF_LIFELINE, PREF_SYNC_MESS, PREF_SYNC_MESS_RET, PREF_ASYNC_MESS, PREF_ASYNC_MESS_RET, PREF_LIFELINE_HEADER, PREF_FRAME_NAME };
+ /**
+ * Temporary tag
+ * @since 2.0
+ */
+ public static final String TEMP_TAG = "_TEMP";//$NON-NLS-1$
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+
+ /**
+ * The sequence diagram preferences singleton instance
+ */
+ private static SDViewPref fHandle = null;
+ /**
+ * Hashtable for font preferences
+ */
+ private Map<String, IFont> fFontPref;
+
+ /**
+ * Hashtable for foreground color preferences
+ */
+ private Map<String, IColor> fForeColorPref;
+ /**
+ * Hashtable for background color preferences
+ */
+ private Map<String, IColor> fBackColorPref;
+ /**
+ * Hashtable for text color preferences
+ */
+ private Map<String, IColor> fTextColorPref;
+ /**
+ * The reference to the preference store.
+ */
+ private IPreferenceStore fPrefStore = null;
+ /**
+ * Color for the time compression selection
+ */
+ private IColor fTimeCompressionSelectionColor = null;
+ /**
+ * Flag whether no focus selection or not.
+ */
+ private boolean fNoFocusSelection = false;
+
+ // ------------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------------
+
+ /**
+ * Builds the Sequence Diagram preference handler: - Define the preference default values. - Load the currently used
+ * preferences setting
+ */
+ protected SDViewPref() {
+ fPrefStore = Activator.getDefault().getPreferenceStore();
+
+ fPrefStore.setDefault(PREF_LINK_FONT, true);
+ fPrefStore.setDefault(PREF_EXCLUDE_EXTERNAL_TIME, true);
+ fPrefStore.setDefault(PREF_LIFELINE_WIDTH, 200);
+ fPrefStore.setDefault(PREF_USE_GRADIENT, true);
+ fPrefStore.setDefault(PREF_TOOLTIP, true);
+
+ fFontPref = new Hashtable<>();
+ fForeColorPref = new Hashtable<>();
+ fBackColorPref = new Hashtable<>();
+ fTextColorPref = new Hashtable<>();
+
+ for (int i = 0; i < FONT_LIST.length; i++) {
+ if (FONT_LIST[i].equals(PREF_FRAME_NAME)) {
+ FontData[] data = Display.getDefault().getSystemFont().getFontData();
+ data[0].setStyle(SWT.BOLD);
+ PreferenceConverter.setDefault(fPrefStore, FONT_LIST[i], data[0]);
+ PreferenceConverter.setDefault(fPrefStore, FONT_LIST[i] + TEMP_TAG, data[0]);
+ } else {
+ PreferenceConverter.setDefault(fPrefStore, FONT_LIST[i], Display.getDefault().getSystemFont().getFontData());
+ PreferenceConverter.setDefault(fPrefStore, FONT_LIST[i] + TEMP_TAG, Display.getDefault().getSystemFont().getFontData());
+ }
+ }
+
+ for (int i = 0; i < PREF_BACK_COLOR_LIST.length; i++) {
+ IColor color;
+ if ((PREF_BACK_COLOR_LIST[i].equals(PREF_EXEC)) || PREF_BACK_COLOR_LIST[i].equals(PREF_FRAME_NAME)) {
+ color = new ColorImpl(Display.getDefault(), 201, 222, 233);
+ } else if (PREF_BACK_COLOR_LIST[i].equals(PREF_LIFELINE)) {
+ color = new ColorImpl(Display.getDefault(), 220, 220, 220);
+ } else if (PREF_BACK_COLOR_LIST[i].equals(PREF_LIFELINE_HEADER)) {
+ color = new ColorImpl(Display.getDefault(), 245, 244, 244);
+ } else {
+ color = new ColorImpl(Display.getDefault(), 255, 255, 255);
+ }
+ PreferenceConverter.setDefault(fPrefStore, PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX, ((Color) color.getColor()).getRGB());
+ PreferenceConverter.setDefault(fPrefStore, PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX + TEMP_TAG, ((Color) color.getColor()).getRGB());
+ color.dispose();
+ }
+
+ for (int i = 0; i < PREF_FORE_COLOR_LIST.length; i++) {
+ IColor color;
+ if (PREF_FORE_COLOR_LIST[i].equals(PREF_LIFELINE)) {
+ color = new ColorImpl(Display.getDefault(), 129, 129, 129);
+ } else if (PREF_FORE_COLOR_LIST[i].equals(PREF_FRAME_NAME)) {
+ color = new ColorImpl(Display.getDefault(), 81, 153, 200);
+ } else if (PREF_FORE_COLOR_LIST[i].equals(PREF_LIFELINE_HEADER)) {
+ color = new ColorImpl(Display.getDefault(), 129, 127, 137);
+ } else {
+ color = new ColorImpl(Display.getDefault(), 134, 176, 212);
+ }
+ PreferenceConverter.setDefault(fPrefStore, PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX, ((Color) color.getColor()).getRGB());
+ PreferenceConverter.setDefault(fPrefStore, PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX + TEMP_TAG, ((Color) color.getColor()).getRGB());
+ color.dispose();
+ }
+
+ for (int i = 0; i < PREF_TEXT_COLOR_LIST.length; i++) {
+ IColor color;
+ if (PREF_TEXT_COLOR_LIST[i].equals(PREF_LIFELINE)) {
+ color = new ColorImpl(Display.getDefault(), 129, 129, 129);
+ } else if (PREF_TEXT_COLOR_LIST[i].equals(PREF_FRAME_NAME)) {
+ color = new ColorImpl(Display.getDefault(), 0, 0, 0);
+ } else if (PREF_TEXT_COLOR_LIST[i].equals(PREF_LIFELINE_HEADER)) {
+ color = new ColorImpl(Display.getDefault(), 129, 127, 137);
+ } else {
+ color = new ColorImpl(Display.getDefault(), 134, 176, 212);
+ }
+ PreferenceConverter.setDefault(fPrefStore, PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX, ((Color) color.getColor()).getRGB());
+ PreferenceConverter.setDefault(fPrefStore, PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX + TEMP_TAG, ((Color) color.getColor()).getRGB());
+ color.dispose();
+ }
+
+ IColor color = new ColorImpl(Display.getDefault(), 218, 232, 238);
+ PreferenceConverter.setDefault(fPrefStore, PREF_TIME_COMP, ((Color) color.getColor()).getRGB());
+ color.dispose();
+
+ buildFontsAndColors();
+
+ fPrefStore.addPropertyChangeListener(this);
+ }
+
+ /**
+ * Returns the PreferenceStore
+ *
+ * @return the PreferenceStore
+ */
+ public IPreferenceStore getPreferenceStore() {
+ return fPrefStore;
+ }
+
+ /**
+ * Apply the preferences in the preferences handler
+ */
+ public void apply() {
+ buildFontsAndColors();
+ fPrefStore.firePropertyChangeEvent("PREFOK", null, null); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns an unique instance of the Sequence Diagram preference handler
+ *
+ * @return the preference handler instance
+ */
+ public static synchronized SDViewPref getInstance() {
+ if (fHandle == null) {
+ fHandle = new SDViewPref();
+ }
+ return fHandle;
+ }
+
+ @Override
+ public IColor getForeGroundColor(String prefName) {
+ if ((fForeColorPref.get(prefName + FORE_COLOR_POSTFIX) != null) && (fForeColorPref.get(prefName + FORE_COLOR_POSTFIX) instanceof ColorImpl)) {
+ return fForeColorPref.get(prefName + FORE_COLOR_POSTFIX);
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ @Override
+ public IColor getBackGroundColor(String prefName) {
+ if ((fBackColorPref.get(prefName + BACK_COLOR_POSTFIX) != null) && (fBackColorPref.get(prefName + BACK_COLOR_POSTFIX) instanceof ColorImpl)) {
+ return fBackColorPref.get(prefName + BACK_COLOR_POSTFIX);
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_WHITE);
+ }
+
+ @Override
+ public IColor getFontColor(String prefName) {
+ if ((fTextColorPref.get(prefName + TEXT_COLOR_POSTFIX) != null) && (fTextColorPref.get(prefName + TEXT_COLOR_POSTFIX) instanceof ColorImpl)) {
+ return fTextColorPref.get(prefName + TEXT_COLOR_POSTFIX);
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_BLACK);
+ }
+
+ @Override
+ public IColor getForeGroundColorSelection() {
+ if (fNoFocusSelection) {
+ return ColorImpl.getSystemColor(SWT.COLOR_TITLE_INACTIVE_FOREGROUND);
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT);
+ }
+
+ @Override
+ public IColor getBackGroundColorSelection() {
+ if (fNoFocusSelection) {
+ return ColorImpl.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
+ }
+ return ColorImpl.getSystemColor(SWT.COLOR_LIST_SELECTION);
+ }
+
+ @Override
+ public IFont getFont(String prefName) {
+ if (fFontPref.get(prefName) != null) {
+ return fFontPref.get(prefName);
+ }
+ return FontImpl.getSystemFont();
+ }
+
+ /**
+ * Returns the SwimLane width chosen
+ *
+ * @return the SwimLane width
+ */
+ public int getLifelineWidth() {
+ return fPrefStore.getInt(PREF_LIFELINE_WIDTH);
+ }
+
+ /**
+ * Returns if font linkage with zoom has been chosen
+ *
+ * @return true if checked false otherwise
+ */
+ public boolean fontLinked() {
+ return fPrefStore.getBoolean(PREF_LINK_FONT);
+ }
+
+ /**
+ * Returns the tooltip enablement
+ *
+ * @return true if checked false otherwise
+ */
+ public boolean tooltipEnabled() {
+ return fPrefStore.getBoolean(PREF_TOOLTIP);
+ }
+
+ /**
+ * Return true if the user do not want to take external time (basically found and lost messages with time) into
+ * account in the min max computation
+ *
+ * @return true if checked false otherwise
+ */
+ public boolean excludeExternalTime() {
+ return fPrefStore.getBoolean(PREF_EXCLUDE_EXTERNAL_TIME);
+ }
+
+ @Override
+ public boolean useGradienColor() {
+ return fPrefStore.getBoolean(PREF_USE_GRADIENT);
+ }
+
+ @Override
+ public IColor getTimeCompressionSelectionColor() {
+ return fTimeCompressionSelectionColor;
+ }
+
+ /**
+ * Builds the new colors and fonts according the current user selection when the OK or Apply button is clicked
+ */
+ private void buildFontsAndColors() {
+
+ Display display = Display.getDefault();
+
+ for (int i = 0; i < FONT_LIST.length; i++) {
+ FontData fontData = PreferenceConverter.getFontData(fPrefStore, FONT_LIST[i]);
+ if (fFontPref.get(FONT_LIST[i]) != null) {
+ fFontPref.get(FONT_LIST[i]).dispose();
+ }
+ fFontPref.put(FONT_LIST[i], new FontImpl(display, fontData));
+ }
+
+ for (int i = 0; i < PREF_BACK_COLOR_LIST.length; i++) {
+ RGB rgb = PreferenceConverter.getColor(fPrefStore, PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX);
+ if (fBackColorPref.get(PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX) != null) {
+ fBackColorPref.get(PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX).dispose();
+ }
+ fBackColorPref.put(PREF_BACK_COLOR_LIST[i] + BACK_COLOR_POSTFIX, new ColorImpl(display, rgb.red, rgb.green, rgb.blue));
+ }
+
+ for (int i = 0; i < PREF_FORE_COLOR_LIST.length; i++) {
+ RGB rgb = PreferenceConverter.getColor(fPrefStore, PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX);
+ if (fForeColorPref.get(PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX) != null) {
+ fForeColorPref.get(PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX).dispose();
+ }
+ fForeColorPref.put(PREF_FORE_COLOR_LIST[i] + FORE_COLOR_POSTFIX, new ColorImpl(display, rgb.red, rgb.green, rgb.blue));
+ }
+
+ for (int i = 0; i < PREF_TEXT_COLOR_LIST.length; i++) {
+ RGB rgb = PreferenceConverter.getColor(fPrefStore, PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX);
+ if (fTextColorPref.get(PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX) != null) {
+ fTextColorPref.get(PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX).dispose();
+ }
+ fTextColorPref.put(PREF_TEXT_COLOR_LIST[i] + TEXT_COLOR_POSTFIX, new ColorImpl(display, rgb.red, rgb.green, rgb.blue));
+ }
+
+ RGB rgb = PreferenceConverter.getColor(fPrefStore, PREF_TIME_COMP);
+ if (fTimeCompressionSelectionColor != null) {
+ fTimeCompressionSelectionColor.dispose();
+ }
+ fTimeCompressionSelectionColor = new ColorImpl(display, rgb.red, rgb.green, rgb.blue);
+ }
+
+ /**
+ * Add a property-change listener
+ *
+ * @param listener
+ * The listener to add
+ */
+ public void addPropertyChangeListener(IPropertyChangeListener listener) {
+ fPrefStore.addPropertyChangeListener(listener);
+ }
+
+ /**
+ * Remove a property-change listener
+ *
+ * @param listener
+ * The listerner to remove
+ */
+ public void removePropertyChangeListener(IPropertyChangeListener listener) {
+ fPrefStore.removePropertyChangeListener(listener);
+ }
+
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ if (!event.getProperty().equals("PREFOK")) { //$NON-NLS-1$
+ buildFontsAndColors();
+ fPrefStore.firePropertyChangeEvent("PREFOK", null, null); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Set the "no focus selection" preference
+ *
+ * @param v
+ * New value to use
+ */
+ public void setNoFocusSelection(boolean v) {
+ fNoFocusSelection = v;
+ }
+
+ /**
+ * Returns a unmodifiable map with font preferences.
+ *
+ * @return map with font preferences
+ * @since 2.0
+ */
+ protected Map<String, IFont> getFontPref() {
+ return Collections.unmodifiableMap(fFontPref);
+ }
+
+ /**
+ * Returns a unmodifiable map with foreground color preferences
+ *
+ * @return map with foreground color preferences
+ * @since 2.0
+ */
+ public Map<String, IColor> getForeColorPref() {
+ return Collections.unmodifiableMap(fForeColorPref);
+ }
+
+ /**
+ * Returns a unmodifiable map with background color preferences
+ *
+ * @return map with background color preferences
+ * @since 2.0
+ */
+ public Map<String, IColor> getBackColorPref() {
+ return Collections.unmodifiableMap(fBackColorPref);
+ }
+
+ /**
+ * Returns a unmodifiable map with text color preferences
+ *
+ * @return map with text color preferences
+ * @since 2.0
+ */
+ public Map<String, IColor> getTextColorPref() {
+ return Collections.unmodifiableMap(fTextColorPref);
+ }
+
+ /**
+ * Returns the preference store.
+ *
+ * @return the preference store
+ * @since 2.0
+ */
+ public IPreferenceStore getPrefStore() {
+ return fPrefStore;
+ }
+
+ /**
+ * Returns flag about focus selection
+ *
+ * @return flag about focus selection
+ * @since 2.0
+ */
+ public boolean isNoFocusSelection() {
+ return fNoFocusSelection;
+ }
+
+ /**
+ * Returns the static font list.
+ *
+ * @return static font list
+ */
+ public static String[] getFontList() {
+ return Arrays.copyOf(FONT_LIST, FONT_LIST.length);
+ }
+
+ /**
+ * Returns the 2nd static font list.
+ *
+ * @return 2nd static font list
+ */
+ public static String[] getFontList2() {
+ return Arrays.copyOf(FONT_LIST2, FONT_LIST2.length);
+ }
+
+ /**
+ * Returns the preference background color list.
+ *
+ * @return preference background color list
+ */
+ public static String[] getPrefBackColorList() {
+ return Arrays.copyOf(PREF_BACK_COLOR_LIST, PREF_BACK_COLOR_LIST.length);
+ }
+
+ /**
+ * Returns the preference foreground color list.
+ *
+ * @return preference foreground color list
+ */
+ public static String[] getPrefForeColorList() {
+ return Arrays.copyOf(PREF_FORE_COLOR_LIST, PREF_FORE_COLOR_LIST.length);
+ }
+
+ /**
+ * Returns the preference text color list color list.
+ *
+ * @return preference text color list color list
+ */
+ public static String[] getPrefTextColorList() {
+ return Arrays.copyOf(PREF_TEXT_COLOR_LIST, PREF_TEXT_COLOR_LIST.length);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewerPage.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewerPage.java
new file mode 100755
index 0000000000..98ba43fef4
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/preferences/SDViewerPage.java
@@ -0,0 +1,431 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2014 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.preferences;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.ColorFieldEditor;
+import org.eclipse.jface.preference.FontFieldEditor;
+import org.eclipse.jface.preference.IntegerFieldEditor;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.List;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.Messages;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * The Sequence Diagram preferences page implementation.
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class SDViewerPage extends PreferencePage implements IWorkbenchPreferencePage, SelectionListener {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Temporary preferences tag
+ */
+ private static final String TEMP_TAG = SDViewPref.TEMP_TAG;
+
+ // ------------------------------------------------------------------------
+ // Attributes
+ // ------------------------------------------------------------------------
+ /**
+ * The preference handler used to access the PreferenceStore
+ */
+ private SDViewPref fPreferences = null;
+ /**
+ * BackGround color selector
+ */
+ private ColorFieldEditor fLineColor = null;
+ /**
+ * Foreground color selector
+ */
+ private ColorFieldEditor fBackGroundColor = null;
+ /**
+ * Font color selector
+ */
+ private ColorFieldEditor fTextColor = null;
+ /**
+ * List which display all modifiable sequence Diagram font
+ */
+ private List fClassItemList = null;
+ /**
+ * Font selector (The same is used for each modifiable font)
+ */
+ private FontFieldEditor fFont = null;
+ /**
+ * Link font when zooming selector
+ */
+ private BooleanFieldEditor fLink = null;
+ /**
+ * Enable tooltip selector
+ */
+ private BooleanFieldEditor fTooltip = null;
+ /**
+ * Do not take external time into account in the min max computation
+ */
+ private BooleanFieldEditor fNoExternalTime = null;
+ /**
+ * Use gradient color selector
+ */
+ private BooleanFieldEditor fUseGrad = null;
+ /**
+ * A button area.
+ */
+ private Composite fButtonArea;
+ /**
+ * SwimLane width selector
+ */
+ private IntegerFieldEditor fLifelineWidth = null;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ protected Control createContents(Composite parent) {
+ GridLayout gl = new GridLayout();
+ gl.marginHeight = 0;
+ gl.marginWidth = 0;
+ parent.setLayout(gl);
+ Composite page = new Composite(parent, SWT.NONE);
+ GridLayout pageLayout = new GridLayout();
+ pageLayout.numColumns = 2;
+ GridData pageLayoutdata = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ page.setLayoutData(pageLayoutdata);
+ page.setLayout(pageLayout);
+
+ fTooltip = new BooleanFieldEditor(ISDPreferences.PREF_TOOLTIP, Messages.SequenceDiagram_ShowTooltips, page);
+ fTooltip.setPreferenceStore(fPreferences.getPreferenceStore());
+ fTooltip.load();
+
+ // link font with zoom pref
+ fLink = new BooleanFieldEditor(ISDPreferences.PREF_LINK_FONT, Messages.SequenceDiagram_IncreaseFontSizeWhenZooming, page);
+ fLink.setPreferenceStore(fPreferences.getPreferenceStore());
+ fLink.load();
+
+ fNoExternalTime = new BooleanFieldEditor(ISDPreferences.PREF_EXCLUDE_EXTERNAL_TIME, Messages.SequenceDiagram_ExcludeExternalTime, page);
+ fNoExternalTime.setPreferenceStore(fPreferences.getPreferenceStore());
+ fNoExternalTime.load();
+
+ // use gradient color pref
+ fUseGrad = new BooleanFieldEditor(ISDPreferences.PREF_USE_GRADIENT, Messages.SequenceDiagram_UseGradientColor, page);
+ fUseGrad.setPreferenceStore(fPreferences.getPreferenceStore());
+ fUseGrad.load();
+
+ Label separator = new Label(page, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_NONE);
+ GridData sepData = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
+ separator.setLayoutData(sepData);
+
+ Composite prefPage = new Composite(page, SWT.NONE);
+ GridLayout prefPageLayout = new GridLayout();
+ prefPage.setLayoutData(pageLayoutdata);
+ prefPageLayout.numColumns = 1;
+ prefPage.setLayout(prefPageLayout);
+
+ // swimLane width pref
+ fLifelineWidth = new IntegerFieldEditor(ISDPreferences.PREF_LIFELINE_WIDTH, Messages.SequenceDiagram_LifelineWidth, prefPage);
+ fLifelineWidth.setPreferenceStore(fPreferences.getPreferenceStore());
+ fLifelineWidth.setValidRange(119, 500);
+ fLifelineWidth.load();
+
+ // not very nice
+ new Label(prefPage, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_NONE);
+ new Label(prefPage, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.SHADOW_NONE);
+
+ // Font list pref
+ fClassItemList = new List(prefPage, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
+ GridData tabItemLayoutdata = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ fClassItemList.setLayoutData(tabItemLayoutdata);
+
+ String[] fontList2 = SDViewPref.getFontList2();
+ for (int i = 0; i < fontList2.length; i++) {
+ fClassItemList.add(fontList2[i]);
+ }
+ fClassItemList.setSelection(0);
+ fClassItemList.addSelectionListener(this);
+ fButtonArea = new Composite(prefPage, SWT.NONE);
+ GridData tabItemLayoutdata2 = new GridData(GridData.HORIZONTAL_ALIGN_FILL/* |GridData.GRAB_HORIZONTAL */| GridData.GRAB_VERTICAL | GridData.VERTICAL_ALIGN_FILL);
+ fButtonArea.setLayoutData(tabItemLayoutdata2);
+ GridLayout buttonAreaLayout = new GridLayout();
+ buttonAreaLayout.numColumns = 1;
+ fButtonArea.setLayout(buttonAreaLayout);
+
+ // font selector initialise for the lifeline font pref
+ String[] fontList = SDViewPref.getFontList();
+ fFont = new FontFieldEditor(fontList[0], "",//$NON-NLS-1$
+ Messages.SequenceDiagram_AaBbYyZz, fButtonArea);
+ fFont.getPreviewControl().setSize(500, 500);
+ fFont.setPreferenceStore(fPreferences.getPreferenceStore());
+ fFont.load();
+
+ fBackGroundColor = new ColorFieldEditor(fontList[0] + SDViewPref.BACK_COLOR_POSTFIX, Messages.SequenceDiagram_Background, fButtonArea);
+ fBackGroundColor.setPreferenceStore(fPreferences.getPreferenceStore());
+ fBackGroundColor.load();
+
+ fLineColor = new ColorFieldEditor(fontList[0] + SDViewPref.FORE_COLOR_POSTFIX, Messages.SequenceDiagram_Lines, fButtonArea);
+ fLineColor.setPreferenceStore(fPreferences.getPreferenceStore());
+ fLineColor.load();
+
+ fTextColor = new ColorFieldEditor(fontList[0] + SDViewPref.TEXT_COLOR_POSTFIX, Messages.SequenceDiagram_Text, fButtonArea);
+ fTextColor.setPreferenceStore(fPreferences.getPreferenceStore());
+ fTextColor.load();
+ swapPref(true);
+ Dialog.applyDialogFont(page);
+
+ return page;
+ }
+
+ @Override
+ public void init(IWorkbench workbench) {
+ fPreferences = SDViewPref.getInstance();
+ }
+
+ @Override
+ protected void performApply() {
+ // Store the prefrences in the PreferenceStore
+ if (!fLifelineWidth.isValid()) {
+ fLifelineWidth.showErrorMessage();
+ return;
+ }
+ fFont.store();
+ fBackGroundColor.store();
+ fLineColor.store();
+ fLink.store();
+ fTooltip.store();
+ fNoExternalTime.store();
+ fTextColor.store();
+ fUseGrad.store();
+ fLifelineWidth.store();
+ swapPref(false);
+ // then save them in the preference file
+ fPreferences.apply();
+ swapPref(true);
+ }
+
+ @Override
+ public boolean performOk() {
+ performApply();
+ return true;
+ }
+
+ @Override
+ protected void performDefaults() {
+ fLink.loadDefault();
+ fTooltip.loadDefault();
+ fNoExternalTime.loadDefault();
+ fUseGrad.loadDefault();
+ fLifelineWidth.loadDefault();
+
+ // and all the fonts and colors
+ // fonts and colors are stored for each time because
+ // we are using only one FontFieldEditor
+ Set<String> keySet = SDViewPref.getInstance().getFontPref().keySet();
+ Iterator<String> it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fFont.setPreferenceName((String) prefName);
+ fFont.loadDefault();
+ fFont.setPreferenceName((String) prefName + TEMP_TAG);
+ fFont.store();
+ }
+ }
+
+ keySet = SDViewPref.getInstance().getBackColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fBackGroundColor.setPreferenceName((String) prefName);
+ fBackGroundColor.loadDefault();
+ fBackGroundColor.setPreferenceName((String) prefName + TEMP_TAG);
+ fBackGroundColor.store();
+ }
+
+ }
+
+ String[] fontList = SDViewPref.getFontList();
+ fBackGroundColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.BACK_COLOR_POSTFIX + TEMP_TAG);
+ fBackGroundColor.load();
+
+ keySet = SDViewPref.getInstance().getForeColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fLineColor.setPreferenceName((String) prefName);
+ fLineColor.loadDefault();
+ fLineColor.setPreferenceName((String) prefName + TEMP_TAG);
+ fLineColor.store();
+ }
+ }
+
+ fLineColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.FORE_COLOR_POSTFIX + TEMP_TAG);
+ fLineColor.load();
+
+ keySet = SDViewPref.getInstance().getTextColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fTextColor.setPreferenceName((String) prefName);
+ fTextColor.loadDefault();
+ fTextColor.setPreferenceName((String) prefName + TEMP_TAG);
+ fTextColor.store();
+ }
+ }
+ fTextColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.TEXT_COLOR_POSTFIX + TEMP_TAG);
+ fTextColor.load();
+ }
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ // Store the past set font preference or else the
+ // FontFieldEditor reassignment will make us loose the current modification
+ fFont.store();
+ fLineColor.store();
+ fBackGroundColor.store();
+ fTextColor.store();
+
+ String[] fontList = SDViewPref.getFontList();
+
+ // set the FontFieldEditor for the new selected graphNode font
+ fFont.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + TEMP_TAG);
+ fFont.load();
+
+ fBackGroundColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.BACK_COLOR_POSTFIX + TEMP_TAG);
+ fBackGroundColor.load();
+
+ fLineColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.FORE_COLOR_POSTFIX + TEMP_TAG);
+ fLineColor.load();
+
+ fTextColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.TEXT_COLOR_POSTFIX + TEMP_TAG);
+ fTextColor.load();
+
+ // No Background for message graphNodes
+ if ((fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_SYNC_MESS)) || (fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_SYNC_MESS_RET))
+ || (fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_ASYNC_MESS)) || (fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_ASYNC_MESS_RET))) {
+ fBackGroundColor.setEnabled(false, fButtonArea);
+ } else {
+ fBackGroundColor.setEnabled(true, fButtonArea);
+ }
+
+ // No font used for execution occurrence and global frame
+ if ((fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_EXEC)) || (fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_FRAME))) {
+ fTextColor.setEnabled(false, fButtonArea);
+ } else {
+ fTextColor.setEnabled(true, fButtonArea);
+ }
+
+ if (fontList[fClassItemList.getSelectionIndex()].equals(ISDPreferences.PREF_FRAME)) {
+ fFont.setEnabled(false, fButtonArea);
+ } else {
+ fFont.setEnabled(true, fButtonArea);
+ }
+ }
+
+ /**
+ * Swap viewer preferences.
+ *
+ * @param toTemp Switch to the temporary preferences
+ */
+ protected void swapPref(boolean toTemp) {
+ String tag1 = "";//$NON-NLS-1$
+ String tag2 = TEMP_TAG;
+ if (!toTemp) {
+ tag1 = TEMP_TAG;
+ tag2 = "";//$NON-NLS-1$
+ }
+ Set<String> keySet = SDViewPref.getInstance().getFontPref().keySet();
+ Iterator<String> it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fFont.setPreferenceName((String) prefName + tag1);
+ fFont.load();
+ fFont.setPreferenceName((String) prefName + tag2);
+ fFont.store();
+ }
+ }
+
+ keySet = SDViewPref.getInstance().getBackColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fBackGroundColor.setPreferenceName((String) prefName + tag1);
+ fBackGroundColor.load();
+ fBackGroundColor.setPreferenceName((String) prefName + tag2);
+ fBackGroundColor.store();
+ }
+ }
+
+ keySet = SDViewPref.getInstance().getForeColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fLineColor.setPreferenceName((String) prefName + tag1);
+ fLineColor.load();
+ fLineColor.setPreferenceName((String) prefName + tag2);
+ fLineColor.store();
+ }
+ }
+
+ keySet = SDViewPref.getInstance().getTextColorPref().keySet();
+ it = keySet.iterator();
+ while (it.hasNext()) {
+ Object prefName = it.next();
+ if (prefName instanceof String) {
+ fTextColor.setPreferenceName((String) prefName + tag1);
+ fTextColor.load();
+ fTextColor.setPreferenceName((String) prefName + tag2);
+ fTextColor.store();
+ }
+ }
+ String[] fontList = SDViewPref.getFontList();
+ if (toTemp) {
+ // set the FontFieldEditor for the new selected graphNode font
+ fFont.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + TEMP_TAG);
+ fFont.load();
+
+ fBackGroundColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.BACK_COLOR_POSTFIX + TEMP_TAG);
+ fBackGroundColor.load();
+
+ fLineColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.FORE_COLOR_POSTFIX + TEMP_TAG);
+ fLineColor.load();
+
+ fTextColor.setPreferenceName(fontList[fClassItemList.getSelectionIndex()] + SDViewPref.TEXT_COLOR_POSTFIX + TEMP_TAG);
+ fTextColor.load();
+ }
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/Messages.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/Messages.java
new file mode 100755
index 0000000000..0a7f99f150
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/Messages.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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
+ * Bernd Hufmann - Updated for TMF
+ * Alexandre Montplaisir - Renamed variables
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.util;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Messages related to the sequence diagram
+ *
+ * @version 1.0
+ * @author Bernd Hufmann
+ * @since 2.0
+ */
+@SuppressWarnings("javadoc")
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "org.eclipse.tracecompass.tmf.ui.views.uml2sd.util.messages"; //$NON-NLS-1$
+
+ private Messages() {
+ // Do not instantiate
+ }
+
+ public static String SequenceDiagram_LifelineNode;
+ public static String SequenceDiagram_MessageNode;
+ public static String SequenceDiagram_LostMessageNode;
+ public static String SequenceDiagram_FoundMessageNode;
+ public static String SequenceDiagram_ExecutionOccurrenceWithParams;
+
+ public static String SequenceDiagram_Find;
+ public static String SequenceDiagram_Close;
+ public static String SequenceDiagram_StringNotFound;
+ public static String SequenceDiagram_SequenceDiagramFind;
+ public static String SequenceDiagram_SearchFor;
+ public static String SequenceDiagram_MatchingString;
+ public static String SequenceDiagram_CaseSensitive;
+ public static String SequenceDiagram_Lifeline;
+ public static String SequenceDiagram_Stop;
+ public static String SequenceDiagram_SynchronousMessage;
+ public static String SequenceDiagram_SynchronousMessageReturn;
+ public static String SequenceDiagram_AsynchronousMessage;
+ public static String SequenceDiagram_AsynchronousMessageReturn;
+ public static String SequenceDiagram_or;
+ public static String SequenceDiagram_PreviousPage;
+ public static String SequenceDiagram_NextPage;
+ public static String SequenceDiagram_GoToPreviousPage;
+ public static String SequenceDiagram_GoToNextPage;
+ public static String SequenceDiagram_GoToMessage;
+ public static String SequenceDiagram_GoToMessageReturn;
+ public static String SequenceDiagram_EditFilters;
+ public static String SequenceDiagram_HidePatterns;
+ public static String SequenceDiagram_Pages;
+
+ public static String SequenceDiagram_ZoomIn;
+ public static String SequenceDiagram_ZoomInTheDiagram;
+ public static String SequenceDiagram_ResetZoomFactor;
+ public static String SequenceDiagram_ZoomOut;
+ public static String SequenceDiagram_ZoomOutTheDiagram;
+ public static String SequenceDiagram_Select;
+ public static String SequenceDiagram_Max;
+ public static String SequenceDiagram_Min;
+ public static String SequenceDiagram_ListOfHideDisplayPatterns;
+ public static String SequenceDiagram_hide;
+ public static String SequenceDiagram_display;
+ public static String SequenceDiagram_EditIt;
+ public static String SequenceDiagram_Add;
+ public static String SequenceDiagram_Create;
+ public static String SequenceDiagram_Update;
+ public static String SequenceDiagram_Remove;
+ public static String SequenceDiagram_SequenceDiagramHidePatterns;
+ public static String SequenceDiagram_DefinitionOfHidePattern;
+ public static String SequenceDiagram_PageNavigation;
+ public static String SequenceDiagram_SequenceDiagramPages;
+ public static String SequenceDiagram_IsInBetween;
+ public static String SequenceDiagram_Total;
+ public static String SequenceDiagram_pages;
+ public static String SequenceDiagram_page;
+
+ public static String SequenceDiagram_CurrentPage;
+
+ public static String SequenceDiagram_Navigation;
+ public static String SequenceDiagram_OpenOverviewTooltip;
+
+ public static String SequenceDiagram_LifelineWidth;
+ public static String SequenceDiagram_AaBbYyZz;
+ public static String SequenceDiagram_IncreaseFontSizeWhenZooming;
+ public static String SequenceDiagram_ExcludeExternalTime;
+ public static String SequenceDiagram_UseGradientColor;
+ public static String SequenceDiagram_Background;
+ public static String SequenceDiagram_Lines;
+ public static String SequenceDiagram_Text;
+
+ public static String SequenceDiagram_ExecutionOccurrence;
+ public static String SequenceDiagram_SyncMessage;
+ public static String SequenceDiagram_SyncMessageReturn;
+ public static String SequenceDiagram_AsyncMessage;
+ public static String SequenceDiagram_AsyncMessageReturn;
+ public static String SequenceDiagram_Frame;
+ public static String SequenceDiagram_LifelineHeader;
+ public static String SequenceDiagram_FrameTitle;
+ public static String SequenceDiagram_ShowTooltips;
+ public static String SequenceDiagram_Error;
+ public static String SequenceDiagram_InvalidRange;
+ public static String SequenceDiagram_InvalidNbVertical;
+ public static String SequenceDiagram_InvalidNbHorizontal;
+ public static String SequenceDiagram_NoPageSelected;
+ public static String SequenceDiagram_FromPage;
+
+ public static String SequenceDiagram_to;
+ public static String SequenceDiagram_SelectedPages;
+ public static String SequenceDiagram_CurrentView;
+ public static String SequenceDiagram_AllPages;
+ public static String TotalNumberOfPages;
+ public static String SequenceDiagram_NumberOfHorizontalPages;
+ public static String SequenceDiagram_NumberOfVerticalPages;
+ public static String SequenceDiagram_UseCurrentZoom;
+ public static String SequenceDiagram_ZoomOption;
+ public static String SequenceDiagram_Print;
+ public static String SequenceDiagram_Printer;
+ public static String SequenceDiagram_plus;
+ public static String SequenceDiagram_Page;
+ public static String SequenceDiagram_PrintRange;
+ public static String SequenceDiagram_Preview;
+
+ public static String SequenceDiagram_TimeCompressionBarConfig;
+ public static String SequenceDiagram_MinTime;
+ public static String SequenceDiagram_MaxTime;
+ public static String SequenceDiagram_Default;
+
+ public static String SequenceDiagram_NoPrinterSelected;
+ public static String SequenceDiagram_Scale;
+ public static String SequenceDiagram_Precision;
+ public static String SequenceDiagram_Delta;
+
+ public static String SequenceDiagram_FirstPage;
+ public static String SequenceDiagram_GoToFirstPage;
+ public static String SequenceDiagram_LastPage;
+ public static String SequenceDiagram_GoToLastPage;
+
+ public static String SequenceDiagram_ShowNodeEnd;
+ public static String SequenceDiagram_ShowNodeStart;
+ public static String SequenceDiagram_ConfigureMinMax;
+
+ static {
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncForBackward.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncForBackward.java
new file mode 100755
index 0000000000..004c23e8fa
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncForBackward.java
@@ -0,0 +1,96 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.util;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+
+/**
+ * Asynchronous message comparator.
+ *
+ * Compares two asyncMessages only taking into account the event occurrence when their
+ * appear.<br>
+ *
+ * Used to order the AsyncMessage list insuring that the previous node has both of his ends smaller than the current node
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SortAsyncForBackward implements Comparator<GraphNode>, Serializable {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = 603959931263853359L;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int compare(GraphNode arg0, GraphNode arg1) {
+ if (arg0 instanceof AsyncMessage && arg1 instanceof AsyncMessage) {
+ AsyncMessage m1 = (AsyncMessage) arg0;
+ AsyncMessage m2 = (AsyncMessage) arg1;
+ int m1Max, m2Max;
+ // AsyncMessage has two ends which may have different event occurrences
+ // Search for the greater event occurrence for each messages
+ if (m1.getStartOccurrence() > m1.getEndOccurrence()) {
+ m1Max = m1.getStartOccurrence();
+ } else {
+ m1Max = m1.getEndOccurrence();
+ }
+ if (m2.getStartOccurrence() > m2.getEndOccurrence()) {
+ m2Max = m2.getStartOccurrence();
+ } else {
+ m2Max = m2.getEndOccurrence();
+ }
+
+ int m1Min, m2Min;
+ // Search for the smaller event occurrence for each messages
+ if (m1.getStartOccurrence() > m1.getEndOccurrence()) {
+ m1Min = m1.getEndOccurrence();
+ } else {
+ m1Min = m1.getStartOccurrence();
+ }
+ if (m2.getStartOccurrence() > m2.getEndOccurrence()) {
+ m2Min = m2.getEndOccurrence();
+ } else {
+ m2Min = m2.getStartOccurrence();
+ }
+
+ if (m1Max > m2Max) {
+ return 1;
+ } else if (m1Max == m2Max) {
+ if (m1Min == m2Min) {
+ return 0;
+ } else if (m1Min > m2Min) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncMessageComparator.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncMessageComparator.java
new file mode 100755
index 0000000000..251eb46bbf
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortAsyncMessageComparator.java
@@ -0,0 +1,94 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.util;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.AsyncMessage;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+
+/**
+ * Asynchronous message comparator Compare two AsyncMessages only taking into account the event occurrence when their
+ * appear.<br>
+ *
+ * Used to order the AsyncMessage list insuring that next node has one of his ends greater than the current node
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SortAsyncMessageComparator implements Comparator<GraphNode>, Serializable {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = 1L;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int compare(GraphNode arg0, GraphNode arg1) {
+ if (arg0 instanceof AsyncMessage && arg1 instanceof AsyncMessage) {
+ AsyncMessage m1 = (AsyncMessage) arg0;
+ AsyncMessage m2 = (AsyncMessage) arg1;
+ int m1Min, m2Min;
+ // AsyncMessage has two ends which may have different event occurrences
+ // Search for the smaller event occurrence for each messages
+ if (m1.getStartOccurrence() > m1.getEndOccurrence()) {
+ m1Min = m1.getEndOccurrence();
+ } else {
+ m1Min = m1.getStartOccurrence();
+ }
+ if (m2.getStartOccurrence() > m2.getEndOccurrence()) {
+ m2Min = m2.getEndOccurrence();
+ } else {
+ m2Min = m2.getStartOccurrence();
+ }
+
+ int m1Max, m2Max;
+ // Search for the greater event occurrence for each messages
+ if (m1.getStartOccurrence() > m1.getEndOccurrence()) {
+ m1Max = m1.getStartOccurrence();
+ } else {
+ m1Max = m1.getEndOccurrence();
+ }
+ if (m2.getStartOccurrence() > m2.getEndOccurrence()) {
+ m2Max = m2.getStartOccurrence();
+ } else {
+ m2Max = m2.getEndOccurrence();
+ }
+
+ if (m1Min > m2Min) {
+ return 1;
+ } else if ((m1Min == m2Min)) {
+ if (m1Max == m2Max) {
+ return 0;
+ } else if (m1Max > m2Max) {
+ return -1;
+ } else {
+ return 1;
+ }
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortSyncMessageComparator.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortSyncMessageComparator.java
new file mode 100755
index 0000000000..a19d28b1f1
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/SortSyncMessageComparator.java
@@ -0,0 +1,61 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.util;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.GraphNode;
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SyncMessage;
+
+/**
+ * Synchronous message comparator Compare two syncMessages only taking into account the event occurrence when their
+ * appear.<br>
+ *
+ * The message with the greater event occurrence is considered to be the greater.<br>
+ *
+ * @version 1.0
+ * @author sveyrier
+ *
+ */
+public class SortSyncMessageComparator implements Comparator<GraphNode>, Serializable {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = 4781250984753283718L;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int compare(GraphNode arg0, GraphNode arg1) {
+ if (arg0 instanceof SyncMessage && arg1 instanceof SyncMessage) {
+ SyncMessage m1 = (SyncMessage) arg0;
+ SyncMessage m2 = (SyncMessage) arg1;
+ if (m1.getEventOccurrence() > m2.getEventOccurrence()) {
+ return 1;
+ } else if (m1.getEventOccurrence() == m2.getEventOccurrence()) {
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/TimeEventComparator.java b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/TimeEventComparator.java
new file mode 100755
index 0000000000..3c97af2df7
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/TimeEventComparator.java
@@ -0,0 +1,53 @@
+/**********************************************************************
+ * Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms 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 - Initial API and implementation
+ * Bernd Hufmann - Updated for TMF
+ **********************************************************************/
+
+package org.eclipse.tracecompass.tmf.ui.views.uml2sd.util;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+import org.eclipse.tracecompass.tmf.ui.views.uml2sd.core.SDTimeEvent;
+
+/**
+ * Time event comparator
+ *
+ * @version 1.0
+ * @author sveyrier
+ */
+public class TimeEventComparator implements Comparator<SDTimeEvent>, Serializable {
+
+ // ------------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------------
+
+ /**
+ * Serial version UID
+ */
+ private static final long serialVersionUID = 5885497718872575669L;
+
+ // ------------------------------------------------------------------------
+ // Methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public int compare(SDTimeEvent arg0, SDTimeEvent arg1) {
+ SDTimeEvent t1 = arg0;
+ SDTimeEvent t2 = arg1;
+ if (t1.getEvent() > t2.getEvent()) {
+ return 1;
+ }
+ else if (t1.getEvent() == t2.getEvent()) {
+ return 0;
+ }
+ return -1;
+ }
+}
diff --git a/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/messages.properties b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/messages.properties
new file mode 100755
index 0000000000..f8ef1c7c63
--- /dev/null
+++ b/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/uml2sd/util/messages.properties
@@ -0,0 +1,132 @@
+###############################################################################
+# Copyright (c) 2005, 2013 IBM Corporation, Ericsson
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms 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
+# Bernd Hufmann - Updated for TMF
+# Alexandre Montplaisir - Renamed variables
+###############################################################################
+
+# NLS_MESSAGEFORMAT_VAR
+# NLS_ENCODING=UTF-8
+
+##SD
+SequenceDiagram_LifelineNode=Lifeline node {0}
+SequenceDiagram_MessageNode=Message node {0} from Lifeline {1} at event occurrence {2} to Lifeline {3} at event occurrence {4}
+SequenceDiagram_LostMessageNode=Lost Message node {0} from Lifeline {1} at event occurrence {2}
+SequenceDiagram_FoundMessageNode=Found Message node {0} to Lifeline {1} at event occurrence {2}
+SequenceDiagram_ExecutionOccurrenceWithParams=Execution occurrence {0} on Lifeline {1} from event occurrence {2} to {3}
+
+SequenceDiagram_Find=Find
+SequenceDiagram_Close=Close
+SequenceDiagram_StringNotFound=String not found
+SequenceDiagram_SequenceDiagramFind=Sequence Diagram Find
+SequenceDiagram_SearchFor=Search for
+SequenceDiagram_MatchingString=Matching string (regular expression):
+SequenceDiagram_CaseSensitive=Case sensitive
+SequenceDiagram_Lifeline=Lifeline
+SequenceDiagram_Stop=Stop
+SequenceDiagram_SynchronousMessage=Synchronous message
+SequenceDiagram_SynchronousMessageReturn=Synchronous message return
+SequenceDiagram_AsynchronousMessage=Asynchronous message
+SequenceDiagram_AsynchronousMessageReturn=Asynchronous message return
+SequenceDiagram_or=or
+SequenceDiagram_PreviousPage=Previous page
+SequenceDiagram_NextPage=Next page
+SequenceDiagram_GoToPreviousPage=Go to previous page
+SequenceDiagram_GoToNextPage=Go to next page
+SequenceDiagram_GoToMessage=Go to message
+SequenceDiagram_GoToMessageReturn=Go to message return
+SequenceDiagram_EditFilters=Edit filters...
+SequenceDiagram_HidePatterns=Hide Patterns...
+SequenceDiagram_Pages=Pages...
+SequenceDiagram_ZoomIn=Zoom in
+SequenceDiagram_ZoomInTheDiagram=Zoom in the diagram
+SequenceDiagram_ResetZoomFactor=Reset zoom factor
+SequenceDiagram_ZoomOut=Zoom out
+SequenceDiagram_ZoomOutTheDiagram=Zoom out the diagram
+SequenceDiagram_Select=Select
+SequenceDiagram_Max=Max
+SequenceDiagram_Min=Min
+SequenceDiagram_ListOfHideDisplayPatterns=List of hide/display patterns
+SequenceDiagram_hide=hide
+SequenceDiagram_display=display
+SequenceDiagram_EditIt=Edit it
+SequenceDiagram_Add=Add...
+SequenceDiagram_Create=Create
+SequenceDiagram_Update=Update
+SequenceDiagram_Remove=Remove
+SequenceDiagram_SequenceDiagramHidePatterns=Sequence Diagram Hide Patterns
+SequenceDiagram_DefinitionOfHidePattern=Definition of Hide Pattern
+SequenceDiagram_PageNavigation=Page navigation
+SequenceDiagram_SequenceDiagramPages=Sequence Diagram Pages
+SequenceDiagram_IsInBetween={0,number} <= value <= {1,number}
+SequenceDiagram_Total=Total:
+SequenceDiagram_pages=pages
+SequenceDiagram_page=page
+SequenceDiagram_CurrentPage=Current page:
+SequenceDiagram_Navigation=Navigation
+SequenceDiagram_OpenOverviewTooltip=Click to open Overview\nDrag mouse to scroll\nUse Shift+Drag, Ctrl+Drag to scroll slower\nUse Shift+Ctrl+Drag to scroll very fine
+SequenceDiagram_LifelineWidth=&Lifeline Width (in pixels)
+SequenceDiagram_AaBbYyZz=AaBbYyZz
+SequenceDiagram_IncreaseFontSizeWhenZooming=&Increase font size when zooming
+SequenceDiagram_ExcludeExternalTime=&Exclude external time
+SequenceDiagram_UseGradientColor=&Use gradient color
+SequenceDiagram_Background=Background
+SequenceDiagram_Lines=Lines
+SequenceDiagram_Text=Text
+SequenceDiagram_ExecutionOccurrence=Execution Occurrence
+SequenceDiagram_SyncMessage=Sync Message
+SequenceDiagram_SyncMessageReturn=Sync Message Return
+SequenceDiagram_AsyncMessage=Async Message
+SequenceDiagram_AsyncMessageReturn=Async Message Return
+SequenceDiagram_Frame=Frame
+SequenceDiagram_LifelineHeader=Lifeline Header
+SequenceDiagram_FrameTitle=Frame Title
+SequenceDiagram_ShowTooltips=&Show tooltips
+SequenceDiagram_Error=Error
+SequenceDiagram_InvalidRange=Invalid range
+SequenceDiagram_InvalidNbVertical=Number of vertical pages is invalid
+SequenceDiagram_InvalidNbHorizontal=Number of horizontal pages is invalid
+SequenceDiagram_NoPageSelected=There is no page selected
+SequenceDiagram_FromPage=F&rom page
+SequenceDiagram_to=&to
+SequenceDiagram_SelectedPages=Selected pages
+SequenceDiagram_CurrentView=Current view
+SequenceDiagram_AllPages=&All pages
+TotalNumberOfPages=Total number of pages:
+SequenceDiagram_NumberOfHorizontalPages=Number of horizontal pages:
+SequenceDiagram_NumberOfVerticalPages=Number of vertical pages:
+SequenceDiagram_UseCurrentZoom=Use current zoom
+SequenceDiagram_ZoomOption=Zoom options
+SequenceDiagram_Print=Print
+SequenceDiagram_Printer=Printer...
+SequenceDiagram_plus={0} + {1}
+SequenceDiagram_Page=Page {0}
+SequenceDiagram_PrintRange=Print range
+SequenceDiagram_Preview=Preview
+
+SequenceDiagram_TimeCompressionBarConfig=TimeCompression bar configuration
+SequenceDiagram_MinTime=Min time
+SequenceDiagram_MaxTime=Max time
+SequenceDiagram_Default=Default
+
+SequenceDiagram_NoPrinterSelected=No default printer is selected. Click Printer button first and select a printer.
+
+SequenceDiagram_Scale=Scale
+SequenceDiagram_Precision=Precision
+SequenceDiagram_Delta=Delta
+
+SequenceDiagram_FirstPage=First page
+SequenceDiagram_GoToFirstPage=Go to first page
+SequenceDiagram_LastPage=Last page
+SequenceDiagram_GoToLastPage=Go to last page
+
+SequenceDiagram_ShowNodeEnd=Show the node end
+SequenceDiagram_ShowNodeStart=Show the node start
+SequenceDiagram_ConfigureMinMax=Configure Min Max...

Back to the top