PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Sources/Applications/Observatory/Monitor/ReactRT.Observatory.Monitor.TimelineControl/TimelineViewModel.cs

https://bitbucket.org/thedmi/reactrt
C# | 349 lines | 266 code | 80 blank | 3 comment | 19 complexity | 4a9d9e1e5f8bd9b81f0a770d64c5523b MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Collections.ObjectModel;
  6. using ReactRT.Observatory.Monitor.Domain;
  7. using GalaSoft.MvvmLight;
  8. using System.ComponentModel;
  9. using GalaSoft.MvvmLight.Command;
  10. using System.Windows.Input;
  11. using System.Collections.Specialized;
  12. using System.Windows.Media;
  13. using System.Windows;
  14. namespace ReactRT.Observatory.Monitor.TimelineControl {
  15. /// <summary>
  16. /// This is the main view-model of the timeline control.
  17. /// </summary>
  18. public class TimelineViewModel : ViewModelBase, ITimelinePositionTracker, ISessionInformationProvider {
  19. #region Private fields
  20. private Session _session;
  21. private readonly TimeConverter _timeConverter = new TimeConverter();
  22. private double _currentPosition = 0;
  23. #endregion
  24. public TimelineViewModel() {
  25. _timeConverter.PixelsPerMillisecond = 6;
  26. ZeroPointOffset = 1500;
  27. JumpToNewReactions = false;
  28. IsLiveTraceMode = false;
  29. ProgressIndicator = new ProgressIndicatorViewModel();
  30. Axis = new AxisViewModel(this, _timeConverter);
  31. }
  32. #region Events
  33. public event EventHandler<TimelinePositionChangedEventArgs> TimelinePositionChanged = delegate { };
  34. public event EventHandler<SessionDurationChangedEventArgs> SessionDurationChanged = delegate { };
  35. #endregion
  36. #region Properties
  37. public AxisViewModel Axis { get; private set; }
  38. public ProgressIndicatorViewModel ProgressIndicator { get; private set; }
  39. public ObservableCollection<StateMachineViewModel> StateMachines { get; private set; }
  40. public ObservableSortedSet<ReactionViewModel> AllReactions { get; private set; }
  41. public double ZeroPointOffset { get; private set; }
  42. public DateTime StartTime { get; private set; }
  43. public DateTime EndTime { get; private set; }
  44. public bool JumpToNewReactions { get; set; }
  45. private bool _hasReactions = false;
  46. public bool HasReactions {
  47. get {
  48. return _hasReactions;
  49. }
  50. private set {
  51. _hasReactions = value;
  52. RaisePropertyChanged("HasReactions");
  53. }
  54. }
  55. public Session ActiveSession {
  56. get {
  57. return _session;
  58. }
  59. set {
  60. ActivateNewSession(value);
  61. }
  62. }
  63. private bool _isLiveTraceActive = false;
  64. public bool IsLiveTraceActive {
  65. get {
  66. return _isLiveTraceActive;
  67. }
  68. set {
  69. _isLiveTraceActive = value;
  70. RaisePropertyChanged("IsLiveTraceActive");
  71. RaisePropertyChanged("LiveTraceStateMessage");
  72. RaisePropertyChanged("JumpToNewReactions");
  73. }
  74. }
  75. public string LiveTraceStateMessage {
  76. get {
  77. if (IsLiveTraceActive) {
  78. return "Live Trace in progress";
  79. } else {
  80. return "Live Trace stopped";
  81. }
  82. }
  83. }
  84. private bool _isLiveTraceMode = false;
  85. public bool IsLiveTraceMode {
  86. get {
  87. return _isLiveTraceMode;
  88. }
  89. set {
  90. _isLiveTraceMode = value;
  91. RaisePropertyChanged("IsLiveTraceMode");
  92. RaisePropertyChanged("SessionTypeMessage");
  93. }
  94. }
  95. public string SessionTypeMessage {
  96. get {
  97. if (_session == null) {
  98. return "";
  99. } else {
  100. if (IsLiveTraceMode) {
  101. return "Live Trace Session";
  102. } else {
  103. return "Replay Session";
  104. }
  105. }
  106. }
  107. }
  108. public TimeSpan SessionDuration {
  109. get {
  110. if (HasReactions) {
  111. return _timeConverter.ToRelativeTime(EndTime);
  112. } else {
  113. return TimeSpan.FromTicks(0);
  114. }
  115. }
  116. }
  117. public double SessionWidth {
  118. get {
  119. return _timeConverter.ToPixels(SessionDuration);
  120. }
  121. }
  122. public double CurrentPositionFraction {
  123. get {
  124. if (SessionDuration.Ticks > 0) {
  125. return Convert.ToDouble(CurrentTime.Ticks) / Convert.ToDouble(SessionDuration.Ticks);
  126. }
  127. return 0;
  128. }
  129. set {
  130. CurrentTime = TimeSpan.FromTicks(Convert.ToInt64(SessionDuration.Ticks * value));
  131. }
  132. }
  133. public double CurrentPosition {
  134. get {
  135. return _currentPosition;
  136. }
  137. set {
  138. _currentPosition = value;
  139. RaiseCurrentPositionChanged();
  140. }
  141. }
  142. public double CurrentScrollPosition {
  143. get {
  144. return CurrentPosition + ZeroPointOffset;
  145. }
  146. set {
  147. CurrentPosition = value - ZeroPointOffset;
  148. }
  149. }
  150. public TimeSpan CurrentTime {
  151. get {
  152. TimeSpan current = _timeConverter.ToTimeSpan(CurrentPosition);
  153. if (current < TimeSpan.FromTicks(0)) {
  154. return TimeSpan.FromTicks(0);
  155. }
  156. return current;
  157. }
  158. set {
  159. CurrentPosition = _timeConverter.ToPixels(value);
  160. }
  161. }
  162. #endregion
  163. #region Commands
  164. public RelayCommand NextCommand {
  165. get {
  166. return new RelayCommand(SkipToNextReaction);
  167. }
  168. }
  169. public RelayCommand PreviousCommand {
  170. get {
  171. return new RelayCommand(SkipToPreviousReaction);
  172. }
  173. }
  174. public RelayCommand StopLiveTracingCommand {
  175. get {
  176. return new RelayCommand(StopLiveTracing, () => IsLiveTraceActive);
  177. }
  178. }
  179. #endregion
  180. #region Public Methods
  181. public void OnLoaded() {
  182. CurrentTime = TimeSpan.FromTicks(0);
  183. }
  184. public void StopLiveTracing() {
  185. if (IsLiveTraceActive) {
  186. _session.RawEventLogProvider.Stop();
  187. IsLiveTraceActive = false;
  188. }
  189. }
  190. #endregion
  191. #region Helper Methods
  192. private void ActivateNewSession(Session newSession) {
  193. Reset();
  194. _session = newSession;
  195. ProgressIndicator.SetSession(_session);
  196. IsLiveTraceMode = !_session.IsReplaySession;
  197. IsLiveTraceActive = !_session.IsReplaySession;
  198. _session.StateMachines.ForEach(CreateStateMachineViewModel);
  199. }
  200. private void Reset() {
  201. HasReactions = false;
  202. JumpToNewReactions = false;
  203. _timeConverter.Reset();
  204. CurrentTime = TimeSpan.FromTicks(0);
  205. StateMachines = new ObservableCollection<StateMachineViewModel>();
  206. AllReactions = new ObservableSortedSet<ReactionViewModel>();
  207. RaisePropertyChanged("StateMachines");
  208. RaisePropertyChanged("AllReactions");
  209. RaiseSessionDurationChanged();
  210. }
  211. private void CreateStateMachineViewModel(StateMachine stateMachine) {
  212. StateMachineViewModel smvm = new StateMachineViewModel(stateMachine, this, _timeConverter);
  213. StateMachines.Add(smvm);
  214. smvm.ReactionViewModelCreated += (object sender, ReactionViewModelCreatedEventArgs e) => HandleReactionViewModelCreated(e.Reaction);
  215. }
  216. private void EstablishSessionStartReference(ReactionViewModel firstReaction) {
  217. StartTime = firstReaction.AbsoluteStartTime;
  218. EndTime = firstReaction.AbsoluteEndTime;
  219. _timeConverter.SetStartReference(StartTime);
  220. HasReactions = true;
  221. RaisePropertyChanged("StartTime");
  222. RaiseSessionDurationChanged();
  223. CurrentTime = TimeSpan.FromTicks(0);
  224. }
  225. private void HandleReactionViewModelCreated(ReactionViewModel rvm) {
  226. AllReactions.Add(rvm);
  227. if (!HasReactions) {
  228. EstablishSessionStartReference(rvm);
  229. }
  230. if (EndTime < rvm.AbsoluteEndTime) {
  231. EndTime = rvm.AbsoluteEndTime;
  232. RaiseSessionDurationChanged();
  233. }
  234. if (JumpToNewReactions) {
  235. CurrentPosition = rvm.Offset;
  236. }
  237. }
  238. private void SkipToNextReaction() {
  239. Func<ReactionViewModel, bool> laterThanCurrent = (ReactionViewModel rvm) => rvm.StartTime > CurrentTime + TimeSpan.FromMilliseconds(1);
  240. if (AllReactions.Count(laterThanCurrent) > 0) {
  241. CurrentTime = AllReactions.FirstOrDefault(laterThanCurrent).StartTime;
  242. } else {
  243. CurrentTime = SessionDuration;
  244. }
  245. }
  246. private void SkipToPreviousReaction() {
  247. Func<ReactionViewModel, bool> earlierThanCurrent = (ReactionViewModel rvm) => rvm.StartTime < CurrentTime - TimeSpan.FromMilliseconds(1);
  248. if (AllReactions.Count(earlierThanCurrent) > 0) {
  249. CurrentTime = AllReactions.LastOrDefault(earlierThanCurrent).StartTime;
  250. } else {
  251. CurrentTime = TimeSpan.FromTicks(0);
  252. }
  253. }
  254. private void RaiseSessionDurationChanged() {
  255. RaisePropertyChanged("EndTime");
  256. RaisePropertyChanged("SessionDuration");
  257. RaisePropertyChanged("SessionWidth");
  258. SessionDurationChanged(this, new SessionDurationChangedEventArgs(SessionDuration));
  259. }
  260. private void RaiseCurrentPositionChanged() {
  261. RaisePropertyChanged("CurrentPosition");
  262. RaisePropertyChanged("CurrentScrollPosition");
  263. RaisePropertyChanged("CurrentPositionFraction");
  264. RaisePropertyChanged("CurrentTime");
  265. TimelinePositionChanged(this, new TimelinePositionChangedEventArgs(CurrentPosition, CurrentTime));
  266. }
  267. #endregion
  268. }
  269. }