| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- // 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 System.Windows.Forms;
- using System.Windows.Forms.Design;
- using System.ComponentModel;
- using System.ComponentModel.Design;
- namespace System.Windows.Forms.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;
- #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;
- }
- // 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 { return grid_items.Count > 0; }
- }
- public override bool Expanded {
- get { return expanded; }
- set {
- if (expanded != value) {
- if (value)
- property_grid.OnExpandItem (this);
- else
- property_grid.OnCollapseItem (this);
- expanded = value;
- }
- }
- }
- public override GridItemCollection GridItems {
- get { return grid_items; }
- }
- public override GridItemType GridItemType {
- get { return GridItemType.Property; }
- }
- public override string Label {
- get { return PropertyDescriptor.Name; }
- }
- 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 ParentEntry.Values;
- return null;
- }
- }
- // 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);
- }
- }
- public string ValueText {
- get { return ConvertToString (this.Value); }
- }
- 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 { return PropertyOwner; }
- }
- PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor {
- get { 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 {
- if (PropertyDescriptor != null && PropertyDescriptor.Converter != null &&
- PropertyDescriptor.Converter.GetStandardValuesSupported ()) {
- ArrayList values = new ArrayList ();
- string stringVal = null;
- ICollection standardValues = PropertyDescriptor.Converter.GetStandardValues ();
- 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 (typeof (string))) {
- try {
- return PropertyDescriptor.Converter.ConvertToString (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 GetEditor() != null; }
- }
- 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 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
- return PropertyDescriptor.GetEditor (typeof (UITypeEditor)) as UITypeEditor;
- } catch {
- // property_grid.ShowError ("Unable to load UITypeEditor for property '" + PropertyDescriptor.Name + "'.");
- }
- }
- return null;
- }
- public bool ToggleValue ()
- {
- if (IsReadOnly || (IsMerged && !HasMergedValue))
- return false;
- bool success = false;
- string error = null;
- if (PropertyDescriptor.PropertyType == typeof(bool))
- success = SetValue (!(bool)this.Value, out error);
- else if (PropertyDescriptor.Converter != null &&
- PropertyDescriptor.Converter.GetStandardValuesSupported ()) {
- TypeConverter.StandardValuesCollection values =
- (TypeConverter.StandardValuesCollection) PropertyDescriptor.Converter.GetStandardValues();
- if (values != null) {
- for (int i = 0; i < values.Count; i++) {
- if (this.Value != null && this.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)) {
- property_grid.OnPropertyValueChangedInternal (this, this.Value);
- return true;
- }
- return false;
- }
- protected virtual bool SetValueCore (object value, out string error)
- {
- error = null;
- TypeConverter converter = PropertyDescriptor.Converter;
- // if the new value is not of the same type try to convert it
- if (value != null &&
- (this.Value == null ||
- this.Value != null && value.GetType () != this.Value.GetType ())) {
- bool conversionError = false;
- if (converter != null &&
- converter.CanConvertFrom (value.GetType ())) {
- try {
- value = converter.ConvertFrom (value);
- } catch {
- conversionError = true;
- }
- } else {
- conversionError = true;
- }
- if (conversionError) {
- // MS swallows those
- //
- // string valueText = ConvertToString (value);
- // if (valueText != null) {
- // error = "Property value '" + valueText + "' of '" +
- // PropertyDescriptor.Name + "' is not convertible to type '" +
- // this.PropertyDescriptor.PropertyType.Name + "'";
- //
- // } else {
- // error = "Property value of '" +
- // PropertyDescriptor.Name + "' is not convertible to type '" +
- // this.PropertyDescriptor.PropertyType.Name + "'";
- // }
- 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 (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);
- }
- // restore original value if doesn't get set
- if (!current_changed && !PropertyDescriptor.IsReadOnly)
- properties[i].SetValue (propertyOwners[i], currentVal);
- }
- 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 &&
- PropertyDescriptor.Attributes[typeof (DefaultValueAttribute)] != null)
- return true;
- 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 {
- if (PropertyDescriptor == null)
- return false;
- else if (PropertyDescriptor.PropertyType.IsArray)
- return false;
- else if (PropertyDescriptor.IsReadOnly && this.ShouldCreateParentInstance)
- return true;
- else if (PropertyDescriptor.Converter == null ||
- !PropertyDescriptor.Converter.CanConvertFrom (this, typeof (string)))
- return false;
- else if (PropertyDescriptor.Converter.GetStandardValuesSupported () &&
- PropertyDescriptor.Converter.GetStandardValuesExclusive ())
- return false;
- else
- return true;
- }
- }
- // If true the the entry cannot be modified at all
- //
- public virtual bool IsReadOnly {
- get {
- // if (PropertyDescriptor != null) {
- // Console.WriteLine ("=== [" + PropertyDescriptor.Name + "]");
- // Console.WriteLine ("PropertyDescriptor.IsReadOnly: " + PropertyDescriptor.IsReadOnly);
- // Console.WriteLine ("Editor: " + (GetEditor () == null ? "none" : GetEditor ().GetType ().Name));
- // Console.WriteLine ("Converter: " + (PropertyDescriptor.Converter == null ? "none" : PropertyDescriptor.Converter.GetType ().Name));
- // Console.WriteLine ("Converter.GetStandardValuesSupported: " + PropertyDescriptor.Converter.GetStandardValuesSupported ().ToString ());
- // Console.WriteLine ("Converter.GetStandardValuesExclusive: " + PropertyDescriptor.Converter.GetStandardValuesExclusive ().ToString ());
- // Console.WriteLine ("ShouldCreateParentInstance: " + this.ShouldCreateParentInstance);
- // Console.WriteLine ("CanConvertFrom (string): " + PropertyDescriptor.Converter.CanConvertFrom ((ITypeDescriptorContext)this, typeof (string)));
- // Console.WriteLine ("IsArray: " + PropertyDescriptor.PropertyType.IsArray.ToString ());
- // }
- if (PropertyDescriptor == null || PropertyOwner == null ||
- (PropertyDescriptor.IsReadOnly && !this.ShouldCreateParentInstance))
- return true;
- else if (!HasCustomEditor && PropertyDescriptor.Converter == null)
- return true;
- else if (PropertyDescriptor.Converter != null &&
- !PropertyDescriptor.Converter.GetStandardValuesSupported () &&
- !PropertyDescriptor.Converter.CanConvertFrom ((ITypeDescriptorContext)this,
- typeof (string)) &&
- !HasCustomEditor) {
- return true;
- } else if (PropertyDescriptor.PropertyType.IsArray && !HasCustomEditor)
- return true;
- else
- 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 = Parent.PropertyDescriptor.Converter;
- 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
- }
- }
- }
- }
- }
|