[amd64/tramp] hide interpreter specific trampoline behind ifdef
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / View / ViewUtilities.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4
5 namespace System.Activities.Presentation.View
6 {
7     using System.Activities.Presentation.Model;
8     using System.Activities.Presentation.Services;
9     using System.Collections.Generic;
10     using System.Runtime;
11     using System.Windows;
12     using System.Windows.Controls;
13     using System.Windows.Media;
14
15     internal static class ViewUtilities
16     {
17         const string ExpandViewStateKey = "IsExpanded";
18         internal static bool DoesParentAlwaysExpandChildren(ModelItem modelItem, EditingContext context)
19         {
20             return IsParentOfType(modelItem, typeof(IExpandChild), context);
21         }
22
23         internal static bool DoesParentAlwaysCollapseChildren(ModelItem modelItem, EditingContext context)
24         {
25             bool parentAlwaysCollapsesChild = false;
26             Type parentDesignerType = GetParentDesignerType(modelItem, context);
27             if (typeof(WorkflowViewElement).IsAssignableFrom(parentDesignerType))
28             {
29                 ActivityDesignerOptionsAttribute options = WorkflowViewService.GetAttribute<ActivityDesignerOptionsAttribute>(parentDesignerType);
30                 parentAlwaysCollapsesChild = (options != null && options.AlwaysCollapseChildren);
31             }
32             return parentAlwaysCollapsesChild;
33         }
34
35         // Determines whether a particular ModelItem's view will be visible for a given breadcrumb root. 
36         //It depends on whether the intermediate designers are expanded or collapsed.
37         internal static bool IsViewVisible(ModelItem child, ModelItem root, EditingContext context)
38         {
39             if (child == root)
40             {
41                 return !IsDefaultDesigner(context, root);
42             }
43
44             if (child.Parent == null)
45             {
46                 return false;
47             }
48
49             WorkflowViewService viewService = GetViewService(context);
50             ModelItem parent = ModelUtilities.ReverseFindFirst(child.Parent, (ModelItem current) =>
51             {
52                 return object.Equals(current, root) ||
53                     HasView(current, viewService, false) &&
54                     (!IsViewExpanded(current, context) || IsDefaultDesigner(context, current));
55             });
56
57             return object.Equals(parent, root) && !IsDefaultDesigner(context, root);
58         }
59
60         private static bool IsDefaultDesigner(EditingContext context, ModelItem item)
61         {
62             WorkflowViewService viewService = GetViewService(context);
63             Type viewType = viewService.GetDesignerType(item.ItemType);
64             return viewType == typeof(ActivityDesigner);
65         }
66
67         private static bool HasView(ModelItem modelItem, WorkflowViewService viewService, bool allowDrillIn)
68         {
69             ActivityDesignerOptionsAttribute options = WorkflowViewService.GetAttribute<ActivityDesignerOptionsAttribute>(modelItem.ItemType);
70             Type viewType = viewService.GetDesignerType(modelItem.ItemType);
71             return typeof(WorkflowViewElement).IsAssignableFrom(viewType) && (!allowDrillIn || options == null || options.AllowDrillIn);
72         }
73
74         // Get the first parent ModelItem that has a view
75         internal static ModelItem GetParentModelItemWithView(ModelItem modelItem, EditingContext context, bool allowDrillIn)
76         {
77             if (modelItem == null || modelItem.Parent == null)
78             {
79                 return null;
80             }
81
82             WorkflowViewService viewService = GetViewService(context);
83
84             return ModelUtilities.ReverseFindFirst(modelItem.Parent, (ModelItem current) =>
85                 {
86                     return HasView(current, viewService, allowDrillIn);
87                 });
88         }
89
90         // Determine whether the view of a ModelItem is expanded without querying the view itself - the view may have not been constructed.
91         internal static bool IsViewExpanded(ModelItem modelItem, EditingContext context)
92         {
93             if (modelItem == null)
94             {
95                 return false;
96             }
97
98             bool isDesignerExpanded = true;
99             bool isDesignerPinned = false;
100             object isExpandedViewState = GetViewStateService(context).RetrieveViewState(modelItem, ExpandViewStateKey);
101             object isPinnedViewState = GetViewStateService(context).RetrieveViewState(modelItem, WorkflowViewElement.PinnedViewStateKey);
102             if (isExpandedViewState != null)
103             {
104                 isDesignerExpanded = (bool)isExpandedViewState;
105             }
106             if (isPinnedViewState != null)
107             {
108                 isDesignerPinned = (bool)isPinnedViewState;
109             }
110
111             DesignerView designerView = context.Services.GetService<DesignerView>();
112              
113             return ShouldShowExpanded(IsBreadcrumbRoot(modelItem, context), DoesParentAlwaysExpandChildren(modelItem, context),
114                 DoesParentAlwaysCollapseChildren(modelItem, context), isDesignerExpanded, designerView.ShouldExpandAll, designerView.ShouldCollapseAll, isDesignerPinned);
115         }
116
117         internal static bool IsBreadcrumbRoot(ModelItem modelItem, EditingContext context)
118         {
119             DesignerView designerView = context.Services.GetService<DesignerView>();
120             return modelItem != null && modelItem.View != null && modelItem.View.Equals(designerView.RootDesigner);
121         }
122
123         internal static bool ShouldShowExpanded(
124             bool isRootDesigner,
125             bool parentAlwaysExpandChildren,
126             bool parentAlwaysCollapseChildren,
127             bool expandState,
128             bool expandAll,
129             bool collapseAll,
130             bool pinState)
131         {
132             //ShowExpanded based on ExpandAll, CollapseAll, PinState, ExpandState
133             bool showExpanded = ShouldShowExpanded(expandState, expandAll, collapseAll, pinState);
134
135             //return value based on the position of the element in the workflow tree.
136             return (isRootDesigner || parentAlwaysExpandChildren || (!parentAlwaysCollapseChildren && showExpanded));
137         }
138
139         internal static bool ShouldShowExpanded(bool isExpanded, bool shouldExpandAll, bool shouldCollapseAll, bool isPinned)
140         {
141             if (isPinned)
142             {
143                 return isExpanded;
144             }
145             else
146             {
147                 return !shouldCollapseAll && (shouldExpandAll || isExpanded);
148             }
149         }
150
151         static WorkflowViewService GetViewService(EditingContext context)
152         {
153             return context.Services.GetService<ViewService>() as WorkflowViewService;
154         }
155
156         static ViewStateService GetViewStateService(EditingContext context)
157         {
158             return context.Services.GetService<ViewStateService>();
159         }
160
161         //Checks to see if the immediate parent WorkflowViewElement is of type "parentType".
162         static bool IsParentOfType(ModelItem modelItem, Type parentType, EditingContext context)
163         {
164             Type parentDesignerType = GetParentDesignerType(modelItem, context);
165             return parentType.IsAssignableFrom(parentDesignerType);
166         }
167
168         static Type GetParentDesignerType(ModelItem modelItem, EditingContext context)
169         {
170             ModelItem parent = GetParentModelItemWithView(modelItem, context, false);
171             if (parent != null)
172             {
173                 return GetViewService(context).GetDesignerType(parent.ItemType);
174             }
175             return null;
176         }
177
178         internal static void MeasureView(WorkflowViewElement view, bool measureAsCollapsed)
179         {
180             bool expandState = view.ExpandState;
181             bool pinState = view.PinState;
182          
183             if (measureAsCollapsed)
184             {
185                 view.ForceCollapse();
186             }
187
188             view.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
189             view.UpdateLayout();
190
191             if (view.ExpandState != expandState)
192             {
193                 view.ExpandState = expandState;
194             }
195             if (view.PinState != pinState)
196             {
197                 view.PinState = pinState;
198             }
199         }
200
201         // the job of this method is to construct a DisplayName for ActivityBuilder
202         // This name will be shown in breadcrumb bar.
203         // if ActivityBuilder.Name = "workflowconsoleApp.Sequence1"
204         // we want DisplayName = "Sequence1"
205         internal static string GetActivityBuilderDisplayName(ModelItem modelItem)
206         {
207             Fx.Assert(modelItem != null, "modelItem != null");
208             ModelItem nameModelItem = modelItem.Properties["Name"].Value;
209             string name = (nameModelItem == null) ? null : (string)nameModelItem.GetCurrentValue();
210
211             if (string.IsNullOrEmpty(name))
212             {
213                 return string.Empty;
214             }
215
216             string displayName = string.Empty;
217             int indexOfDot = name.LastIndexOf('.');
218             if (indexOfDot > -1)
219             {
220                 // if make sure there at least one character after .
221                 if (indexOfDot < name.Length - 1)
222                 {
223                     displayName = name.Substring(indexOfDot + 1);
224                 }
225             }
226             else
227             {
228                 displayName = name;
229             }
230
231             return displayName;
232         }
233
234         internal static GeneralTransform GetTransformToRoot(Visual visual)
235         {
236             Visual rootVisual = GetRootVisual(visual);
237
238             return (rootVisual != null) ? visual.TransformToAncestor(rootVisual) : null;
239         }
240
241         private static Visual GetRootVisual(Visual visual)
242         {
243             Fx.Assert(visual != null, "visual should not be null");
244
245             Visual root = null;
246
247             PresentationSource source = PresentationSource.FromDependencyObject(visual);
248             if (source != null)
249             {
250                 root = source.RootVisual;
251             }
252
253             // PresentationSource will be null if the element is not in a window
254             // Window w = new Window();
255             // Button b = new Button();
256             // w.Show();
257             // w.Content = b;
258             // PresentationSource.FromDependencyObject(b) will return an instance
259             // w.Content = null;
260             // PresentationSource.FromDependencyObject(b) will return null
261             // The reason of tree walk is to make some effort to support 
262             // the scenario where user wants to capture a visual that is 
263             // not in a window. 
264             if (root == null)
265             {
266                 for (DependencyObject current = visual;
267                     current != null; current = VisualTreeHelper.GetParent(current))
268                 {
269                     // Maybe Visual is not enought in some case, but I don't get a sample 
270                     // till now. If it happens, add LogicalTreeHelper.GetParent() to the 
271                     // parent getting chain.
272                     Visual currentVisual = current as Visual;
273                     if (currentVisual != null)
274                     {
275                         root = currentVisual;
276                     }
277                 }
278             }
279
280             return root;
281         }
282     }
283 }