diff options
| author | Michael VanOverbeek <[email protected]> | 2016-07-25 12:57:52 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2016-07-25 12:57:52 -0400 |
| commit | 46c1c31302f111a1f3ec23a70e6f3986a9aa2a27 (patch) | |
| tree | f00af7ea3f6ad2641fb26fa1d310fd8b7179b39c /source/ShiftUI/Widgets/GridEntry.cs | |
| parent | af48e774189596b8d7a058c564a7d6d75205ca03 (diff) | |
| parent | 6fa16209519896de09949a27425dff00ebf2970a (diff) | |
| download | shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.gz shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.tar.bz2 shiftos-c--46c1c31302f111a1f3ec23a70e6f3986a9aa2a27.zip | |
Merge pull request #17 from MichaelTheShifter/shiftui_integration
Shiftui integration
Diffstat (limited to 'source/ShiftUI/Widgets/GridEntry.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/GridEntry.cs | 860 |
1 files changed, 860 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/GridEntry.cs b/source/ShiftUI/Widgets/GridEntry.cs new file mode 100644 index 0000000..619bb4c --- /dev/null +++ b/source/ShiftUI/Widgets/GridEntry.cs @@ -0,0 +1,860 @@ +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// Copyright (c) 2004-2008 Novell, Inc. +// +// Authors: +// Jonathan Chambers ([email protected]) +// Ivan N. Zlatev ([email protected]) +// + +// NOT COMPLETE + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Design; +using ShiftUI; +using ShiftUI.Design; +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Globalization; + +namespace ShiftUI.PropertyGridInternal +{ + internal class GridEntry : GridItem, ITypeDescriptorContext + { + #region Local Variables + private PropertyGrid property_grid; + private bool expanded; + private GridItemCollection grid_items; + private GridItem parent; + private PropertyDescriptor[] property_descriptors; + private int top; + private Rectangle plus_minus_bounds; + private GridItemCollection child_griditems_cache; + #endregion // Local Variables + + #region Contructors + protected GridEntry (PropertyGrid propertyGrid, GridEntry parent) + { + if (propertyGrid == null) + throw new ArgumentNullException ("propertyGrid"); + property_grid = propertyGrid; + plus_minus_bounds = new Rectangle (0,0,0,0); + top = -1; + grid_items = new GridItemCollection (); + expanded = false; + this.parent = parent; + child_griditems_cache = null; + } + + // Cannot use one PropertyDescriptor for all owners, because the + // propertydescriptors might have different Invokees. Check + // ReflectionPropertyDescriptor.GetInvokee and how it's used. + // + public GridEntry (PropertyGrid propertyGrid, PropertyDescriptor[] properties, + GridEntry parent) : this (propertyGrid, parent) + { + if (properties == null || properties.Length == 0) + throw new ArgumentNullException ("prop_desc"); + property_descriptors = properties; + } + #endregion // Constructors + + + public override bool Expandable { + get { + TypeConverter converter = GetConverter (); + if (converter == null || !converter.GetPropertiesSupported ((ITypeDescriptorContext)this)) + return false; + + if (GetChildGridItemsCached ().Count > 0) + return true; + + return false; + } + } + + public override bool Expanded { + get { return expanded; } + set { + if (expanded != value) { + expanded = value; + PopulateChildGridItems (); + if (value) + property_grid.OnExpandItem (this); + else + property_grid.OnCollapseItem (this); + } + } + } + + public override GridItemCollection GridItems { + get { + PopulateChildGridItems (); + return grid_items; + } + } + + public override GridItemType GridItemType { + get { return GridItemType.Property; } + } + + public override string Label { + get { + PropertyDescriptor property = this.PropertyDescriptor; + if (property != null) { + string label = property.DisplayName; + ParenthesizePropertyNameAttribute parensAttr = + property.Attributes[typeof (ParenthesizePropertyNameAttribute)] as ParenthesizePropertyNameAttribute; + if (parensAttr != null && parensAttr.NeedParenthesis) + label = "(" + label + ")"; + return label; + } + return String.Empty; + } + } + + public override GridItem Parent { + get { return parent; } + } + + public GridEntry ParentEntry { + get { + if (parent != null && parent.GridItemType == GridItemType.Category) + return parent.Parent as GridEntry; + return parent as GridEntry; + } + } + + public override PropertyDescriptor PropertyDescriptor { + get { return property_descriptors != null ? property_descriptors[0] : null; } + } + + public PropertyDescriptor[] PropertyDescriptors { + get { return property_descriptors; } + } + + public object PropertyOwner { + get { + object[] owners = PropertyOwners; + if (owners != null) + return owners[0]; + return null; + } + } + + public object[] PropertyOwners { + get { + if (ParentEntry == null) + return null; + + object[] owners = ParentEntry.Values; + PropertyDescriptor[] properties = PropertyDescriptors; + object newOwner = null; + for (int i=0; i < owners.Length; i++) { + if (owners[i] is ICustomTypeDescriptor) { + newOwner = ((ICustomTypeDescriptor)owners[i]).GetPropertyOwner (properties[i]); + if (newOwner != null) + owners[i] = newOwner; + } + } + return owners; + } + } + + // true if the value is the same among all properties + public bool HasMergedValue { + get { + if (!IsMerged) + return false; + + object[] values = this.Values; + for (int i=0; i+1 < values.Length; i++) { + if (!Object.Equals (values[i], values[i+1])) + return false; + } + return true; + } + } + + public virtual bool IsMerged { + get { return (PropertyDescriptors != null && PropertyDescriptors.Length > 1); } + } + + // If IsMerged this will return all values for all properties in all owners + public virtual object[] Values { + get { + if (PropertyDescriptor == null || this.PropertyOwners == null) + return null; + if (IsMerged) { + object[] owners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + object[] values = new object[owners.Length]; + for (int i=0; i < owners.Length; i++) + values[i] = properties[i].GetValue (owners[i]); + return values; + } else { + return new object[] { this.Value }; + } + } + } + + // Returns the first value for the first propertyowner and propertydescriptor + // + public override object Value { + get { + if (PropertyDescriptor == null || PropertyOwner == null) + return null; + + return PropertyDescriptor.GetValue (PropertyOwner); + } + set + { + PropertyDescriptor.SetValue(PropertyOwner, value); + } + } + + public string ValueText { + get { + string text = null; + try { + text = ConvertToString (this.Value); + if (text == null) + text = String.Empty; + } catch { + text = String.Empty; + } + return text; + } + } + + public override bool Select () + { + property_grid.SelectedGridItem = this; + return true; + } + + #region ITypeDescriptorContext + void ITypeDescriptorContext.OnComponentChanged () + { + } + + bool ITypeDescriptorContext.OnComponentChanging () + { + return false; + } + + IContainer ITypeDescriptorContext.Container { + get { + if (PropertyOwner == null) + return null; + + IComponent component = property_grid.SelectedObject as IComponent; + if (component != null && component.Site != null) + return component.Site.Container; + return null; + } + } + + object ITypeDescriptorContext.Instance { + get { + if (ParentEntry != null && ParentEntry.PropertyOwner != null) + return ParentEntry.PropertyOwner; + return PropertyOwner; + } + } + + PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor { + get { + if (ParentEntry != null && ParentEntry.PropertyDescriptor != null) + return ParentEntry.PropertyDescriptor; + return PropertyDescriptor; + } + } + #endregion + + #region IServiceProvider Members + + object IServiceProvider.GetService (Type serviceType) { + IComponent selectedComponent = property_grid.SelectedObject as IComponent; + if (selectedComponent != null && selectedComponent.Site != null) + return selectedComponent.Site.GetService (serviceType); + return null; + } + + #endregion + + internal int Top { + get { return top; } + set { + if (top != value) + top = value; + } + } + + internal Rectangle PlusMinusBounds { + get { return plus_minus_bounds; } + set { plus_minus_bounds = value; } + } + + public void SetParent (GridItem parent) + { + this.parent = parent; + } + + public ICollection AcceptedValues { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor != null && converter != null && + converter.GetStandardValuesSupported ((ITypeDescriptorContext)this)) { + ArrayList values = new ArrayList (); + string stringVal = null; + ICollection standardValues = converter.GetStandardValues ((ITypeDescriptorContext)this); + if (standardValues != null) { + foreach (object value in standardValues) { + stringVal = ConvertToString (value); + if (stringVal != null) + values.Add (stringVal); + } + } + return values.Count > 0 ? values : null; + } + return null; + } + } + + private string ConvertToString (object value) + { + if (value is string) + return (string)value; + + if (PropertyDescriptor != null && PropertyDescriptor.Converter != null && + PropertyDescriptor.Converter.CanConvertTo ((ITypeDescriptorContext)this, typeof (string))) { + try { + return PropertyDescriptor.Converter.ConvertToString ((ITypeDescriptorContext)this, value); + } catch { + // XXX: Happens too often... + // property_grid.ShowError ("Property value of '" + property_descriptor.Name + "' is not convertible to string."); + return null; + } + } + + return null; + } + + public bool HasCustomEditor { + get { return EditorStyle != UITypeEditorEditStyle.None; } + } + + public UITypeEditorEditStyle EditorStyle { + get { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + return editor.GetEditStyle ((ITypeDescriptorContext)this); + } catch { + // Some of our Editors throw NotImplementedException + } + } + return UITypeEditorEditStyle.None; + } + } + + public bool EditorResizeable { + get { + if (this.EditorStyle == UITypeEditorEditStyle.DropDown) { + UITypeEditor editor = GetEditor (); + if (editor != null && editor.IsDropDownResizable) + return true; + } + return false; + } + } + + public bool EditValue (IWindowsFormsEditorService service) + { + if (service == null) + throw new ArgumentNullException ("service"); + + IServiceContainer parent = ((ITypeDescriptorContext)this).GetService (typeof (IServiceContainer)) as IServiceContainer; + ServiceContainer container = null; + + if (parent != null) + container = new ServiceContainer (parent); + else + container = new ServiceContainer (); + + container.AddService (typeof (IWindowsFormsEditorService), service); + + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + object value = editor.EditValue ((ITypeDescriptorContext)this, + container, + this.Value); + string error = null; + return SetValue (value, out error); + } catch { //(Exception e) { + // property_grid.ShowError (e.Message + Environment.NewLine + e.StackTrace); + } + } + return false; + } + + private UITypeEditor GetEditor () + { + if (PropertyDescriptor != null) { + try { // can happen, because we are missing some editors + if (PropertyDescriptor != null) + return (UITypeEditor) PropertyDescriptor.GetEditor (typeof (UITypeEditor)); + } catch { + // property_grid.ShowError ("Unable to load UITypeEditor for property '" + PropertyDescriptor.Name + "'."); + } + } + return null; + } + + private TypeConverter GetConverter () + { + if (PropertyDescriptor != null) + return PropertyDescriptor.Converter; + return null; + } + + public bool ToggleValue () + { + if (IsReadOnly || (IsMerged && !HasMergedValue)) + return false; + + bool success = false; + string error = null; + object value = this.Value; + if (PropertyDescriptor.PropertyType == typeof(bool)) + success = SetValue (!(bool)value, out error); + else { + TypeConverter converter = GetConverter (); + if (converter != null && + converter.GetStandardValuesSupported ((ITypeDescriptorContext)this)) { + TypeConverter.StandardValuesCollection values = + (TypeConverter.StandardValuesCollection) converter.GetStandardValues ((ITypeDescriptorContext)this); + if (values != null) { + for (int i = 0; i < values.Count; i++) { + if (value != null && value.Equals (values[i])){ + if (i < values.Count-1) + success = SetValue (values[i+1], out error); + else + success = SetValue (values[0], out error); + break; + } + } + } + } + } + if (!success && error != null) + property_grid.ShowError (error); + return success; + } + + public bool SetValue (object value, out string error) + { + error = null; + if (this.IsReadOnly) + return false; + + if (SetValueCore (value, out error)) { + InvalidateChildGridItemsCache (); + property_grid.OnPropertyValueChangedInternal (this, this.Value); + return true; + } + return false; + } + + protected virtual bool SetValueCore (object value, out string error) + { + error = null; + + TypeConverter converter = GetConverter (); + Type valueType = value != null ? value.GetType () : null; + // if the new value is not of the same type try to convert it + if (valueType != null && this.PropertyDescriptor.PropertyType != null && + !this.PropertyDescriptor.PropertyType.IsAssignableFrom (valueType)) { + bool conversionError = false; + try { + if (converter != null && + converter.CanConvertFrom ((ITypeDescriptorContext)this, valueType)) + value = converter.ConvertFrom ((ITypeDescriptorContext)this, + CultureInfo.CurrentCulture, value); + else + conversionError = true; + } catch (Exception e) { + error = e.Message; + conversionError = true; + } + if (conversionError) { + string valueText = ConvertToString (value); + string errorShortDescription = null; + if (valueText != null) { + errorShortDescription = "Property value '" + valueText + "' of '" + + PropertyDescriptor.Name + "' is not convertible to type '" + + this.PropertyDescriptor.PropertyType.Name + "'"; + + } else { + errorShortDescription = "Property value of '" + + PropertyDescriptor.Name + "' is not convertible to type '" + + this.PropertyDescriptor.PropertyType.Name + "'"; + } + error = errorShortDescription + Environment.NewLine + Environment.NewLine + error; + return false; + } + } + + bool changed = false; + bool current_changed = false; + object[] propertyOwners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + for (int i=0; i < propertyOwners.Length; i++) { + object currentVal = properties[i].GetValue (propertyOwners[i]); + current_changed = false; + if (!Object.Equals (currentVal, value)) { + if (this.ShouldCreateParentInstance) { + Hashtable updatedParentProperties = new Hashtable (); + PropertyDescriptorCollection parentProperties = TypeDescriptor.GetProperties (propertyOwners[i]); + foreach (PropertyDescriptor property in parentProperties) { + if (property.Name == properties[i].Name) + updatedParentProperties[property.Name] = value; + else + updatedParentProperties[property.Name] = property.GetValue (propertyOwners[i]); + } + object updatedParentValue = this.ParentEntry.PropertyDescriptor.Converter.CreateInstance ( + (ITypeDescriptorContext)this, updatedParentProperties); + if (updatedParentValue != null) + current_changed = this.ParentEntry.SetValueCore (updatedParentValue, out error); + } else { + try { + properties[i].SetValue (propertyOwners[i], value); + } catch { + // MS seems to swallow this + // + // string valueText = ConvertToString (value); + // if (valueText != null) + // error = "Property value '" + valueText + "' of '" + properties[i].Name + "' is invalid."; + // else + // error = "Property value of '" + properties[i].Name + "' is invalid."; + return false; + } + + if (IsValueType (this.ParentEntry)) + current_changed = ParentEntry.SetValueCore (propertyOwners[i], out error); + else + current_changed = Object.Equals (properties[i].GetValue (propertyOwners[i]), value); + } + } + if (current_changed) + changed = true; + } + return changed; + } + + private bool IsValueType (GridEntry item) + { + if (item != null && item.PropertyDescriptor != null && + (item.PropertyDescriptor.PropertyType.IsValueType || + item.PropertyDescriptor.PropertyType.IsPrimitive)) + return true; + return false; + } + + public bool ResetValue () + { + if (IsResetable) { + object[] owners = this.PropertyOwners; + PropertyDescriptor[] properties = PropertyDescriptors; + for (int i=0; i < owners.Length; i++) { + properties[i].ResetValue (owners[i]); + if (IsValueType (this.ParentEntry)) { + string error = null; + if (!ParentEntry.SetValueCore (owners[i], out error) && error != null) + property_grid.ShowError (error); + } + } + property_grid.OnPropertyValueChangedInternal (this, this.Value); + return true; + } + return false; + } + + public bool HasDefaultValue { + get { + if (PropertyDescriptor != null) + return !PropertyDescriptor.ShouldSerializeValue (PropertyOwner); + return false; + } + } + + // Determines if the current value can be reset + // + public virtual bool IsResetable { + get { return (!IsReadOnly && PropertyDescriptor.CanResetValue (PropertyOwner)); } + + } + + // If false the entry can be modified only by the means of a predefined values + // and not such inputed by the user. + // + public virtual bool IsEditable { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor == null) + return false; + else if (PropertyDescriptor.PropertyType.IsArray) + return false; + else if (PropertyDescriptor.IsReadOnly && !this.ShouldCreateParentInstance) + return false; + else if (converter == null || + !converter.CanConvertFrom ((ITypeDescriptorContext)this, typeof (string))) + return false; + else if (converter.GetStandardValuesSupported ((ITypeDescriptorContext)this) && + converter.GetStandardValuesExclusive ((ITypeDescriptorContext)this)) + return false; + else + return true; + } + } + + // If true the the entry cannot be modified at all + // + public virtual bool IsReadOnly { + get { + TypeConverter converter = GetConverter (); + if (PropertyDescriptor == null || PropertyOwner == null) + return true; + else if (PropertyDescriptor.IsReadOnly && + (EditorStyle != UITypeEditorEditStyle.Modal || PropertyDescriptor.PropertyType.IsValueType) && + !this.ShouldCreateParentInstance) + return true; + else if (PropertyDescriptor.IsReadOnly && + TypeDescriptor.GetAttributes (PropertyDescriptor.PropertyType) + [typeof(ImmutableObjectAttribute)].Equals (ImmutableObjectAttribute.Yes)) + return true; + else if (ShouldCreateParentInstance && ParentEntry.IsReadOnly) + return true; + else if (!HasCustomEditor && converter == null) + return true; + else if (converter != null && + !converter.GetStandardValuesSupported ((ITypeDescriptorContext)this) && + !converter.CanConvertFrom ((ITypeDescriptorContext)this, + typeof (string)) && + !HasCustomEditor) { + return true; + } else if (PropertyDescriptor.PropertyType.IsArray && !HasCustomEditor) + return true; + else + return false; + } + } + + public bool IsPassword { + get { + if (PropertyDescriptor != null) + return PropertyDescriptor.Attributes.Contains (PasswordPropertyTextAttribute.Yes); + return false; + } + } + // This is a way to set readonly properties (e.g properties without a setter). + // The way it works is that if CreateInstance is supported by the parent's converter + // it gets passed a list of properties and their values which it uses to create an + // instance (e.g by passing them to the ctor of that object type). + // + // This is used for e.g Font + // + public virtual bool ShouldCreateParentInstance { + get { + if (this.ParentEntry != null && ParentEntry.PropertyDescriptor != null) { + TypeConverter parentConverter = ParentEntry.GetConverter (); + if (parentConverter != null && parentConverter.GetCreateInstanceSupported ((ITypeDescriptorContext)this)) + return true; + } + return false; + } + } + + public virtual bool PaintValueSupported { + get { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + return editor.GetPaintValueSupported (); + } catch { + // Some of our Editors throw NotImplementedException + } + } + return false; + } + } + + public virtual void PaintValue (Graphics gfx, Rectangle rect) + { + UITypeEditor editor = GetEditor (); + if (editor != null) { + try { + editor.PaintValue (this.Value, gfx, rect); + } catch { + // Some of our Editors throw NotImplementedException + } + } + } + +#region Population + protected void PopulateChildGridItems () + { + grid_items = GetChildGridItemsCached (); + } + + private void InvalidateChildGridItemsCache () + { + if (child_griditems_cache != null) { + child_griditems_cache = null; + PopulateChildGridItems (); + } + } + + private GridItemCollection GetChildGridItemsCached () + { + if (child_griditems_cache == null) { + child_griditems_cache = GetChildGridItems (); + // foreach (GridEntry item in child_griditems_cache) + // PrintDebugInfo (item); + } + + return child_griditems_cache; + } + + // private static void PrintDebugInfo (GridEntry item) + // { + // if (item.PropertyDescriptor != null) { + // Console.WriteLine ("=== [" + item.PropertyDescriptor.Name + "] ==="); + // try { + // TypeConverter converter = item.GetConverter (); + // Console.WriteLine ("IsReadOnly: " + item.IsReadOnly); + // Console.WriteLine ("IsEditable: " + item.IsEditable); + // Console.WriteLine ("PropertyDescriptor.IsReadOnly: " + item.PropertyDescriptor.IsReadOnly); + // if (item.ParentEntry != null) + // Console.WriteLine ("ParentEntry.IsReadOnly: " + item.ParentEntry.IsReadOnly); + // Console.WriteLine ("ImmutableObjectAttribute.Yes: " + TypeDescriptor.GetAttributes (item.PropertyDescriptor.PropertyType) + // [typeof(ImmutableObjectAttribute)].Equals (ImmutableObjectAttribute.Yes)); + // UITypeEditor editor = item.GetEditor (); + // Console.WriteLine ("Editor: " + (editor == null ? "none" : editor.GetType ().Name)); + // if (editor != null) + // Console.WriteLine ("Editor.EditorStyle: " + editor.GetEditStyle ((ITypeDescriptorContext)item)); + // Console.WriteLine ("Converter: " + (converter == null ? "none" : converter.GetType ().Name)); + // if (converter != null) { + // Console.WriteLine ("Converter.GetStandardValuesSupported: " + converter.GetStandardValuesSupported ((ITypeDescriptorContext)item).ToString ()); + // Console.WriteLine ("Converter.GetStandardValuesExclusive: " + converter.GetStandardValuesExclusive ((ITypeDescriptorContext)item).ToString ()); + // Console.WriteLine ("ShouldCreateParentInstance: " + item.ShouldCreateParentInstance); + // Console.WriteLine ("CanConvertFrom (string): " + converter.CanConvertFrom ((ITypeDescriptorContext)item, typeof (string))); + // } + // Console.WriteLine ("IsArray: " + item.PropertyDescriptor.PropertyType.IsArray.ToString ()); + // } catch { /* Some converters and editor throw NotImplementedExceptions */ } + // } + // } + + private GridItemCollection GetChildGridItems () + { + object[] propertyOwners = this.Values; + string[] propertyNames = GetMergedPropertyNames (propertyOwners); + GridItemCollection items = new GridItemCollection (); + + foreach (string propertyName in propertyNames) { + PropertyDescriptor[] properties = new PropertyDescriptor[propertyOwners.Length]; + for (int i=0; i < propertyOwners.Length; i++) + properties[i] = GetPropertyDescriptor (propertyOwners[i], propertyName); + items.Add (new GridEntry (property_grid, properties, this)); + } + + return items; + } + + private bool IsPropertyMergeable (PropertyDescriptor property) + { + if (property == null) + return false; + + MergablePropertyAttribute attrib = property.Attributes [typeof (MergablePropertyAttribute)] as MergablePropertyAttribute; + if (attrib != null && !attrib.AllowMerge) + return false; + + return true; + } + + private string[] GetMergedPropertyNames (object [] objects) + { + if (objects == null || objects.Length == 0) + return new string[0]; + + ArrayList intersection = new ArrayList (); + for (int i = 0; i < objects.Length; i ++) { + if (objects [i] == null) + continue; + + PropertyDescriptorCollection properties = GetProperties (objects[i], property_grid.BrowsableAttributes); + ArrayList new_intersection = new ArrayList (); + + foreach (PropertyDescriptor currentProperty in (i == 0 ? (ICollection)properties : (ICollection)intersection)) { + PropertyDescriptor matchingProperty = (i == 0 ? currentProperty : properties [currentProperty.Name]); + if (objects.Length > 1 && !IsPropertyMergeable (matchingProperty)) + continue; + if (matchingProperty.PropertyType == currentProperty.PropertyType) + new_intersection.Add (matchingProperty); + } + + intersection = new_intersection; + } + + string[] propertyNames = new string [intersection.Count]; + for (int i=0; i < intersection.Count; i++) + propertyNames[i] = ((PropertyDescriptor)intersection[i]).Name; + + return propertyNames; + } + + private PropertyDescriptor GetPropertyDescriptor (object propertyOwner, string propertyName) + { + if (propertyOwner == null || propertyName == null) + return null; + + PropertyDescriptorCollection properties = GetProperties (propertyOwner, property_grid.BrowsableAttributes); + if (properties != null) + return properties[propertyName]; + return null; + } + + private PropertyDescriptorCollection GetProperties (object propertyOwner, AttributeCollection attributes) + { + if (propertyOwner == null || property_grid.SelectedTab == null) + return new PropertyDescriptorCollection (null); + + Attribute[] atts = new Attribute[attributes.Count]; + attributes.CopyTo (atts, 0); + return property_grid.SelectedTab.GetProperties ((ITypeDescriptorContext)this, propertyOwner, atts); + } +#endregion + } +} |
