void IView.SetViewModel(IViewModel viewModel) { this.viewModel = viewModel; var itemsUpdater = Updaters.Create( () => viewModel.Items, items => { using (new ScopedGuard( () => { dropDownPanel.SuspendLayout(); updateLock = true; }, () => { dropDownPanel.ResumeLayout(); updateLock = false; } )) { UpdateToolStripControls(mainToolStripControls, items.FirstOrDefault()); var existingControls = dropDownPanel.Controls.OfType <ExtendedToolStrip>().ToList(); int idx = 0; foreach (var item in items) { var row = existingControls.LastOrDefault(); if (row != null) { existingControls.RemoveAt(existingControls.Count - 1); } else { row = new ExtendedToolStrip() { GripStyle = ToolStripGripStyle.Hidden, ImageScalingSize = mainToolStrip.ImageScalingSize, Font = mainToolStrip.Font, TabStop = true, }; row.Tag = AddToolStripControls(row); dropDownPanel.Controls.Add(row); dropDownPanel.Controls.SetChildIndex(row, 0); } var ctrls = (ToolStripControls)row.Tag; ctrls.dropdownBtnShowsList = (idx == 0) ? false : new bool?(); UpdateToolStripControls(ctrls, item); ++idx; } existingControls.ForEach(c => c.Dispose()); UpdateToolStripTextSizes(); } } ); viewModel.ChangeNotification.CreateSubscription(() => { itemsUpdater(); }); }
public StateInspectorPresenter( IView view, IStateInspectorVisualizerModel model, IUserNamesProvider shortNames, ILogSourcesManager logSources, LoadedMessages.IPresenter loadedMessagesPresenter, IBookmarks bookmarks, IModelThreads threads, IPresentersFacade presentersFacade, IClipboardAccess clipboardAccess, SourcesManager.IPresenter sourcesManagerPresenter, IColorTheme theme, IChangeNotification changeNotification ) { this.view = view; this.model = model; this.shortNames = shortNames; this.threads = threads; this.presentersFacade = presentersFacade; this.bookmarks = bookmarks; this.clipboardAccess = clipboardAccess; this.sourcesManagerPresenter = sourcesManagerPresenter; this.loadedMessagesPresenter = loadedMessagesPresenter; this.theme = theme; this.changeNotification = changeNotification.CreateChainedChangeNotification(initiallyActive: false); var annotationsVersion = 0; logSources.OnLogSourceAnnotationChanged += (sender, e) => { annotationsVersion++; changeNotification.Post(); }; var getAnnotationsMap = Selectors.Create( () => logSources.Items, () => annotationsVersion, (sources, _) => sources .Where(s => !s.IsDisposed && !string.IsNullOrEmpty(s.Annotation)) .ToImmutableDictionary(s => s, s => s.Annotation) ); VisualizerNode rootNode = new VisualizerNode(null, ImmutableList <VisualizerNode> .Empty, true, false, 0, ImmutableDictionary <ILogSource, string> .Empty); var updateRoot = Updaters.Create( () => model.Groups, getAnnotationsMap, (groups, annotationsMap) => rootNode = MakeRootNode(groups, OnNodeCreated, annotationsMap, rootNode) ); this.getRootNode = () => { updateRoot(); return(rootNode); }; this.updateRootNode = reducer => { var oldRoot = getRootNode(); var newRoot = reducer(oldRoot); if (oldRoot != newRoot) { rootNode = newRoot; changeNotification.Post(); } }; this.getSelectedNodes = Selectors.Create( getRootNode, (root) => { var result = ImmutableArray.CreateBuilder <VisualizerNode>(); void traverse(VisualizerNode n) { if (!n.HasSelectedNodes) { return; } if (n.IsSelected) { result.Add(n); } foreach (var c in n.Children) { traverse(c); } } traverse(root); return(result.ToImmutable()); } ); this.getSelectedInspectedObjects = Selectors.Create( getSelectedNodes, nodes => ImmutableArray.CreateRange(nodes.Select(n => n.InspectedObject)) ); this.getStateHistoryItems = Selectors.Create( getSelectedInspectedObjects, () => selectedHistoryEvents, MakeSelectedObjectHistory ); this.getIsHistoryItemBookmarked = Selectors.Create( () => bookmarks.Items, boormarksItems => { Predicate <IStateHistoryItem> result = (item) => { var change = (item as StateHistoryItem)?.Event; if (change == null || change.Output.LogSource.IsDisposed) { return(false); } var bmk = bookmarks.Factory.CreateBookmark( change.Trigger.Timestamp.Adjust(change.Output.LogSource.TimeOffsets), change.Output.LogSource.GetSafeConnectionId(), change.Trigger.StreamPosition, 0); var pos = boormarksItems.FindBookmark(bmk); return(pos.Item2 > pos.Item1); }; return(result); } ); this.getFocusedMessageInfo = () => loadedMessagesPresenter.LogViewerPresenter.FocusedMessage; this.getFocusedMessageEqualRange = Selectors.Create( getFocusedMessageInfo, focusedMessageInfo => { var cache = new Dictionary <IStateInspectorOutputsGroup, FocusedMessageEventsRange>(); Func <IStateInspectorOutputsGroup, FocusedMessageEventsRange> result = forGroup => { if (!cache.TryGetValue(forGroup, out FocusedMessageEventsRange eventsRange)) { eventsRange = new FocusedMessageEventsRange(focusedMessageInfo, forGroup.Events.CalcFocusedMessageEqualRange(focusedMessageInfo)); cache.Add(forGroup, eventsRange); } return(eventsRange); }; return(result); } ); this.getPaintNode = Selectors.Create( getFocusedMessageEqualRange, MakePaintNodeDelegate ); this.getFocusedMessagePositionInHistory = Selectors.Create( getStateHistoryItems, getFocusedMessageInfo, (changes, focusedMessage) => { return (focusedMessage == null ? null : new ListUtils.VirtualList <StateInspectorEvent>(changes.Length, i => changes[i].Event).CalcFocusedMessageEqualRange(focusedMessage)); } ); this.getCurrentTimeLabelText = Selectors.Create( getFocusedMessageInfo, focusedMsg => focusedMsg != null ? $"at {focusedMsg.Time}" : "" ); this.getCurrentProperties = Selectors.Create( getSelectedInspectedObjects, getFocusedMessageEqualRange, () => selectedProperty, MakeCurrentProperties ); this.getPropertyItems = Selectors.Create( getCurrentProperties, props => (IReadOnlyList <IPropertyListItem>)props.Cast <IPropertyListItem>().ToImmutableArray() ); this.getObjectsProperties = Selectors.Create( getCurrentProperties, props => (IReadOnlyList <KeyValuePair <string, object> >)props.Select(p => p.ToDataSourceItem()).ToImmutableArray() ); view.SetViewModel(this); }
void IView.SetViewModel(IViewModel viewModel) { this.viewModel = viewModel; var prototypeStringFormat = (StringFormat)StringFormat.GenericDefault.Clone(); prototypeStringFormat.SetTabStops(0, new float[] { 20 }); prototypeStringFormat.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces | StringFormatFlags.NoFontFallback; // this is to treat \0002 and \0003 as regular characters graphicsResources = new GraphicsResources(viewModel, fontData => new LJD.Font(GetFontFamily(fontData.Name).Name, ToFontEmSize(fontData.Size)), textFormat: new LJD.StringFormat(prototypeStringFormat), (error: new LJD.Image(Properties.Resources.ErrorLogSeverity), warn: new LJD.Image(Properties.Resources.WarnLogSeverity), bookmark: new LJD.Image(Properties.Resources.Bookmark), focusedMark: new LJD.Image(Properties.Resources.FocusedMsg)), () => new LJD.Graphics(this.CreateGraphics(), ownsGraphics: true) ); viewDrawing = new ViewDrawing( viewModel, graphicsResources, dpiScale: UIUtils.Dpi.Scale(1f), scrollPosXSelector: () => scrollPosXCache, viewWidthSelector: () => viewWidthCache ); viewWidthCache = this.ClientRectangle.Width; var viewUpdater = Updaters.Create( () => viewModel.ViewLines, () => viewModel.FocusedMessageMark, (_1, _2) => { Invalidate(); } ); var vScrollerUpdater = Updaters.Create( () => viewModel.VerticalScrollerPosition, value => { scrollBarsInfo.scrollSize.Height = value != null ? ScrollBarsInfo.virtualVScrollSize : 0; SetScrollPos(posY: (int)(value.GetValueOrDefault() * (double)(ScrollBarsInfo.virtualVScrollSize - ClientRectangle.Height + 1))); } ); var emptyViewMessageUpdater = Updaters.Create( () => viewModel.EmptyViewMessage, value => { if (emptyMessagesCollectionMessage == null) { Controls.Add(emptyMessagesCollectionMessage = new EmptyMessagesCollectionMessage { Dock = DockStyle.Fill }); } emptyMessagesCollectionMessage.Visible = value != null; emptyMessagesCollectionMessage.SetMessage(value ?? ""); } ); viewModel.ChangeNotification.CreateSubscription(() => { viewUpdater(); vScrollerUpdater(); emptyViewMessageUpdater(); }); }
void IView.SetViewModel(IViewModel viewModel) { this.viewModel = viewModel; this.Window.EnsureCreated(); treeViewController.OnExpand = viewModel.OnExpandNode; treeViewController.OnCollapse = viewModel.OnCollapseNode; treeViewController.OnSelect = viewModel.OnSelect; treeViewController.OnCreateView = (col, node) => { TreeNodeView view = (TreeNodeView)treeView.MakeView("view", this); if (view == null) { view = new TreeNodeView { owner = this, Identifier = "view", Menu = new NSMenu { Delegate = GetContextMenuDelegate() } } } ; view.Update(node); return(view); }; treeViewController.OnCreateRowView = (node) => { TreeRowView view = (TreeRowView)treeView.MakeView("row", this); if (view == null) { view = new TreeRowView { owner = this, Identifier = "row" } } ; view.Update(node); return(view); }; treeViewController.OnUpdateRowView = (rowView, node) => { ((TreeRowView)rowView).Update(node); }; stateHistoryController.OnSelect = items => viewModel.OnChangeHistoryChangeSelection(items); stateHistoryController.OnCreateView = (historyItem, tableColumn) => { NSTextField MakeTextField(string viewId) { NSTextField view = (NSTextField)stateHistoryView.MakeView(viewId, this); if (view == null) { view = new NSTextField() { Identifier = viewId, Editable = false, Selectable = false, Bordered = false, BackgroundColor = NSColor.Clear }; view.Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; } return(view); } if (tableColumn == HistoryItemTimeColumn) { var view = MakeTextField("timeView"); view.StringValue = historyItem.Time; return(view); } else if (tableColumn == HistoryItemTextColumn) { var view = MakeTextField("messageView"); view.StringValue = historyItem.Message; return(view); } return(null); }; stateHistoryController.OnUpdateView = (item, tableColumn, view, oldItem) => { if (tableColumn == HistoryItemTimeColumn) { ((NSTextField)view).StringValue = item.Time; } else if (tableColumn == HistoryItemTextColumn) { ((NSTextField)view).StringValue = item.Message; } }; stateHistoryController.OnCreateRowView = (item, rowIndex) => { return(new StateHistoryTableRowView { owner = this, row = rowIndex, items = viewModel.ChangeHistoryItems }); }; var updateTree = Updaters.Create( () => viewModel.ObjectsTreeRoot, treeViewController.Update ); var invalidateTree = Updaters.Create( () => viewModel.PaintNode, () => viewModel.ColorTheme, (_1, _2) => InvalidateTree() ); var updateStateHistory = Updaters.Create( () => viewModel.ChangeHistoryItems, items => { stateHistoryController.Update(items); UpdateStateHistoryTimeColumn(items); } ); var invalidateStateHistory = Updaters.Create( () => viewModel.IsChangeHistoryItemBookmarked, () => viewModel.FocusedMessagePositionInChangeHistory, (_1, _2) => InvalidateStateHistoryTableView() ); var updateProperties = Updaters.Create( () => viewModel.ObjectsProperties, properties => { propsDataSource.data = properties; propertiesView.ReloadData(); } ); var updateCurrentTime = Updaters.Create( () => viewModel.CurrentTimeLabelText, timeValue => currentTimeLabel.StringValue = timeValue ); viewModel.ChangeNotification.CreateSubscription(() => { updateTree(); invalidateTree(); updateStateHistory(); invalidateStateHistory(); updateProperties(); updateCurrentTime(); }); } void IView.Show() { ShowInternal(); } void IView.ScrollStateHistoryItemIntoView(int itemIndex) { var items = viewModel.ChangeHistoryItems; if (items.Count == 0) { return; } stateHistoryView.ScrollRowToVisible(RangeUtils.PutInRange(0, items.Count - 1, itemIndex)); } void InvalidateTree() { treeView.NeedsDisplay = true; var rows = treeView.RowsInRect(treeView.VisibleRect()); for (var r = 0; r < rows.Length; ++r) { var rv = treeView.GetRowView(r + rows.Location, false); if (rv != null) { rv.NeedsDisplay = true; } var nv = treeView.GetView(0, r + rows.Location, false); if (nv != null) { nv.NeedsDisplay = true; } } } void UpdateStateHistoryTimeColumn(IReadOnlyList <IStateHistoryItem> items) { var widestCell = items.Select( (item, idx) => (item, idx) ).MaxByKey( i => i.item.Time.Length ); if (widestCell.item != null) { var cellView = (NSTextField)stateHistoryView.GetView(1, widestCell.idx, makeIfNecessary: true); cellView.SizeToFit(); historyItemTimeColumn.Width = cellView.Frame.Width + 10; } else { historyItemTimeColumn.Width = 0; } } void Presenters.Postprocessing.IPostprocessorVisualizerPresenter.Show() { ShowInternal(); }
void IView.SetViewModel(IViewModel viewModel) { this.EnsureCreated(); this.viewModel = viewModel; var fontSz = (NSFont.SystemFontSize + NSFont.SmallSystemFontSize) / 2f; this.resources = new Resources( viewModel, NSFont.SystemFontOfSize(NSFont.SystemFontSize).FamilyName, (float)fontSz) { BookmarkImage = new LJD.Image(NSImage.ImageNamed("Bookmark.png")), FocusedMessageImage = new LJD.Image(NSImage.ImageNamed("FocusedMsgSlave.png")), FocusedMsgSlaveVert = new LJD.Image(NSImage.ImageNamed("FocusedMsgSlaveVert.png")) }; this.drawingUtils = new DrawingUtils(viewModel, resources); var notificationsIconUpdater = Updaters.Create( () => viewModel.IsNotificationsIconVisibile, value => activeNotificationsButton.Hidden = !value ); var updateCurrentArrowControls = Updaters.Create( () => viewModel.CurrentArrowInfo, value => { arrowNameTextField.StringValue = value.Caption; arrowDetailsLink.StringValue = value.DescriptionText; arrowDetailsLink.Links = (value.DescriptionLinks ?? Enumerable.Empty <Tuple <object, int, int> >()) .Select(l => new NSLinkLabel.Link(l.Item2, l.Item3, l.Item1)).ToArray(); } ); var updateCollapseResponsesCheckbox = Updaters.Create( () => viewModel.IsCollapseResponsesChecked, value => collapseResponsesCheckbox.State = value ? NSCellStateValue.On : NSCellStateValue.Off ); var updateCollapseRoleInstancesCheckbox = Updaters.Create( () => viewModel.IsCollapseRoleInstancesChecked, value => collapseRoleInstancesCheckbox.State = value ? NSCellStateValue.On : NSCellStateValue.Off); var scrollBarsUpdater = Updaters.Create( () => viewModel.ScrollInfo, value => UpdateScrollBars(value.vMax, value.vChange, value.vValue, value.hMax, value.hChange, value.hValue) ); var invalidateViews = Updaters.Create( () => viewModel.RolesDrawInfo, () => viewModel.ArrowsDrawInfo, (_1, _2) => { rolesCaptionsView.NeedsDisplay = true; arrowsView.NeedsDisplay = true; leftPanelView.NeedsDisplay = true; } ); viewModel.ChangeNotification.CreateSubscription(() => { notificationsIconUpdater(); updateCurrentArrowControls(); updateCollapseResponsesCheckbox(); updateCollapseRoleInstancesCheckbox(); scrollBarsUpdater(); invalidateViews(); }); }
public override void AwakeFromNib() { base.AwakeFromNib(); Window.owner = this; var sysFont = NSFont.SystemFontOfSize(NSFont.SystemFontSize); res = new Lazy <GraphicsResources> (() => new GraphicsResources( model, sysFont.FamilyName, (float)NSFont.SystemFontSize, (float)NSFont.SmallSystemFontSize, (float)NSFont.SmallSystemFontSize, new LJD.Image(NSImage.ImageNamed("UserAction.png")), new LJD.Image(NSImage.ImageNamed("APICall.png")), new LJD.Image(NSImage.ImageNamed("TimelineBookmark.png")), new LJD.Image(NSImage.ImageNamed("FocusedMsgSlaveVert.png")), 1f, new LJD.Brush(Color.FromArgb(235, 235, 235)) )); drawing = new Lazy <ControlDrawing> (() => new ControlDrawing(res.Value)); activitiesView.PostsFrameChangedNotifications = true; captionsView.PostsFrameChangedNotifications = true; NSNotificationCenter.DefaultCenter.AddObserver(NSView.FrameChangedNotification, ns => { UpdateVertScroller(); }, activitiesView); PlaceToastNotificationsView(toastNotifications.View, activitiesView); activitiesView.BackgroundColor = NSColor.TextBackground; activitiesView.CanBeFirstResponder = true; activitiesView.OnPaint = DrawActivitiesView; activitiesView.OnScrollWheel = ActivitiesViewScrollWheel; activitiesView.OnMagnify = ActivitiesViewMagnify; activitiesView.OnMouseDown = e => model.OnMouseDown(new HitTestToken(activitiesView, e), GetModifiers(e), e.ClickCount == 2); activitiesView.OnMouseUp = e => model.OnMouseUp(new HitTestToken(activitiesView, e)); activitiesView.OnMouseMove = e => { SetActivitiesCursor(e); SetActivitiesToolTip(e); model.OnMouseMove(new HitTestToken(activitiesView, e), GetModifiers(e)); }; activitiesView.OnMouseLeave = e => NSCursor.ArrowCursor.Set(); activitiesView.OnMouseDragged = activitiesView.OnMouseMove; captionsView.BackgroundColor = NSColor.TextBackground; captionsView.CanBeFirstResponder = true; captionsView.OnPaint = DrawCaptionsView; captionsView.OnMouseDown = e => model.OnMouseDown(new HitTestToken(captionsView, e), GetModifiers(e), e.ClickCount == 2); captionsView.OnMouseUp = e => model.OnMouseUp(new HitTestToken(captionsView, e)); activityDetailsLabel.BackgroundColor = NSColor.TextBackground; activityDetailsLabel.LinkClicked = (s, e) => model.OnActivityTriggerClicked(e.Link.Tag); activityLogSourceLabel.BackgroundColor = NSColor.TextBackground; activityLogSourceLabel.LinkClicked = (s, e) => model.OnActivitySourceLinkClicked(e.Link.Tag); navigatorView.OnPaint = DrawNavigationPanel; navigatorView.OnMouseDown = e => model.OnMouseDown(new HitTestToken(navigatorView, e), GetModifiers(e), e.ClickCount == 2); navigatorView.OnMouseUp = e => model.OnMouseUp(new HitTestToken(navigatorView, e)); navigatorView.OnMouseMove = (e) => { SetNavigationCursor(e); model.OnMouseMove(new HitTestToken(navigatorView, e), GetModifiers(e)); }; navigatorView.OnMouseDragged = navigatorView.OnMouseMove; navigatorView.OnMouseLeave = e => NSCursor.ArrowCursor.Set(); vertScroller.Action = new Selector("OnVertScrollChanged"); vertScroller.Target = this; tagsListController.View.MoveToPlaceholder(tagsSelectorPlacefolder); quickSearchTextBox.View.MoveToPlaceholder(searchTextBoxPlaceholder); Window.InitialFirstResponder = activitiesView; var updateNotificationsButton = Updaters.Create(() => model.NotificationsIconVisibile, v => activeNotificationsButton.Hidden = !v); var updateNoContentMessage = Updaters.Create(() => model.NoContentMessageVisibile, SetNoContentMessageVisibility); var updateVertScroller = Updaters.Create(() => model.ActivitiesCount, _ => UpdateVertScroller()); var updateCurrentActivityInfo = Updaters.Create(() => model.CurrentActivity, UpdateCurrentActivityControls); changeNotification.CreateSubscription(() => { updateNotificationsButton(); updateNoContentMessage(); updateVertScroller(); updateCurrentActivityInfo(); }); Window.WillClose += (s, e) => model.OnWindowHidden(); }