68652bc26b459464b8b33e03890e72b42d8d9fc6
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / PropertyEditing / EditModeSwitchButton.cs
1 namespace System.Activities.Presentation.PropertyEditing {
2     using System;
3     using System.Windows;
4     using System.Windows.Input;
5     using System.Windows.Controls;
6     using System.Diagnostics.CodeAnalysis;
7     using System.Diagnostics;
8
9     /// <summary>
10     /// Convenience button that allows the user to switch between the different PropertyContainer modes.
11     /// This button is styled to follow the look and feel specific to the host application.  It can operate
12     /// in two modes - either it always executes a specified mode-switching command, or it adapts to
13     /// the current mode of the containing PropertyContainer and "does the right thing".  If set manually,
14     /// SyncModeToOwningContainer must be set to false and the mode-switching command needs to be specified
15     /// using the TargetEditMode property.  To set the mode automatically, SyncModeToOwningContainer must
16     /// be set to true in which case the TargetEditMode property is ignored.
17     /// </summary>
18     [SuppressMessage("Microsoft.Maintainability", "CA1501:AvoidExcessiveInheritance")]
19     public class EditModeSwitchButton : Button {
20
21         private PropertyContainer _owningContainer;
22         private bool _attachedToContainerEvents;
23
24         /// <summary>
25         /// Basic ctor
26         /// </summary>
27         [SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
28         public EditModeSwitchButton() {
29             this.Loaded += new RoutedEventHandler(OnLoaded);
30             this.Unloaded += new RoutedEventHandler(OnUnloaded);
31             this.FontSize = SystemFonts.IconFontSize;
32             this.FontFamily = SystemFonts.IconFontFamily;
33             this.FontWeight = SystemFonts.IconFontWeight;
34         }
35
36         // TargetEditMode DP
37
38         /// <summary>
39         /// The mode to switch to when this control is clicked.  Only used when 
40         /// SyncModeToOwningContainer is set to false.  Defaults to Inline.
41         /// </summary>
42         public static readonly DependencyProperty TargetEditModeProperty = DependencyProperty.Register(
43             "TargetEditMode",
44             typeof(PropertyContainerEditMode),
45             typeof(EditModeSwitchButton),
46             new FrameworkPropertyMetadata(
47                 PropertyContainerEditMode.Inline,
48                 null,  // PropertyChangedCallback
49                 new CoerceValueCallback(OnCoerceEditModeProperty)));
50
51         /// <summary>
52         /// The mode to switch to when this control is clicked.  Only used when 
53         /// SyncModeToOwningContainer is set to false.  Defaults to Inline.
54         /// </summary>
55         public PropertyContainerEditMode TargetEditMode {
56             get { return (PropertyContainerEditMode) this.GetValue(TargetEditModeProperty); }
57             set { this.SetValue(TargetEditModeProperty, value); }
58         }
59
60         private static object OnCoerceEditModeProperty(DependencyObject obj, object value) {
61
62             EditModeSwitchButton theThis = (EditModeSwitchButton) obj;
63
64             // [....] to the owning PropertyContainer only if requested to do so
65             if (!theThis.SyncModeToOwningContainer)
66                 return value;
67
68             // Do we have an owning PropertyContainer?
69             if (theThis._owningContainer == null)
70                 return value;
71
72             PropertyContainerEditMode newMode;
73             PropertyContainer owningContainer = theThis._owningContainer;
74
75             switch (owningContainer.ActiveEditMode) {
76                 case PropertyContainerEditMode.Inline:
77                     // when clicked, have this button switch to extended popup mode
78                     // or dialog mode (dialog takes precedence)
79                     if (owningContainer.SupportsEditMode(PropertyContainerEditMode.Dialog))
80                         newMode = PropertyContainerEditMode.Dialog;
81                     else if (owningContainer.SupportsEditMode(PropertyContainerEditMode.ExtendedPopup))
82                         newMode = PropertyContainerEditMode.ExtendedPopup;
83                     else
84                         newMode = PropertyContainerEditMode.Inline;
85
86                     break;
87
88                 case PropertyContainerEditMode.ExtendedPopup:
89                     // when clicked, have this button switch to extended pinned mode
90                     newMode = PropertyContainerEditMode.ExtendedPinned;
91                     break;
92
93                 case PropertyContainerEditMode.ExtendedPinned:
94                     // when clicked, have this button switch to inline mode
95                     newMode = PropertyContainerEditMode.Inline;
96                     break;
97
98                 case PropertyContainerEditMode.Dialog:
99                     // do nothing
100                     newMode = theThis.TargetEditMode;
101                     break;
102
103                 default:
104                     Debug.Fail(string.Format(
105                         System.Globalization.CultureInfo.CurrentCulture,
106                         "ModeSwitchControl does not yet support PropertyContainerEditMode '{0}'.",
107                         owningContainer.ActiveEditMode.ToString()));
108                     newMode = (PropertyContainerEditMode) value;
109                     break;
110             }
111
112             return newMode;
113         }
114
115
116         // SyncModeToOwningContainer DP
117
118         /// <summary>
119         /// When set to true, the TargetEditMode will be calculated automatically to match the ActiveEditMode
120         /// of the owning PropertyContainer. Otherwise, the mode to switch to will be based on the
121         /// TargetEditMode property.
122         /// </summary>
123         public static readonly DependencyProperty SyncModeToOwningContainerProperty = DependencyProperty.Register(
124             "SyncModeToOwningContainer",
125             typeof(bool),
126             typeof(EditModeSwitchButton),
127             new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnSyncModeToOwningContainerChanged)));
128
129         /// <summary>
130         /// When set to true, the TargetEditMode will be calculated automatically to match the ActiveEditMode
131         /// of the owning PropertyContainer. Otherwise, the mode to switch to will be based on the
132         /// TargetEditMode property.
133         /// </summary>
134         public bool SyncModeToOwningContainer {
135             get { return (bool)this.GetValue(SyncModeToOwningContainerProperty); }
136             set { this.SetValue(SyncModeToOwningContainerProperty, value); }
137         }
138
139         // When the SyncModeToOwningContainer changes, we may need to update the current
140         // TargetEditMode
141         private static void OnSyncModeToOwningContainerChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) {
142             EditModeSwitchButton theThis = (EditModeSwitchButton)obj;
143             theThis.CoerceValue(TargetEditModeProperty);
144         }
145
146
147         /// <summary>
148         /// Called when any DependencyProperties of this Control change.  If you override
149         /// this method, call the base implementation first to preserve the desired functionality.
150         /// </summary>
151         /// <param name="e">Event args</param>
152         protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) {
153             // Check to see if this control has changed (or gained or lost) its owning PropertyContainer.
154             // If so, it may need to update its state / appearance accordingly
155             if (e.Property == PropertyContainer.OwningPropertyContainerProperty) {
156                 PropertyContainer oldContainer = (PropertyContainer)e.OldValue;
157                 PropertyContainer newContainer = (PropertyContainer)e.NewValue;
158                 _owningContainer = newContainer;
159
160                 if (oldContainer != null)
161                     DisassociateContainerEventHandlers(oldContainer);
162
163                 if (newContainer != null)
164                     AssociateContainerEventHandlers(newContainer);
165
166                 this.CoerceValue(TargetEditModeProperty);
167             }
168
169             base.OnPropertyChanged(e);
170         }
171
172         private void OnPropertyContainerDependencyPropertyChanged(object sender, DependencyPropertyChangedEventArgs e) {
173             // All of these properties changing have the potential of affecting the appearance
174             // of this control
175             if (e.Property == PropertyContainer.ActiveEditModeProperty ||
176                 e.Property == PropertyContainer.PropertyEntryProperty ||
177                 e.Property == PropertyContainer.DefaultStandardValuesPropertyValueEditorProperty ||
178                 e.Property == PropertyContainer.DefaultPropertyValueEditorProperty) {
179
180                 this.CoerceValue(TargetEditModeProperty);
181             }
182         }
183
184         private void AssociateContainerEventHandlers(PropertyContainer container) {
185             if (!_attachedToContainerEvents) {
186                 container.DependencyPropertyChanged += new DependencyPropertyChangedEventHandler(OnPropertyContainerDependencyPropertyChanged);
187                 _attachedToContainerEvents = true;
188             }
189         }
190
191         private void DisassociateContainerEventHandlers(PropertyContainer container) {
192             if (_attachedToContainerEvents) {
193                 container.DependencyPropertyChanged -= new DependencyPropertyChangedEventHandler(OnPropertyContainerDependencyPropertyChanged);
194                 _attachedToContainerEvents = false;
195             }
196         }
197
198
199         // When the control gets unloaded, unhook any remaining event handlers
200         // so that it can be garbage collected
201         private void OnUnloaded(object sender, RoutedEventArgs e) {
202             if (_owningContainer != null)
203                 DisassociateContainerEventHandlers(_owningContainer);
204         }
205
206         // When the control gets re-loaded somewhere else in the tree, re-hook the
207         // event handlers back up
208         private void OnLoaded(object sender, RoutedEventArgs e) {
209             if (_owningContainer != null)
210                 AssociateContainerEventHandlers(_owningContainer);
211         }
212
213         /// <summary>
214         /// Because of the nature of the popup capturing mouse and disappearing when the
215         /// user clicks outside of it, to pin an ExtendedEditor we listen to MouseDown event
216         /// rather than the Click event.
217         /// </summary>
218         /// <param name="e">Event args</param>
219         protected override void OnMouseDown(MouseButtonEventArgs e) {
220
221             if (e.LeftButton == MouseButtonState.Pressed) {
222
223                 // Invoke the appropriate command
224                 switch (this.TargetEditMode) {
225                     case PropertyContainerEditMode.Inline:
226                         PropertyValueEditorCommands.ShowInlineEditor.Execute(null, this);
227                         break;
228                     case PropertyContainerEditMode.ExtendedPopup:
229                         PropertyValueEditorCommands.ShowExtendedPopupEditor.Execute(null, this);
230                         break;
231                     case PropertyContainerEditMode.ExtendedPinned:
232                         PropertyValueEditorCommands.ShowExtendedPinnedEditor.Execute(null, this);
233                         break;
234                     case PropertyContainerEditMode.Dialog:
235                         PropertyValueEditorCommands.ShowDialogEditor.Execute(null, this);
236                         break;
237                     default:
238                         Debug.Fail(string.Format(
239                             System.Globalization.CultureInfo.CurrentCulture,
240                             "ModeSwitchControl does not yet support PropertyContainerEditMode '{0}'.",
241                             this.TargetEditMode.ToString()));
242                         break;
243                 }
244             }
245
246             base.OnMouseDown(e);
247         }
248     }
249 }