Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/DynamicDataDisplay/Charts/Navigation/DefaultContextMenu.cs @ 12747

Last change on this file since 12747 was 12503, checked in by aballeit, 10 years ago

#2283 added GUI and charts; fixed MCTS

File size: 10.1 KB
Line 
1using System.Collections.Generic;
2using System.Reflection;
3using System.Windows.Controls;
4using System.Windows.Media.Imaging;
5using System.Windows;
6using System.Windows.Shapes;
7using System.Windows.Media;
8using System.Windows.Input;
9using System.Linq;
10using System.Diagnostics;
11using System;
12using System.Collections.ObjectModel;
13using System.Collections;
14using System.ComponentModel;
15using System.Windows.Data;
16using Microsoft.Research.DynamicDataDisplay.Charts.Navigation;
17
18namespace Microsoft.Research.DynamicDataDisplay.Navigation
19{
20  /// <summary>
21  /// Is responsible for displaying and populating default context menu of ChartPlotter
22  /// </summary>
23  public class DefaultContextMenu : IPlotterElement
24  {
25    private static readonly BitmapImage helpIcon;
26    private static readonly BitmapImage copyScreenshotIcon;
27    private static readonly BitmapImage saveScreenshotIcon;
28    private static readonly BitmapImage fitToViewIcon;
29    static DefaultContextMenu()
30    {
31      helpIcon = LoadIcon("HelpIcon");
32      saveScreenshotIcon = LoadIcon("SaveIcon");
33      copyScreenshotIcon = LoadIcon("CopyScreenshotIcon");
34      fitToViewIcon = LoadIcon("FitToViewIcon");
35    }
36
37    private static BitmapImage LoadIcon(string name)
38    {
39      Assembly currentAssembly = typeof(DefaultContextMenu).Assembly;
40
41      BitmapImage icon = new BitmapImage();
42      icon.BeginInit();
43      icon.StreamSource = currentAssembly.GetManifestResourceStream("Microsoft.Research.DynamicDataDisplay.Resources." + name + ".png");
44      icon.EndInit();
45      icon.Freeze();
46
47      return icon;
48    }
49
50    /// <summary>
51    /// Initializes a new instance of the <see cref="DefaultContextMenu"/> class.
52    /// </summary>
53    public DefaultContextMenu() { }
54
55    protected ContextMenu PopulateContextMenu(Plotter target)
56    {
57      ContextMenu menu = new ContextMenu();
58      MenuItem fitToViewMenuItem = new MenuItem
59      {
60        Header = Strings.UIResources.ContextMenuFitToView,
61        ToolTip = Strings.UIResources.ContextMenuFitToViewTooltip,
62        Icon = new Image { Source = fitToViewIcon },
63        Command = ChartCommands.FitToView,
64        CommandTarget = target
65      };
66
67      MenuItem savePictureMenuItem = new MenuItem
68      {
69        Header = Strings.UIResources.ContextMenuSaveScreenshot,
70        ToolTip = Strings.UIResources.ContextMenuSaveScreenshotTooltip,
71        Icon = new Image { Source = saveScreenshotIcon },
72        Command = ChartCommands.SaveScreenshot,
73        CommandTarget = target
74      };
75
76      MenuItem copyPictureMenuItem = new MenuItem
77      {
78        Header = Strings.UIResources.ContextMenuCopyScreenshot,
79        ToolTip = Strings.UIResources.ContextMenuCopyScreenshotTooltip,
80        Icon = new Image { Source = copyScreenshotIcon },
81        Command = ChartCommands.CopyScreenshot,
82        CommandTarget = target
83      };
84
85      MenuItem quickHelpMenuItem = new MenuItem
86      {
87        Header = Strings.UIResources.ContextMenuQuickHelp,
88        ToolTip = Strings.UIResources.ContextMenuQuickHelpTooltip,
89        Command = ChartCommands.ShowHelp,
90        Icon = new Image { Source = helpIcon },
91        CommandTarget = target
92      };
93
94      MenuItem reportFeedback = new MenuItem
95      {
96        Header = Strings.UIResources.ContextMenuReportFeedback,
97        ToolTip = Strings.UIResources.ContextMenuReportFeedbackTooltip,
98        Icon = (Image)plotter.Resources["SendFeedbackIcon"]
99      };
100      reportFeedback.Click += reportFeedback_Click;
101
102      staticMenuItems.Add(fitToViewMenuItem);
103      staticMenuItems.Add(copyPictureMenuItem);
104      staticMenuItems.Add(savePictureMenuItem);
105      staticMenuItems.Add(quickHelpMenuItem);
106      //staticMenuItems.Add(reportFeedback);
107
108      menu.ItemsSource = staticMenuItems;
109
110      return menu;
111    }
112
113    private void reportFeedback_Click(object sender, RoutedEventArgs e)
114    {
115      try
116      {
117        using (Process.Start("mailto:" + Strings.UIResources.SendFeedbackEmail + "?Subject=[D3]%20" + typeof(DefaultContextMenu).Assembly.GetName().Version)) { }
118      }
119      catch (Exception)
120      {
121        MessageBox.Show(Strings.UIResources.SendFeedbackError + Strings.UIResources.SendFeedbackEmail, "Error while sending feedback", MessageBoxButton.OK, MessageBoxImage.Information);
122      }
123    }
124
125    private readonly ObservableCollection<object> staticMenuItems = new ObservableCollection<object>();
126
127    // hidden because default menu items' command target is plotter, and serializing this will
128    // cause circular reference
129
130    /// <summary>
131    /// Gets the static menu items.
132    /// </summary>
133    /// <value>The static menu items.</value>
134    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
135    public ObservableCollection<object> StaticMenuItems
136    {
137      get { return staticMenuItems; }
138    }
139
140    #region IPlotterElement Members
141
142    private Plotter2D plotter;
143    void IPlotterElement.OnPlotterAttached(Plotter plotter)
144    {
145      this.plotter = (Plotter2D)plotter;
146
147      ContextMenu menu = PopulateContextMenu(plotter);
148      plotter.ContextMenu = menu;
149
150      plotter.PreviewMouseRightButtonDown += plotter_PreviewMouseRightButtonDown;
151      plotter.PreviewMouseRightButtonUp += plotter_PreviewMouseRightButtonUp;
152      plotter.PreviewMouseLeftButtonDown += plotter_PreviewMouseLeftButtonDown;
153
154      plotter.ContextMenu.Closed += ContextMenu_Closed;
155    }
156
157    private void plotter_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
158    {
159      // this will prevent other tools like PointSelector from
160      // wrong actuations
161      if (contextMenuOpen)
162      {
163        plotter.Focus();
164        e.Handled = true;
165      }
166    }
167
168    void IPlotterElement.OnPlotterDetaching(Plotter plotter)
169    {
170      plotter.ContextMenu.Closed -= ContextMenu_Closed;
171
172      plotter.ContextMenu = null;
173      plotter.PreviewMouseRightButtonDown -= plotter_PreviewMouseRightButtonDown;
174      plotter.PreviewMouseRightButtonUp -= plotter_PreviewMouseRightButtonUp;
175
176      this.plotter = null;
177    }
178
179    private void ContextMenu_Closed(object sender, RoutedEventArgs e)
180    {
181      contextMenuOpen = false;
182      foreach (var item in dynamicMenuItems)
183      {
184        staticMenuItems.Remove(item);
185      }
186    }
187
188    private Point mousePos;
189    /// <summary>
190    /// Gets the mouse position when right mouse button was clicked.
191    /// </summary>
192    /// <value>The mouse position on click.</value>
193    public Point MousePositionOnClick
194    {
195      get { return mousePos; }
196    }
197
198    private void plotter_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
199    {
200      contextMenuOpen = false;
201      mousePos = e.GetPosition(plotter);
202    }
203
204    private bool contextMenuOpen = false;
205    private readonly ObservableCollection<object> dynamicMenuItems = new ObservableCollection<object>();
206    private void plotter_PreviewMouseRightButtonUp(object sender, MouseButtonEventArgs e)
207    {
208      Point position = e.GetPosition(plotter);
209      if (mousePos == position)
210      {
211        hitResults.Clear();
212        VisualTreeHelper.HitTest(plotter, null, CollectAllVisuals_Callback, new PointHitTestParameters(position));
213
214        foreach (var item in dynamicMenuItems)
215        {
216          staticMenuItems.Remove(item);
217        }
218        dynamicMenuItems.Clear();
219        var dynamicItems = (hitResults.Where(r =>
220        {
221          IPlotterContextMenuSource menuSource = r as IPlotterContextMenuSource;
222          if (menuSource != null)
223          {
224            menuSource.BuildMenu();
225          }
226
227          var items = GetPlotterContextMenu(r);
228          return items != null && items.Count > 0;
229        }).SelectMany(r =>
230        {
231          var menuItems = GetPlotterContextMenu(r);
232
233          FrameworkElement chart = r as FrameworkElement;
234          if (chart != null)
235          {
236            foreach (var menuItem in menuItems.OfType<MenuItem>())
237            {
238              menuItem.DataContext = chart.DataContext;
239            }
240          }
241          return menuItems;
242        })).ToList();
243
244        foreach (var item in dynamicItems)
245        {
246          dynamicMenuItems.Add(item);
247          //MenuItem menuItem = item as MenuItem;
248          //if (menuItem != null)
249          //{
250          //    menuItem.CommandTarget = plotter;
251          //}
252        }
253
254        staticMenuItems.AddMany(dynamicMenuItems);
255
256        plotter.Focus();
257        contextMenuOpen = true;
258
259        // in XBAP applications these lines throws a SecurityException, as (as I think)
260        // we are opening "new window" here. So in XBAP we are not opening context menu manually, but
261        // it will be opened by itself as this is right click.
262#if !RELEASEXBAP
263        plotter.ContextMenu.IsOpen = true;
264        e.Handled = true;
265#endif
266      }
267      else
268      {
269        // this is to prevent showing menu when RMB was pressed, then moved and now is releasing.
270        e.Handled = true;
271      }
272    }
273
274    #region PlotterContextMenu property
275
276    /// <summary>
277    /// Gets the plotter context menu.
278    /// </summary>
279    /// <param name="obj">The obj.</param>
280    /// <returns></returns>
281    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
282    public static ObjectCollection GetPlotterContextMenu(DependencyObject obj)
283    {
284      return (ObjectCollection)obj.GetValue(PlotterContextMenuProperty);
285    }
286
287    /// <summary>
288    /// Sets the plotter context menu.
289    /// </summary>
290    /// <param name="obj">The obj.</param>
291    /// <param name="value">The value.</param>
292    public static void SetPlotterContextMenu(DependencyObject obj, ObjectCollection value)
293    {
294      obj.SetValue(PlotterContextMenuProperty, value);
295    }
296
297    /// <summary>
298    /// Identifies the PlotterContextMenu attached property.
299    /// </summary>
300    public static readonly DependencyProperty PlotterContextMenuProperty = DependencyProperty.RegisterAttached(
301      "PlotterContextMenu",
302      typeof(ObjectCollection),
303      typeof(DefaultContextMenu),
304      new FrameworkPropertyMetadata(null));
305
306    #endregion
307
308    private List<DependencyObject> hitResults = new List<DependencyObject>();
309    private HitTestResultBehavior CollectAllVisuals_Callback(HitTestResult result)
310    {
311      if (result == null || result.VisualHit == null)
312        return HitTestResultBehavior.Stop;
313
314      hitResults.Add(result.VisualHit);
315      return HitTestResultBehavior.Continue;
316    }
317
318    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
319    Plotter IPlotterElement.Plotter
320    {
321      get { return plotter; }
322    }
323
324    #endregion
325  }
326
327  /// <summary>
328  /// Represents a collection of additional menu items in ChartPlotter's context menu.
329  /// </summary>
330  public sealed class ObjectCollection : ObservableCollection<Object> { }
331}
Note: See TracBrowser for help on using the repository browser.