Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Common/Plotter.cs @ 13808

Last change on this file since 13808 was 12503, checked in by aballeit, 9 years ago

#2283 added GUI and charts; fixed MCTS

File size: 20.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Collections.Specialized;
4using System.ComponentModel;
5using System.Diagnostics;
6using System.IO;
7using System.Linq;
8using System.Windows;
9using System.Windows.Automation.Peers;
10using System.Windows.Controls;
11using System.Windows.Markup;
12using System.Windows.Media.Imaging;
13using Microsoft.Research.DynamicDataDisplay.Common;
14using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
15using Microsoft.Research.DynamicDataDisplay.Common.UndoSystem;
16using Microsoft.Research.DynamicDataDisplay.Navigation;
17
18namespace Microsoft.Research.DynamicDataDisplay
19{
20  /// <summary>Plotter is a base control for displaying various graphs. It provides
21  /// means to draw chart itself and side space for axes, annotations, etc</summary>
22  [ContentProperty("Children")]
23  [TemplatePart(Name = "PART_HeaderPanel", Type = typeof(StackPanel))]
24  [TemplatePart(Name = "PART_FooterPanel", Type = typeof(StackPanel))]
25
26  [TemplatePart(Name = "PART_BottomPanel", Type = typeof(StackPanel))]
27  [TemplatePart(Name = "PART_LeftPanel", Type = typeof(StackPanel))]
28  [TemplatePart(Name = "PART_RightPanel", Type = typeof(StackPanel))]
29  [TemplatePart(Name = "PART_TopPanel", Type = typeof(StackPanel))]
30
31  [TemplatePart(Name = "PART_MainCanvas", Type = typeof(Canvas))]
32  [TemplatePart(Name = "PART_CentralGrid", Type = typeof(Grid))]
33  [TemplatePart(Name = "PART_MainGrid", Type = typeof(Grid))]
34  [TemplatePart(Name = "PART_ContentsGrid", Type = typeof(Grid))]
35  [TemplatePart(Name = "PART_ParallelCanvas", Type = typeof(Canvas))]
36  public abstract class Plotter : ContentControl
37  {
38    private PlotterLoadMode loadMode = PlotterLoadMode.Normal;
39    protected PlotterLoadMode LoadMode
40    {
41      get { return loadMode; }
42    }
43
44    private static Plotter current;
45    /// <summary>
46    /// Gets the current plotter. Used in VisualDebug.
47    /// </summary>
48    /// <value>The current.</value>
49    internal static Plotter Current
50    {
51      get { return Plotter.current; }
52    }
53
54    protected Plotter() : this(PlotterLoadMode.Normal) { }
55
56    /// <summary>
57    /// Initializes a new instance of the <see cref="Plotter"/> class.
58    /// </summary>
59    protected Plotter(PlotterLoadMode loadMode)
60    {
61      current = this;
62
63      this.loadMode = loadMode;
64
65      SetPlotter(this, this);
66
67      if (loadMode == PlotterLoadMode.Normal)
68      {
69        UpdateUIParts();
70      }
71
72      children = new PlotterChildrenCollection(this);
73      children.CollectionChanged += OnChildrenCollectionChanged;
74      Loaded += Plotter_Loaded;
75      Unloaded += Plotter_Unloaded;
76
77      genericResources = (ResourceDictionary)Application.LoadComponent(new Uri("/DynamicDataDisplay;component/Themes/Generic.xaml", UriKind.Relative));
78
79      ContextMenu = null;
80
81      foreach (var panel in GetAllPanels().Where(panel => panel != null))
82      {
83        Plotter.SetIsDefaultPanel(panel, true);
84      }
85    }
86
87    private void Plotter_Unloaded(object sender, RoutedEventArgs e)
88    {
89      OnUnloaded();
90    }
91
92    protected virtual void OnUnloaded() { }
93
94    protected override AutomationPeer OnCreateAutomationPeer()
95    {
96      return new PlotterAutomationPeer(this);
97    }
98
99    [EditorBrowsable(EditorBrowsableState.Never)]
100    public override bool ShouldSerializeContent()
101    {
102      return false;
103    }
104
105    protected override bool ShouldSerializeProperty(DependencyProperty dp)
106    {
107      // do not serialize context menu if it was created by DefaultContextMenu, because that context menu items contains references of plotter
108      if (dp == ContextMenuProperty && children.Any(el => el is DefaultContextMenu)) return false;
109      if (dp == TemplateProperty) return false;
110      if (dp == ContentProperty) return false;
111
112      return base.ShouldSerializeProperty(dp);
113    }
114
115    private const string templateKey = "defaultPlotterTemplate";
116    private const string styleKey = "defaultPlotterStyle";
117    private void UpdateUIParts()
118    {
119      ResourceDictionary dict = new ResourceDictionary
120      {
121        Source = new Uri("/DynamicDataDisplay;component/Common/PlotterStyle.xaml", UriKind.Relative)
122      };
123
124      Resources.MergedDictionaries.Add(dict);
125
126      Style = (Style)dict[styleKey];
127
128      ControlTemplate template = (ControlTemplate)dict[templateKey];
129      Template = template;
130      ApplyTemplate();
131    }
132
133    private ResourceDictionary genericResources;
134    protected ResourceDictionary GenericResources
135    {
136      get { return genericResources; }
137    }
138
139    /// <summary>
140    /// Forces plotter to load.
141    /// </summary>
142    public void PerformLoad()
143    {
144      isLoadedIntensionally = true;
145      ApplyTemplate();
146
147      Plotter_Loaded(null, null);
148    }
149
150    private bool isLoadedIntensionally = false;
151    protected virtual bool IsLoadedInternal
152    {
153      get { return isLoadedIntensionally || IsLoaded; }
154    }
155
156    private void Plotter_Loaded(object sender, RoutedEventArgs e)
157    {
158      ExecuteWaitingChildrenAdditions();
159
160      OnLoaded();
161    }
162
163    protected internal void ExecuteWaitingChildrenAdditions()
164    {
165      executedWaitingChildrenAdding = true;
166
167      foreach (var pair in waitingForExecute)
168      {
169        pair.Value.Invoke();
170      }
171
172      waitingForExecute.Clear();
173    }
174
175    protected virtual void OnLoaded()
176    {
177      // this is done to enable keyboard shortcuts
178      Focus();
179    }
180
181    protected override void OnTemplateChanged(ControlTemplate oldTemplate, ControlTemplate newTemplate)
182    {
183      base.OnTemplateChanged(oldTemplate, newTemplate);
184    }
185
186    private Grid contentsGrid;
187    public override void OnApplyTemplate()
188    {
189      base.OnApplyTemplate();
190
191      var headerPanel = GetPart<StackPanel>("PART_HeaderPanel");
192      MigrateChildren(this.headerPanel, headerPanel);
193      this.headerPanel = headerPanel;
194
195      var footerPanel = GetPart<StackPanel>("PART_FooterPanel");
196      MigrateChildren(this.footerPanel, footerPanel);
197      this.footerPanel = footerPanel;
198
199      var leftPanel = GetPart<StackPanel>("PART_LeftPanel");
200      MigrateChildren(this.leftPanel, leftPanel);
201      this.leftPanel = leftPanel;
202
203      var bottomPanel = GetPart<StackPanel>("PART_BottomPanel");
204      MigrateChildren(this.bottomPanel, bottomPanel);
205      this.bottomPanel = bottomPanel;
206
207      var rightPanel = GetPart<StackPanel>("PART_RightPanel");
208      MigrateChildren(this.rightPanel, rightPanel);
209      this.rightPanel = rightPanel;
210
211      var topPanel = GetPart<StackPanel>("PART_TopPanel");
212      MigrateChildren(this.topPanel, topPanel);
213      this.topPanel = topPanel;
214
215      var mainCanvas = GetPart<Canvas>("PART_MainCanvas");
216      MigrateChildren(this.mainCanvas, mainCanvas);
217      this.mainCanvas = mainCanvas;
218
219      var centralGrid = GetPart<Grid>("PART_CentralGrid");
220      MigrateChildren(this.centralGrid, centralGrid);
221      this.centralGrid = centralGrid;
222
223      var mainGrid = GetPart<Grid>("PART_MainGrid");
224      MigrateChildren(this.mainGrid, mainGrid);
225      this.mainGrid = mainGrid;
226
227      var parallelCanvas = GetPart<Canvas>("PART_ParallelCanvas");
228      MigrateChildren(this.parallelCanvas, parallelCanvas);
229      this.parallelCanvas = parallelCanvas;
230
231      var contentsGrid = GetPart<Grid>("PART_ContentsGrid");
232      MigrateChildren(this.contentsGrid, contentsGrid);
233      this.contentsGrid = contentsGrid;
234
235      Content = contentsGrid;
236      AddLogicalChild(contentsGrid);
237
238      if (contentsGrid != null)
239        ExecuteWaitingChildrenAdditions();
240    }
241
242    private void MigrateChildren(Panel previousParent, Panel currentParent)
243    {
244      if (previousParent != null && currentParent != null)
245      {
246        UIElement[] children = new UIElement[previousParent.Children.Count];
247        previousParent.Children.CopyTo(children, 0);
248        previousParent.Children.Clear();
249
250        foreach (var child in children)
251        {
252          bool isDefaultPanel = GetIsDefaultPanel(child);
253          if (!currentParent.Children.Contains(child) && !isDefaultPanel)
254          {
255            currentParent.Children.Add(child);
256          }
257        }
258      }
259      else if (previousParent != null)
260      {
261        previousParent.Children.Clear();
262      }
263    }
264
265    internal virtual IEnumerable<Panel> GetAllPanels()
266    {
267      yield return headerPanel;
268      yield return footerPanel;
269
270      yield return leftPanel;
271      yield return bottomPanel;
272      yield return rightPanel;
273      yield return topPanel;
274
275      yield return mainCanvas;
276      yield return centralGrid;
277      yield return mainGrid;
278      yield return parallelCanvas;
279      yield return contentsGrid;
280    }
281
282    private T GetPart<T>(string name)
283    {
284      return (T)Template.FindName(name, this);
285    }
286
287    #region Children and add/removed events handling
288
289    private readonly PlotterChildrenCollection children;
290
291    /// <summary>
292    /// Provides access to Plotter's children charts.
293    /// </summary>
294    /// <value>The children.</value>
295    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
296    public PlotterChildrenCollection Children
297    {
298      [DebuggerStepThrough]
299      get { return children; }
300    }
301
302    private readonly Dictionary<IPlotterElement, Action> waitingForExecute = new Dictionary<IPlotterElement, Action>();
303
304    bool executedWaitingChildrenAdding = false;
305    private void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
306    {
307      if (IsLoadedInternal && !executedWaitingChildrenAdding)
308      {
309        ExecuteWaitingChildrenAdditions();
310        executedWaitingChildrenAdding = true;
311      }
312
313      if (e.NewItems != null)
314      {
315        foreach (IPlotterElement item in e.NewItems)
316        {
317          if (IsLoadedInternal)
318          {
319            OnChildAdded(item);
320          }
321          else
322          {
323            waitingForExecute.Remove(item);
324            waitingForExecute.Add(item, () => OnChildAdded(item));
325          }
326        }
327      }
328      if (e.OldItems != null)
329      {
330        foreach (IPlotterElement item in e.OldItems)
331        {
332          if (IsLoadedInternal)
333          {
334            OnChildRemoving(item);
335          }
336          else
337          {
338            waitingForExecute.Remove(item);
339            waitingForExecute.Add(item, () => OnChildRemoving(item));
340          }
341        }
342      }
343    }
344
345    bool performChildChecks = true;
346    internal bool PerformChildChecks
347    {
348      get { return performChildChecks; }
349      set { performChildChecks = value; }
350    }
351
352    private IPlotterElement currentChild = null;
353    protected IPlotterElement CurrentChild
354    {
355      get { return currentChild; }
356    }
357
358    protected virtual void OnChildAdded(IPlotterElement child)
359    {
360      if (child != null)
361      {
362        currentChild = child;
363
364        if (performChildChecks && child.Plotter != null)
365        {
366          throw new InvalidOperationException(Strings.Exceptions.PlotterElementAddedToAnotherPlotter);
367        }
368
369        if (performChildChecks)
370        {
371          child.OnPlotterAttached(this);
372          if (child.Plotter != this)
373          {
374            throw new InvalidOperationException(Strings.Exceptions.InvalidParentPlotterValue);
375          }
376        }
377
378        DependencyObject dependencyObject = child as DependencyObject;
379        if (dependencyObject != null)
380        {
381          SetPlotter(dependencyObject, this);
382        }
383      }
384    }
385
386    protected virtual void OnChildRemoving(IPlotterElement child)
387    {
388      if (child != null)
389      {
390        // todo probably here child.Plotter can be null.
391        if (performChildChecks && child.Plotter != this)
392        {
393          //throw new InvalidOperationException(Strings.Exceptions.InvalidParentPlotterValueRemoving);
394        }
395
396        if (performChildChecks)
397        {
398          if (child.Plotter != null)
399            child.OnPlotterDetaching(this);
400
401          if (child.Plotter != null)
402          {
403            throw new InvalidOperationException(Strings.Exceptions.ParentPlotterNotNull);
404          }
405        }
406
407        DependencyObject dependencyObject = child as DependencyObject;
408        if (dependencyObject != null)
409        {
410          SetPlotter(dependencyObject, null);
411        }
412      }
413    }
414
415    #endregion
416
417    #region Layout zones
418
419    private Panel parallelCanvas = new Canvas();
420    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
421    public Panel ParallelCanvas
422    {
423      get { return parallelCanvas; }
424      protected set { parallelCanvas = value; }
425    }
426
427    private Panel headerPanel = new StackPanel();
428    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
429    public Panel HeaderPanel
430    {
431      get { return headerPanel; }
432      protected set { headerPanel = value; }
433    }
434
435    private Panel footerPanel = new StackPanel();
436    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
437    public Panel FooterPanel
438    {
439      get { return footerPanel; }
440      protected set { footerPanel = value; }
441    }
442
443    private Panel leftPanel = new StackPanel();
444    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
445    public Panel LeftPanel
446    {
447      get { return leftPanel; }
448      protected set { leftPanel = value; }
449    }
450
451    private Panel rightPanel = new StackPanel();
452    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
453    public Panel RightPanel
454    {
455      get { return rightPanel; }
456      protected set { rightPanel = value; }
457    }
458
459    private Panel topPanel = new StackPanel();
460    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
461    public Panel TopPanel
462    {
463      get { return topPanel; }
464      protected set { topPanel = value; }
465    }
466
467    private Panel bottomPanel = new StackPanel();
468    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
469    public Panel BottomPanel
470    {
471      get { return bottomPanel; }
472      protected set { bottomPanel = value; }
473    }
474
475    private Panel mainCanvas = new Canvas();
476    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
477    public Panel MainCanvas
478    {
479      get { return mainCanvas; }
480      protected set { mainCanvas = value; }
481    }
482
483    private Panel centralGrid = new Grid();
484    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
485    public Panel CentralGrid
486    {
487      get { return centralGrid; }
488      protected set { centralGrid = value; }
489    }
490
491    private Panel mainGrid = new Grid();
492    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
493    public Panel MainGrid
494    {
495      get { return mainGrid; }
496      protected set { mainGrid = value; }
497    }
498
499    #endregion
500
501    #region Screenshots & copy to clipboard
502
503    public BitmapSource CreateScreenshot()
504    {
505      UIElement parent = (UIElement)Parent;
506
507      Rect renderBounds = new Rect(RenderSize);
508
509      Point p1 = renderBounds.TopLeft;
510      Point p2 = renderBounds.BottomRight;
511
512      if (parent != null)
513      {
514        //p1 = TranslatePoint(p1, parent);
515        //p2 = TranslatePoint(p2, parent);
516      }
517
518      Int32Rect rect = new Rect(p1, p2).ToInt32Rect();
519
520      return ScreenshotHelper.CreateScreenshot(this, rect);
521    }
522
523
524    /// <summary>Saves screenshot to file.</summary>
525    /// <param name="filePath">File path.</param>
526    public void SaveScreenshot(string filePath)
527    {
528      ScreenshotHelper.SaveBitmapToFile(CreateScreenshot(), filePath);
529    }
530
531    /// <summary>
532    /// Saves screenshot to stream.
533    /// </summary>
534    /// <param name="stream">The stream.</param>
535    /// <param name="fileExtension">The file type extension.</param>
536    public void SaveScreenshotToStream(Stream stream, string fileExtension)
537    {
538      ScreenshotHelper.SaveBitmapToStream(CreateScreenshot(), stream, fileExtension);
539    }
540
541    /// <summary>Copies the screenshot to clipboard.</summary>
542    public void CopyScreenshotToClipboard()
543    {
544      Clipboard.Clear();
545      Clipboard.SetImage(CreateScreenshot());
546    }
547
548    #endregion
549
550    #region IsDefaultElement attached property
551
552    protected void SetAllChildrenAsDefault()
553    {
554      foreach (var child in Children.OfType<DependencyObject>())
555      {
556        child.SetValue(IsDefaultElementProperty, true);
557      }
558    }
559
560    /// <summary>Gets a value whether specified graphics object is default to this plotter or not</summary>
561    /// <param name="obj">Graphics object to check</param>
562    /// <returns>True if it is default or false otherwise</returns>
563    public static bool GetIsDefaultElement(DependencyObject obj)
564    {
565      return (bool)obj.GetValue(IsDefaultElementProperty);
566    }
567
568    public static void SetIsDefaultElement(DependencyObject obj, bool value)
569    {
570      obj.SetValue(IsDefaultElementProperty, value);
571    }
572
573    public static readonly DependencyProperty IsDefaultElementProperty = DependencyProperty.RegisterAttached(
574      "IsDefaultElement",
575      typeof(bool),
576      typeof(Plotter),
577      new UIPropertyMetadata(false));
578
579    /// <summary>Removes all user graphs from given UIElementCollection,
580    /// leaving only default graphs</summary>
581    protected static void RemoveUserElements(IList<IPlotterElement> elements)
582    {
583      int index = 0;
584
585      while (index < elements.Count)
586      {
587        DependencyObject d = elements[index] as DependencyObject;
588        if (d != null && !GetIsDefaultElement(d))
589        {
590          elements.RemoveAt(index);
591        }
592        else
593        {
594          index++;
595        }
596      }
597    }
598
599    public void RemoveUserElements()
600    {
601      RemoveUserElements(Children);
602    }
603
604    #endregion
605
606    #region IsDefaultAxis
607
608    public static bool GetIsDefaultAxis(DependencyObject obj)
609    {
610      return (bool)obj.GetValue(IsDefaultAxisProperty);
611    }
612
613    public static void SetIsDefaultAxis(DependencyObject obj, bool value)
614    {
615      obj.SetValue(IsDefaultAxisProperty, value);
616    }
617
618    public static readonly DependencyProperty IsDefaultAxisProperty = DependencyProperty.RegisterAttached(
619      "IsDefaultAxis",
620      typeof(bool),
621      typeof(Plotter),
622      new UIPropertyMetadata(false, OnIsDefaultAxisChanged));
623
624    private static void OnIsDefaultAxisChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
625    {
626      Plotter parentPlotter = null;
627      IPlotterElement plotterElement = d as IPlotterElement;
628      if (plotterElement != null)
629      {
630        parentPlotter = plotterElement.Plotter;
631
632        if (parentPlotter != null)
633        {
634          parentPlotter.OnIsDefaultAxisChangedCore(d, e);
635        }
636      }
637    }
638
639    protected virtual void OnIsDefaultAxisChangedCore(DependencyObject d, DependencyPropertyChangedEventArgs e) { }
640
641    #endregion
642
643    #region Undo
644
645    private readonly UndoProvider undoProvider = new UndoProvider();
646    public UndoProvider UndoProvider
647    {
648      get { return undoProvider; }
649    }
650
651    #endregion
652
653    #region Plotter attached property
654
655    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
656    public static Plotter GetPlotter(DependencyObject obj)
657    {
658      return (Plotter)obj.GetValue(PlotterProperty);
659    }
660
661    public static void SetPlotter(DependencyObject obj, Plotter value)
662    {
663      obj.SetValue(PlotterProperty, value);
664    }
665
666    public static readonly DependencyProperty PlotterProperty = DependencyProperty.RegisterAttached(
667      "Plotter",
668      typeof(Plotter),
669      typeof(Plotter),
670      new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, OnPlotterChanged));
671
672    private static void OnPlotterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
673    {
674      FrameworkElement element = d as FrameworkElement;
675      Plotter prevPlotter = (Plotter)e.OldValue;
676      Plotter currPlotter = (Plotter)e.NewValue;
677
678      // raise Plotter[*] events, where * is Attached, Detaching, Changed.
679      if (element != null)
680      {
681        PlotterChangedEventArgs args = new PlotterChangedEventArgs(prevPlotter, currPlotter, PlotterDetachingEvent);
682
683        if (currPlotter == null && prevPlotter != null)
684        {
685          RaisePlotterEvent(element, args);
686        }
687        else if (currPlotter != null)
688        {
689          args.RoutedEvent = PlotterAttachedEvent;
690          RaisePlotterEvent(element, args);
691        }
692
693        args.RoutedEvent = PlotterChangedEvent;
694        RaisePlotterEvent(element, args);
695      }
696    }
697
698    private static void RaisePlotterEvent(FrameworkElement element, PlotterChangedEventArgs args)
699    {
700      element.RaiseEvent(args);
701      PlotterEvents.Notify(element, args);
702    }
703
704    #endregion
705
706    #region Plotter routed events
707
708    public static readonly RoutedEvent PlotterAttachedEvent = EventManager.RegisterRoutedEvent(
709      "PlotterAttached",
710      RoutingStrategy.Direct,
711      typeof(PlotterChangedEventHandler),
712      typeof(Plotter));
713
714    public static readonly RoutedEvent PlotterDetachingEvent = EventManager.RegisterRoutedEvent(
715      "PlotterDetaching",
716      RoutingStrategy.Direct,
717      typeof(PlotterChangedEventHandler),
718      typeof(Plotter));
719
720    public static readonly RoutedEvent PlotterChangedEvent = EventManager.RegisterRoutedEvent(
721      "PlotterChanged",
722      RoutingStrategy.Direct,
723      typeof(PlotterChangedEventHandler),
724      typeof(Plotter));
725
726    #endregion
727
728    #region DefaultPanel property
729
730    /// <summary>
731    /// Gets the value indicating that this is a default panel.
732    /// Default panels are those that are contained in plotter by default, like MainGrid or CentralCanvas.
733    /// </summary>
734    /// <param name="obj">The obj.</param>
735    /// <returns></returns>
736    public static bool GetIsDefaultPanel(DependencyObject obj)
737    {
738      return (bool)obj.GetValue(IsDefaultPanelProperty);
739    }
740
741    public static void SetIsDefaultPanel(DependencyObject obj, bool value)
742    {
743      obj.SetValue(IsDefaultPanelProperty, value);
744    }
745
746    public static readonly DependencyProperty IsDefaultPanelProperty = DependencyProperty.RegisterAttached(
747      "IsDefaultPanel",
748      typeof(bool),
749      typeof(Plotter),
750      new FrameworkPropertyMetadata(false));
751
752    #endregion
753  }
754
755  public delegate void PlotterChangedEventHandler(object sender, PlotterChangedEventArgs e);
756}
757
Note: See TracBrowser for help on using the repository browser.