Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLluis Sanchez <lluis@novell.com>2010-03-17 15:35:28 +0300
committerLluis Sanchez <lluis@novell.com>2010-03-17 15:35:28 +0300
commit8fa37870e9cc22ffccdd494fa951b2c3807d7978 (patch)
treebda14806802947c51676c183b08f166878964c40 /main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid
parentf1a8582658af8aeb0f6fa459965a2e4d0684c347 (diff)
parent585086f0ea0a49166046bb8f48d2def87907d0e0 (diff)
Merged MD.Projects into MD.Core, and MD.Projects.Gui, MD.Core.Gui and MD.Components into MD.Ide.
svn path=/trunk/monodevelop/; revision=153730
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/DefaultPropertyTab.cs98
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EditorManager.cs182
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EventPropertyTab.cs86
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorCell.cs406
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorTypeAttribute.cs63
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs467
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGridTree.cs711
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventArgs.cs65
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventHandler.cs37
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/SurrogateUITypeEditorAttribute.cs61
10 files changed, 2176 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/DefaultPropertyTab.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/DefaultPropertyTab.cs
new file mode 100644
index 0000000000..55737bfa78
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/DefaultPropertyTab.cs
@@ -0,0 +1,98 @@
+ /*
+ * DefaultPropertyTab.cs - The default PropertyTab
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using Gtk;
+using System;
+using System.ComponentModel;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ public class DefaultPropertyTab : PropertyTab
+ {
+ public DefaultPropertyTab ()
+ : base ()
+ {
+ }
+
+ public override string TabName {
+ get {return GettextCatalog.GetString ("Properties"); }
+ }
+
+ public override bool CanExtend (object extendee)
+ {
+ return true;
+ }
+
+ public override PropertyDescriptor GetDefaultProperty (object component)
+ {
+ if (component == null)
+ return null;
+ return TypeDescriptor.GetDefaultProperty (component);
+ }
+
+ public override PropertyDescriptorCollection GetProperties (object component, Attribute[] attributes)
+ {
+ if (component == null)
+ return new PropertyDescriptorCollection (new PropertyDescriptor[] {});
+ return TypeDescriptor.GetProperties (component);
+ }
+ }
+
+ public abstract class PropertyTab
+ {
+ public abstract string TabName { get; }
+ public abstract bool CanExtend (object extendee);
+ public abstract PropertyDescriptor GetDefaultProperty (object component);
+ public abstract PropertyDescriptorCollection GetProperties (object component, Attribute[] attributes);
+
+ public PropertyDescriptorCollection GetProperties (object component)
+ {
+ return GetProperties (component, null);
+ }
+
+ public Gdk.Pixbuf GetIcon ()
+ {
+ using (var stream = GetType ().Assembly.GetManifestResourceStream (GetType ().FullName + ".bmp")) {
+ if (stream != null) {
+ try {
+ return new Gdk.Pixbuf (stream);
+ } catch (Exception e) {
+ LoggingService.LogError ("Can't create pixbuf from resource:" + GetType ().FullName + ".bmp", e);
+ }
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EditorManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EditorManager.cs
new file mode 100644
index 0000000000..5ec06c6c97
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EditorManager.cs
@@ -0,0 +1,182 @@
+/*
+ * EditorManager.cs - Used to register, lookup and select visual editors.
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ * Lluis Sanchez Gual
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+using System.Collections;
+using System.Reflection;
+using System.ComponentModel;
+using MonoDevelop.Components.PropertyGrid.PropertyEditors;
+using System.Drawing.Design;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ internal class EditorManager
+ {
+ private Hashtable editors = new Hashtable ();
+ private Hashtable inheritingEditors = new Hashtable ();
+ private Hashtable surrogates = new Hashtable ();
+ static PropertyEditorCell Default = new PropertyEditorCell ();
+ static Hashtable cellCache = new Hashtable ();
+
+ internal EditorManager ()
+ {
+ LoadEditor (Assembly.GetAssembly (typeof (EditorManager)));
+ }
+
+ public void LoadEditor (Assembly editorAssembly)
+ {
+ foreach (Type t in editorAssembly.GetTypes ()) {
+ foreach (Attribute currentAttribute in Attribute.GetCustomAttributes (t)) {
+ if (currentAttribute.GetType() == typeof (PropertyEditorTypeAttribute)) {
+ PropertyEditorTypeAttribute peta = (PropertyEditorTypeAttribute)currentAttribute;
+ Type editsType = peta.Type;
+ if (t.IsSubclassOf (typeof (PropertyEditorCell)))
+ if (peta.Inherits)
+ inheritingEditors.Add (editsType, t);
+ else
+ editors.Add (editsType, t);
+ }
+ else if (currentAttribute.GetType () == typeof (SurrogateUITypeEditorAttribute)) {
+ Type editsType = (currentAttribute as SurrogateUITypeEditorAttribute).Type;
+ surrogates.Add (editsType, t);
+ }
+ }
+ }
+ }
+
+ public PropertyEditorCell GetEditor (PropertyDescriptor pd)
+ {
+ PropertyEditorCell cell = pd.GetEditor (typeof(PropertyEditorCell)) as PropertyEditorCell;
+ if (cell != null)
+ return cell;
+
+ Type editorType = GetEditorType (pd);
+ if (editorType == null)
+ return Default;
+
+ if (typeof(IPropertyEditor).IsAssignableFrom (editorType)) {
+ if (!typeof(Gtk.Widget).IsAssignableFrom (editorType))
+ throw new Exception ("The property editor '" + editorType + "' must be a Gtk Widget");
+ return Default;
+ }
+
+ cell = cellCache [editorType] as PropertyEditorCell;
+ if (cell != null)
+ return cell;
+
+ if (!typeof(PropertyEditorCell).IsAssignableFrom (editorType))
+ throw new Exception ("The property editor '" + editorType + "' must be a subclass of Stetic.PropertyEditorCell or implement Stetic.IPropertyEditor");
+
+ cell = (PropertyEditorCell) Activator.CreateInstance (editorType);
+ cellCache [editorType] = cell;
+ return cell;
+ }
+
+ public Type GetEditorType (PropertyDescriptor pd)
+ {
+ //try to find a custom editor
+ //TODO: Find a way to provide a IWindowsFormsEditorService so this can work directly
+ //for now, substitute GTK#-based editors
+ /*
+ UITypeEditor UITypeEd = (UITypeEditor) pd.GetEditor(typeof (System.Drawing.Design.UITypeEditor));//first, does it have custom editors?
+ if (UITypeEd != null)
+ if (surrogates.Contains(UITypeEd.GetType ()))
+ return instantiateEditor((Type) surrogates[UITypeEd.GetType()], parentRow);
+ */
+
+ //does a registered GTK# editor support this natively?
+ Type editType = pd.PropertyType;
+ if (editors.Contains (editType))
+ return (Type) editors [editType];
+
+ //editors that edit derived types
+ foreach (DictionaryEntry de in inheritingEditors)
+ if (editType.IsSubclassOf((Type) de.Key))
+ return (Type) de.Value;
+
+ if (pd.PropertyType.IsEnum) {
+ if (pd.PropertyType.IsDefined (typeof (FlagsAttribute), true))
+ return typeof (PropertyEditors.FlagsEditorCell);
+ else
+ return typeof (PropertyEditors.EnumerationEditorCell);
+ }
+
+ //collections with items of single type that aren't just objects
+ if (typeof(IList).IsAssignableFrom (editType)) {
+ // Iterate through all properties since there may be more than one indexer.
+ if (GetCollectionItemType (editType) != null)
+ return typeof (CollectionEditor);
+ }
+
+ //TODO: support simple SWF collection editor derivatives that just override Types available
+ // and reflect protected Type[] NewItemTypes {get;} to get types
+ //if (UITypeEd is System.ComponentModel.Design.CollectionEditor)
+ // ((System.ComponentModel.Design.CollectionEditor)UITypeEd).
+
+ //can we use a type converter with a built-in editor?
+ TypeConverter tc = pd.Converter;
+
+ if (typeof (ExpandableObjectConverter).IsAssignableFrom (tc.GetType ()))
+ return typeof(ExpandableObjectEditor);
+
+ //This is a temporary workaround *and* and optimisation
+ //First, most unknown types will be most likely to convert to/from strings
+ //Second, System.Web.UI.WebControls/UnitConverter.cs dies on non-strings
+ if (tc.CanConvertFrom (typeof (string)) && tc.CanConvertTo (typeof(string)))
+ return typeof(TextEditor);
+
+ foreach (DictionaryEntry editor in editors)
+ if (tc.CanConvertFrom((Type) editor.Key) && tc.CanConvertTo((Type) editor.Key))
+ return (Type) editor.Value;
+
+ foreach (DictionaryEntry de in inheritingEditors)
+ if (tc.CanConvertFrom((Type) de.Key) && tc.CanConvertTo((Type) de.Key))
+ return (Type) de.Value;
+
+ //nothing found - just display type
+ return null;
+ }
+
+ public static Type GetCollectionItemType (Type colType)
+ {
+ foreach (PropertyInfo member in colType.GetProperties ()) {
+ if (member.Name == "Item") {
+ if (member.PropertyType != typeof (object))
+ return member.PropertyType;
+ }
+ }
+ return null;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EventPropertyTab.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EventPropertyTab.cs
new file mode 100644
index 0000000000..32d03e4e03
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/EventPropertyTab.cs
@@ -0,0 +1,86 @@
+ /*
+ * EventPropertyTab.cs - A PropertyTab that displays events
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using MonoDevelop.Core;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ public class EventPropertyTab : PropertyTab
+ {
+ public EventPropertyTab ()
+ {
+ }
+
+ public override string TabName {
+ get {return GettextCatalog.GetString ("Events"); }
+ }
+
+ public override bool CanExtend (object extendee)
+ {
+ IComponent comp = extendee as IComponent;
+ if (comp == null || comp.Site == null)
+ return false;
+
+ IEventBindingService evtBind = (IEventBindingService) comp.Site.GetService (typeof (IEventBindingService));
+ return !(evtBind == null);
+ }
+
+ public override PropertyDescriptor GetDefaultProperty (object component)
+ {
+ IEventBindingService evtBind = GetEventService (component);
+ EventDescriptor e = TypeDescriptor.GetDefaultEvent (component);
+
+ return (e == null)? null : evtBind.GetEventProperty (e);
+ }
+
+ public override PropertyDescriptorCollection GetProperties (object component, Attribute[] attributes)
+ {
+ IEventBindingService evtBind = GetEventService (component);
+ return evtBind.GetEventProperties (TypeDescriptor.GetEvents (component));
+ }
+
+ private IEventBindingService GetEventService (object component)
+ {
+ IComponent comp = component as IComponent;
+ if (comp == null || comp.Site == null)
+ throw new Exception ("Check whether a tab can display a component before displaying it");
+ IEventBindingService evtBind = (IEventBindingService) comp.Site.GetService (typeof (IEventBindingService));
+ if (evtBind == null)
+ throw new Exception ("Check whether a tab can display a component before displaying it");
+ return evtBind;
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorCell.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorCell.cs
new file mode 100644
index 0000000000..f95fc7cc35
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorCell.cs
@@ -0,0 +1,406 @@
+//
+// PropertyEditorCell.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// 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.
+//
+
+using System;
+using System.Reflection;
+using System.Collections;
+using System.ComponentModel;
+using MonoDevelop.Components.PropertyGrid.PropertyEditors;
+using Gtk;
+using Gdk;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ public class PropertyEditorCell
+ {
+ Pango.Layout layout;
+ PropertyDescriptor property;
+ object obj;
+ Gtk.Widget container;
+ EditorManager editorManager;
+
+ public object Instance {
+ get { return obj; }
+ }
+
+ public PropertyDescriptor Property {
+ get { return property; }
+ }
+
+ public Gtk.Widget Container {
+ get { return container; }
+ }
+
+ internal EditorManager EditorManager {
+ get { return editorManager; }
+ }
+
+ internal void Initialize (Widget container, EditorManager editorManager, PropertyDescriptor property, object obj)
+ {
+ this.container = container;
+ this.editorManager = editorManager;
+
+ layout = new Pango.Layout (container.PangoContext);
+ layout.Width = -1;
+
+ Pango.FontDescription des = container.Style.FontDescription.Copy();
+ layout.FontDescription = des;
+
+ this.property = property;
+ this.obj = obj;
+ Initialize ();
+ }
+
+ public EditSession StartEditing (Gdk.Rectangle cell_area, StateType state)
+ {
+ IPropertyEditor ed = CreateEditor (cell_area, state);
+ if (ed == null)
+ return null;
+ return new EditSession (container, obj, property, ed);
+ }
+
+ protected virtual string GetValueText ()
+ {
+ if (obj == null) return "";
+ object val = property.GetValue (obj);
+ if (val == null) return "";
+ else return property.Converter.ConvertToString (val);
+ }
+
+ protected virtual string GetValueMarkup ()
+ {
+ return null;
+ }
+
+ string GetNormalizedText (string s)
+ {
+ if (s == null)
+ return "";
+
+ int i = s.IndexOf ('\n');
+ if (i == -1)
+ return s;
+
+ s = s.TrimStart ('\n',' ','\t');
+ i = s.IndexOf ('\n');
+ if (i != -1)
+ return s.Substring (0, i) + "...";
+ else
+ return s;
+ }
+
+ public object Value {
+ get { return obj != null ? property.GetValue (obj) : null; }
+ }
+
+ protected virtual void Initialize ()
+ {
+ string s = GetValueMarkup ();
+ if (s != null)
+ layout.SetMarkup (GetNormalizedText (s));
+ else
+ layout.SetText (GetNormalizedText (GetValueText ()));
+ }
+
+ public virtual void GetSize (int availableWidth, out int width, out int height)
+ {
+ layout.GetPixelSize (out width, out height);
+ }
+
+ public virtual void Render (Drawable window, Gdk.Rectangle bounds, StateType state)
+ {
+ int w, h;
+ layout.GetPixelSize (out w, out h);
+ int dy = (bounds.Height - h) / 2;
+ window.DrawLayout (container.Style.TextGC (state), bounds.X, dy + bounds.Y, layout);
+ }
+
+ protected virtual IPropertyEditor CreateEditor (Gdk.Rectangle cell_area, StateType state)
+ {
+ if (DialogueEdit && (!property.IsReadOnly || EditsReadOnlyObject)) {
+ return new PropertyDialogueEditor (this);
+ }
+ else {
+ Type editorType = editorManager.GetEditorType (property);
+ if (editorType == null)
+ return null;
+
+ IPropertyEditor editor = Activator.CreateInstance (editorType) as IPropertyEditor;
+ if (editor == null)
+ throw new Exception ("The property editor '" + editorType + "' must implement the interface IPropertyEditor");
+ return editor;
+ }
+ }
+
+ /// <summary>
+ /// Whether the editor should show a button.
+ /// </summary>
+ public virtual bool DialogueEdit {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// If the property is read-only, is is usually not edited. If the editor
+ /// can edit sub-properties of a read-only complex object, this must return true.
+ /// <remarks>The default value is false.</remarks>
+ /// </summary>
+ /// <returns>True if the editor can edit read-only properties</returns>
+ public virtual bool EditsReadOnlyObject {
+ get { return false; }
+ }
+
+ public virtual void LaunchDialogue ()
+ {
+ if (DialogueEdit)
+ throw new NotImplementedException();
+ }
+ }
+
+
+ class DefaultPropertyEditor: Gtk.Entry, IPropertyEditor
+ {
+ PropertyDescriptor property;
+
+ public void Initialize (EditSession session)
+ {
+ this.property = session.Property;
+ }
+
+ public object Value {
+ get {
+ return Convert.ChangeType (Text, property.PropertyType);
+ }
+ set {
+ if (value == null)
+ Text = "";
+ else
+ Text = Convert.ToString (value);
+ }
+ }
+
+ protected override void OnChanged ()
+ {
+ base.OnChanged ();
+ if (ValueChanged != null)
+ ValueChanged (this, EventArgs.Empty);
+ }
+
+ public event EventHandler ValueChanged;
+ }
+
+ public class EditSession : ITypeDescriptorContext
+ {
+ PropertyDescriptor property;
+ object obj;
+ Gtk.Widget container;
+ IPropertyEditor currentEditor;
+ bool syncing;
+
+ public event EventHandler Changed;
+
+ public EditSession (Gtk.Widget container, object instance, PropertyDescriptor property, IPropertyEditor currentEditor)
+ {
+ this.property = property;
+ this.obj = instance;
+ this.container = container;
+ this.currentEditor = currentEditor;
+
+ currentEditor.Initialize (this);
+ if (instance != null)
+ currentEditor.Value = property.GetValue (instance);
+
+ currentEditor.ValueChanged += OnValueChanged;
+ }
+
+ public void Dispose ()
+ {
+ currentEditor.Dispose ();
+ }
+
+ public object Instance {
+ get { return obj; }
+ }
+
+ public PropertyDescriptor Property {
+ get { return property; }
+ }
+
+ PropertyDescriptor ITypeDescriptorContext.PropertyDescriptor {
+ get { return property; }
+ }
+
+ public Gtk.Widget Container {
+ get { return container; }
+ }
+
+ public IPropertyEditor Editor {
+ get { return currentEditor; }
+ }
+
+ void OnValueChanged (object s, EventArgs a)
+ {
+ if (!syncing) {
+ syncing = true;
+ if (!property.IsReadOnly) {
+ property.SetValue (obj, currentEditor.Value);
+ if (Changed != null)
+ Changed (s, a);
+ }
+ syncing = false;
+ }
+ }
+
+/* public void AttachObject (object ob)
+ {
+ if (ob == null)
+ throw new ArgumentNullException ("ob");
+
+ syncing = true;
+ this.obj = ob;
+ currentEditor.AttachObject (obj);
+
+ // It is the responsibility of the editor to convert value types
+ object initial = property.GetValue (obj);
+ currentEditor.Value = initial;
+
+ syncing = false;
+ }
+*/
+ public void UpdateEditor ()
+ {
+ if (!syncing) {
+ syncing = true;
+ currentEditor.Value = property.GetValue (obj);
+ syncing = false;
+ }
+ }
+
+ #region FIXME Unimplemented ITypeDescriptorContext and IServiceProvider members
+
+ object IServiceProvider.GetService (Type serviceType)
+ {
+ return null;
+ }
+
+ void ITypeDescriptorContext.OnComponentChanged ()
+ {
+ }
+
+ bool ITypeDescriptorContext.OnComponentChanging ()
+ {
+ return true;
+ }
+
+ IContainer ITypeDescriptorContext.Container { get { return null; } }
+
+ #endregion
+ }
+
+ class CellRendererWidget: Gtk.DrawingArea
+ {
+ PropertyEditorCell cell;
+ object obj;
+ PropertyDescriptor property;
+ EditorManager em;
+
+ public CellRendererWidget (PropertyEditorCell cell)
+ {
+ this.cell = cell;
+ this.obj = cell.Instance;
+ this.property = cell.Property;
+ em = cell.EditorManager;
+ this.ModifyBg (Gtk.StateType.Normal, this.Style.White);
+ }
+
+ protected override bool OnExposeEvent (EventExpose evnt)
+ {
+ bool res = base.OnExposeEvent (evnt);
+ cell.Initialize (this, em, property, obj);
+
+ Gdk.Rectangle rect = Allocation;
+ rect.Inflate (-3, 0);// Add some margin
+
+ cell.Render (this.GdkWindow, rect, StateType.Normal);
+ return res;
+ }
+ }
+
+ class PropertyDialogueEditor: HBox, IPropertyEditor
+ {
+ PropertyEditorCell cell;
+
+ public PropertyDialogueEditor (PropertyEditorCell cell)
+ {
+ this.cell = cell;
+ Spacing = 3;
+ PackStart (new CellRendererWidget (cell), true, true, 0);
+ Label buttonLabel = new Label ();
+ buttonLabel.UseMarkup = true;
+ buttonLabel.Xpad = 0; buttonLabel.Ypad = 0;
+ buttonLabel.Markup = "<span size=\"small\">...</span>";
+ Button dialogueButton = new Button (buttonLabel);
+ dialogueButton.Clicked += new EventHandler (DialogueButtonClicked);
+ PackStart (dialogueButton, false, false, 0);
+ this.ModifyBg (Gtk.StateType.Normal, this.Style.White);
+ ShowAll ();
+ }
+
+ void DialogueButtonClicked (object s, EventArgs args)
+ {
+ cell.LaunchDialogue ();
+ if (ValueChanged != null)
+ ValueChanged (this, args);
+ }
+
+ public void Initialize (EditSession session)
+ {
+ }
+
+ public object Value {
+ get { return cell.Value; }
+ set { }
+ }
+
+ public event EventHandler ValueChanged;
+
+ }
+
+ public interface IPropertyEditor: IDisposable
+ {
+ // Called once to initialize the editor.
+ void Initialize (EditSession session);
+
+ // Gets/Sets the value of the editor. If the editor supports
+ // several value types, it is the responsibility of the editor
+ // to return values with the expected type.
+ object Value { get; set; }
+
+ // To be fired when the edited value changes.
+ event EventHandler ValueChanged;
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorTypeAttribute.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorTypeAttribute.cs
new file mode 100644
index 0000000000..2b7d2fa623
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyEditorTypeAttribute.cs
@@ -0,0 +1,63 @@
+/*
+ * PropertyTypeAttribute.cs - Shows which types a visual type editor can edit
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Eric Butler <eric@extremeboredom.net>
+ *
+ * Copyright (C) 2005 Eric Butler
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)]
+ public class PropertyEditorTypeAttribute : Attribute
+ {
+ private Type type;
+ private bool inherits = false;
+
+ public PropertyEditorTypeAttribute (Type type)
+ {
+ this.type = type;
+ }
+
+ public PropertyEditorTypeAttribute (Type myType, bool inherits)
+ {
+ this.type = myType;
+ this.inherits = inherits;
+ }
+
+ public bool Inherits {
+ get { return inherits; }
+ }
+
+ public Type Type {
+ get {return type; }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs
new file mode 100644
index 0000000000..56dffeba1b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGrid.cs
@@ -0,0 +1,467 @@
+/*
+ * PropertyGrid.cs - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.comk>
+ * Eric Butler <eric@extremeboredom.net>
+ * Lluis Sanchez Gual <lluis@novell.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ * Copyright (C) 2005 Eric Butler
+ * Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+using System.IO;
+using System.Collections;
+using System.ComponentModel;
+
+using Gtk;
+using Gdk;
+using MonoDevelop.Core;
+using MonoDevelop.Components.PropertyGrid.PropertyEditors;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ [System.ComponentModel.Category("MonoDevelop.Components")]
+ [System.ComponentModel.ToolboxItem(true)]
+ public class PropertyGrid: Gtk.VBox
+ {
+ object currentObject;
+ object[] propertyProviders;
+
+ PropertyGridTree tree;
+ HSeparator helpSeparator;
+ HSeparator toolbarSeparator;
+ VPaned vpaned;
+
+ IToolbarProvider toolbar;
+ RadioButton catButton;
+ RadioButton alphButton;
+ ToggleButton helpButton;
+
+ string descTitle, descText;
+ Label descTitleLabel;
+ TextView descTextView;
+ Gtk.Widget descFrame;
+
+ EditorManager editorManager;
+
+ PropertySort propertySort = PropertySort.Categorized;
+
+ const string PROP_HELP_KEY = "MonoDevelop.PropertyPad.ShowHelp";
+
+ public PropertyGrid (): this (new EditorManager ())
+ {
+ }
+
+ internal PropertyGrid (EditorManager editorManager)
+ {
+ this.editorManager = editorManager;
+
+ #region Toolbar
+
+ PropertyGridToolbar tb = new PropertyGridToolbar ();
+ base.PackStart (tb, false, false, 0);
+ toolbar = tb;
+
+ catButton = new RadioButton ((Gtk.RadioButton)null);
+ catButton.DrawIndicator = false;
+ catButton.Relief = ReliefStyle.None;
+ Gdk.Pixbuf pixbuf = null;
+ try {
+ pixbuf = new Gdk.Pixbuf (typeof (PropertyGrid).Assembly, "MonoDevelop.Components.PropertyGrid.SortByCat.png");
+ } catch (Exception e) {
+ LoggingService.LogError ("Can't create pixbuf from resource: MonoDevelop.Components.PropertyGrid.SortByCat.png", e);
+ }
+ if (pixbuf != null) {
+ catButton.Image = new Gtk.Image (pixbuf);
+ catButton.Image.Show ();
+ }
+ catButton.TooltipText = GettextCatalog.GetString ("Sort in categories");
+ catButton.Toggled += new EventHandler (toolbarClick);
+ toolbar.Insert (catButton, 0);
+
+ alphButton = new RadioButton (catButton);
+ alphButton.DrawIndicator = false;
+ alphButton.Relief = ReliefStyle.None;
+ alphButton.Image = new Gtk.Image (Stock.SortAscending, IconSize.Menu);
+ alphButton.Image.Show ();
+ alphButton.TooltipText = GettextCatalog.GetString ("Sort alphabetically");
+ alphButton.Clicked += new EventHandler (toolbarClick);
+ toolbar.Insert (alphButton, 1);
+
+ catButton.Active = true;
+
+ toolbar.Insert (new SeparatorToolItem (), 2);
+ helpButton = new ToggleButton ();
+ helpButton.Relief = ReliefStyle.None;
+ helpButton.Image = new Gtk.Image (Gtk.Stock.Help, IconSize.Menu);
+ helpButton.TooltipText = GettextCatalog.GetString ("Show help panel");
+ helpButton.Clicked += delegate {
+ ShowHelp = helpButton.Active;
+ MonoDevelop.Core.PropertyService.Set (PROP_HELP_KEY, helpButton.Active);
+ };
+ toolbar.Insert (helpButton, 3);
+
+ #endregion
+
+ vpaned = new VPaned ();
+
+ tree = new PropertyGridTree (editorManager, this);
+ tree.Changed += delegate {
+ Update ();
+ };
+
+ VBox tbox = new VBox ();
+ toolbarSeparator = new HSeparator ();
+ toolbarSeparator.Visible = true;
+ tbox.PackStart (toolbarSeparator, false, false, 0);
+ tbox.PackStart (tree, true, true, 0);
+ helpSeparator = new HSeparator ();
+ tbox.PackStart (helpSeparator, false, false, 0);
+ helpSeparator.NoShowAll = true;
+ vpaned.Pack1 (tbox, true, true);
+
+ AddPropertyTab (new DefaultPropertyTab ());
+ AddPropertyTab (new EventPropertyTab ());
+
+ base.PackEnd (vpaned);
+ base.FocusChain = new Gtk.Widget [] { vpaned };
+
+ helpButton.Active = ShowHelp = MonoDevelop.Core.PropertyService.Get<bool> (PROP_HELP_KEY, true);
+
+ Populate ();
+ UpdateTabs ();
+ }
+
+ public void SetToolbarProvider (IToolbarProvider toolbarProvider)
+ {
+ PropertyGridToolbar t = toolbar as PropertyGridToolbar;
+ if (t == null)
+ throw new InvalidOperationException ("Custom toolbar provider already set");
+ Remove (t);
+ foreach (Widget w in t.Children) {
+ t.Remove (w);
+ toolbarProvider.Insert (w, -1);
+ }
+ t.Destroy ();
+ toolbarSeparator.Hide ();
+ toolbar = toolbarProvider;
+ UpdateTabs ();
+ }
+
+ public event EventHandler Changed {
+ add { tree.Changed += value; }
+ remove { tree.Changed -= value; }
+ }
+
+ internal EditorManager EditorManager {
+ get { return editorManager; }
+ }
+
+ #region Toolbar state and handlers
+
+ private const int FirstTabIndex = 3;
+
+ void toolbarClick (object sender, EventArgs e)
+ {
+ if (sender == alphButton)
+ PropertySort = PropertySort.Alphabetical;
+ else if (sender == catButton)
+ PropertySort = PropertySort.Categorized;
+ else {
+ TabRadioToolButton button = (TabRadioToolButton) sender;
+ if (selectedTab == button.Tab) return;
+ selectedTab = button.Tab;
+ Populate ();
+ }
+ }
+
+ public PropertySort PropertySort {
+ get { return propertySort; }
+ set {
+ if (value != propertySort) {
+ propertySort = value;
+ Populate ();
+ }
+ }
+ }
+
+ ArrayList propertyTabs = new ArrayList ();
+ PropertyTab selectedTab;
+
+ public PropertyTab SelectedTab {
+ get { return selectedTab; }
+ }
+
+ TabRadioToolButton firstTab;
+
+ private void AddPropertyTab (PropertyTab tab)
+ {
+ TabRadioToolButton rtb;
+ if (propertyTabs.Count == 0) {
+ selectedTab = tab;
+ rtb = new TabRadioToolButton (null);
+ rtb.Active = true;
+ firstTab = rtb;
+ toolbar.Insert (new SeparatorToolItem (), FirstTabIndex - 1);
+ }
+ else
+ rtb = new TabRadioToolButton (firstTab);
+
+ //load image from PropertyTab's bitmap
+ var icon = tab.GetIcon ();
+ if (icon != null)
+ rtb.Image = new Gtk.Image (icon);
+ else
+ rtb.Image = new Gtk.Image (Stock.MissingImage, IconSize.Menu);
+
+ rtb.Tab = tab;
+ rtb.TooltipText = tab.TabName;
+ rtb.Toggled += new EventHandler (toolbarClick);
+
+ toolbar.Insert (rtb, propertyTabs.Count + FirstTabIndex);
+
+ propertyTabs.Add(tab);
+ }
+
+ #endregion
+
+ public object CurrentObject {
+ get { return currentObject; }
+ set { SetCurrentObject (value, new object[] {value}); }
+ }
+
+ public void SetCurrentObject (object obj, object[] propertyProviders)
+ {
+ if (this.currentObject == obj)
+ return;
+ this.currentObject = obj;
+ this.propertyProviders = propertyProviders;
+ UpdateTabs ();
+ Populate();
+ }
+
+ public void CommitPendingChanges ()
+ {
+ tree.CommitChanges ();
+ }
+
+ void UpdateTabs ()
+ {
+ foreach (Gtk.Widget w in toolbar.Children) {
+ TabRadioToolButton but = w as TabRadioToolButton;
+ if (but != null)
+ but.Visible = currentObject != null && but.Tab.CanExtend (currentObject);
+ }
+ }
+
+ //TODO: add more intelligence for editing state etc. Maybe need to know which property has changed, then
+ //just update that
+ public void Refresh ()
+ {
+ QueueDraw ();
+ }
+
+ void Populate ()
+ {
+ PropertyDescriptorCollection properties;
+
+ tree.SaveStatus ();
+ tree.Clear ();
+ tree.PropertySort = propertySort;
+
+ if (currentObject == null) {
+ properties = new PropertyDescriptorCollection (new PropertyDescriptor[0] {});
+ tree.Populate (properties, currentObject);
+ }
+ else {
+ foreach (object prov in propertyProviders) {
+ properties = selectedTab.GetProperties (prov);
+ tree.Populate (properties, prov);
+ }
+ }
+ tree.RestoreStatus ();
+ }
+
+ void Update ()
+ {
+ PropertyDescriptorCollection properties;
+
+ if (currentObject == null) {
+ properties = new PropertyDescriptorCollection (new PropertyDescriptor[0] {});
+ tree.Update (properties, currentObject);
+ }
+ else {
+ foreach (object prov in propertyProviders) {
+ properties = selectedTab.GetProperties (prov);
+ tree.Update (properties, prov);
+ }
+ }
+ }
+
+ public bool ShowToolbar {
+ get { return toolbar.Visible; }
+ set { toolbar.Visible = toolbarSeparator.Visible = value; }
+ }
+
+ public ShadowType ShadowType {
+ get { return tree.ShadowType; }
+ set { tree.ShadowType = value; }
+ }
+
+ #region Hel Pane
+
+ public bool ShowHelp
+ {
+ get { return descFrame != null; }
+ set {
+ if (value == ShowHelp)
+ return;
+ if (value) {
+ AddHelpPane ();
+ helpSeparator.Show ();
+ } else {
+ vpaned.Remove (descFrame);
+ descFrame.Destroy ();
+ descFrame = null;
+ descTextView = null;
+ descTitleLabel = null;
+ helpSeparator.Hide ();
+ }
+ }
+ }
+
+ void AddHelpPane ()
+ {
+ VBox desc = new VBox (false, 0);
+
+ descTitleLabel = new Label ();
+ descTitleLabel.SetAlignment(0, 0);
+ descTitleLabel.SetPadding (5, 2);
+ descTitleLabel.UseMarkup = true;
+ desc.PackStart (descTitleLabel, false, false, 0);
+
+ ScrolledWindow textScroll = new ScrolledWindow ();
+ textScroll.HscrollbarPolicy = PolicyType.Never;
+ textScroll.VscrollbarPolicy = PolicyType.Automatic;
+
+ desc.PackEnd (textScroll, true, true, 0);
+
+ //TODO: Use label, but wrapping seems dodgy.
+ descTextView = new TextView ();
+ descTextView.WrapMode = WrapMode.Word;
+ descTextView.WidthRequest = 1;
+ descTextView.HeightRequest = 70;
+ descTextView.Editable = false;
+ descTextView.LeftMargin = 5;
+ descTextView.RightMargin = 5;
+
+ Pango.FontDescription font = Style.FontDescription.Copy ();
+ font.Size = (font.Size * 8) / 10;
+ descTextView.ModifyFont (font);
+
+ textScroll.Add (descTextView);
+
+ descFrame = desc;
+ vpaned.Pack2 (descFrame, false, true);
+ descFrame.ShowAll ();
+ UpdateHelp ();
+ }
+
+ public void SetHelp (string title, string description)
+ {
+ descTitle = title;
+ descText = description;
+ UpdateHelp ();
+ }
+
+ void UpdateHelp ()
+ {
+ if (!ShowHelp)
+ return;
+ descTextView.Buffer.Clear ();
+ if (descText != null)
+ descTextView.Buffer.InsertAtCursor (descText);
+ descTitleLabel.Markup = descTitle != null?
+ "<b>" + descTitle + "</b>" : string.Empty;
+ }
+
+ public void ClearHelp()
+ {
+ descTitle = descText = null;
+ UpdateHelp ();
+ }
+
+ public interface IToolbarProvider
+ {
+ void Insert (Widget w, int pos);
+ Widget[] Children { get; }
+ void ShowAll ();
+ bool Visible { get; set; }
+ }
+
+ class PropertyGridToolbar: HBox, IToolbarProvider
+ {
+ public PropertyGridToolbar ()
+ {
+ Spacing = 3;
+ }
+
+ public void Insert (Widget w, int pos)
+ {
+ PackStart (w, false, false, 0);
+ if (pos != -1) {
+ Box.BoxChild bc = (Box.BoxChild) this [w];
+ bc.Position = pos;
+ }
+ }
+ }
+
+ #endregion
+ }
+
+ class TabRadioToolButton: RadioButton
+ {
+ public TabRadioToolButton (RadioButton group): base (group)
+ {
+ DrawIndicator = false;
+ Relief = ReliefStyle.None;
+ NoShowAll = true;
+ }
+
+ public PropertyTab Tab;
+ }
+
+ public enum PropertySort
+ {
+ NoSort = 0,
+ Alphabetical,
+ Categorized,
+ CategorizedAlphabetical
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGridTree.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGridTree.cs
new file mode 100644
index 0000000000..bb38ce46dc
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyGridTree.cs
@@ -0,0 +1,711 @@
+//
+// PropertyGridTree.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// 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.
+//
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+
+using Gtk;
+using Gdk;
+using MonoDevelop.Core;
+using MonoDevelop.Components.PropertyGrid.PropertyEditors;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ internal class PropertyGridTree: Gtk.ScrolledWindow
+ {
+ Gtk.TreeStore store;
+ InternalTree tree;
+ TreeViewColumn editorColumn;
+ Hashtable propertyRows;
+ ArrayList collapseStatus = new ArrayList ();
+ EditorManager editorManager;
+ PropertyGrid parentGrid;
+
+ public event EventHandler Changed;
+
+ private PropertySort propertySort = PropertySort.Categorized;
+
+
+ public PropertyGridTree (EditorManager editorManager, PropertyGrid parentGrid)
+ {
+ this.editorManager = editorManager;
+ this.parentGrid = parentGrid;
+
+ propertyRows = new Hashtable ();
+
+ store = new TreeStore (typeof (string), typeof(object), typeof(bool), typeof(object));
+
+ tree = new InternalTree (this, store);
+
+ CellRendererText crt;
+
+ TreeViewColumn col;
+
+ col = new TreeViewColumn ();
+ col.Title = GettextCatalog.GetString ("Property");
+ crt = new CellRendererPropertyGroup (tree);
+ crt.Xpad = 0;
+ col.PackStart (crt, true);
+ col.SetCellDataFunc (crt, new TreeCellDataFunc (GroupData));
+ col.Resizable = true;
+ col.Expand = false;
+ col.Sizing = TreeViewColumnSizing.Fixed;
+ col.FixedWidth = 180;
+ tree.AppendColumn (col);
+
+ editorColumn = new TreeViewColumn ();
+ editorColumn.Title = GettextCatalog.GetString ("Value");
+
+ CellRendererProperty crp = new CellRendererProperty (tree);
+
+ editorColumn.PackStart (crp, true);
+ editorColumn.SetCellDataFunc (crp, new TreeCellDataFunc (PropertyData));
+ editorColumn.Sizing = TreeViewColumnSizing.Fixed;
+ editorColumn.Resizable = false;
+ editorColumn.Expand = true;
+ tree.AppendColumn (editorColumn);
+
+ tree.HeadersVisible = false;
+ this.ShadowType = Gtk.ShadowType.None;
+
+ this.HscrollbarPolicy = Gtk.PolicyType.Never;
+
+ Add (tree);
+
+ ShowAll ();
+
+ tree.Selection.Changed += OnSelectionChanged;
+ }
+
+ public void CommitChanges ()
+ {
+ tree.Selection.UnselectAll ();
+ }
+
+ public void SaveStatus ()
+ {
+ collapseStatus.Clear ();
+
+ TreeIter iter;
+ if (!tree.Model.GetIterFirst (out iter))
+ return;
+
+ do {
+ if (!tree.GetRowExpanded (tree.Model.GetPath (iter))) {
+ collapseStatus.Add (tree.Model.GetValue (iter, 0));
+ }
+ } while (tree.Model.IterNext (ref iter));
+ }
+
+ public void RestoreStatus ()
+ {
+ TreeIter iter;
+ if (!tree.Model.GetIterFirst (out iter))
+ return;
+
+ // If the tree only has one group, show it always expanded
+ TreeIter iter2 = iter;
+ if (!tree.Model.IterNext (ref iter2)) {
+ tree.ExpandRow (tree.Model.GetPath (iter), true);
+ return;
+ }
+
+ do {
+ object grp = tree.Model.GetValue (iter, 0);
+ if (!collapseStatus.Contains (grp))
+ tree.ExpandRow (tree.Model.GetPath (iter), false);
+ } while (tree.Model.IterNext (ref iter));
+ }
+
+ public virtual void Clear ()
+ {
+ store.Clear ();
+ propertyRows.Clear ();
+ }
+
+ public virtual void Update ()
+ {
+ // Just repaint the cells
+ QueueDraw ();
+ }
+
+ public PropertySort PropertySort {
+ get { return propertySort; }
+ set { propertySort = value; }
+ }
+
+ internal void Populate (PropertyDescriptorCollection properties, object instance)
+ {
+ bool categorised = PropertySort == PropertySort.Categorized;
+
+ //transcribe browsable properties
+ ArrayList sorted = new ArrayList();
+
+ foreach (PropertyDescriptor descriptor in properties)
+ if (descriptor.IsBrowsable)
+ sorted.Add (descriptor);
+
+ if (sorted.Count == 0)
+ return;
+
+ InstanceData idata = new InstanceData (instance);
+
+ if (!categorised) {
+ if (PropertySort != PropertySort.NoSort)
+ sorted.Sort(new SortByName ());
+ foreach (PropertyDescriptor pd in sorted)
+ AppendProperty (TreeIter.Zero, pd, idata);
+ }
+ else {
+ sorted.Sort (new SortByCat ());
+ string oldCat = null;
+ TreeIter catIter = TreeIter.Zero;
+
+ foreach (PropertyDescriptor pd in sorted) {
+ if (pd.Category != oldCat) {
+ catIter = store.AppendValues (pd.Category, null, true, idata);
+ oldCat = pd.Category;
+ }
+ AppendProperty (catIter, pd, idata);
+ }
+ }
+ }
+
+ internal void Update (PropertyDescriptorCollection properties, object instance)
+ {
+ foreach (PropertyDescriptor pd in properties) {
+ TreeIter it;
+ if (!store.GetIterFirst (out it))
+ continue;
+
+ UpdateProperty (pd, it, instance);
+ }
+ }
+
+ bool UpdateProperty (PropertyDescriptor pd, TreeIter it, object instance)
+ {
+ do {
+ PropertyDescriptor prop = (PropertyDescriptor) store.GetValue (it, 1);
+ InstanceData idata = (InstanceData) store.GetValue (it, 3);
+ if (prop != null && idata != null && prop.Name == pd.Name && idata.Instance == instance) {
+ // Don't update the current editing node, since it may cause tree update problems
+ if (!tree.Editing || !store.GetPath (tree.EditingIter).Equals (store.GetPath (it)))
+ store.SetValue (it, 1, pd);
+ return true;
+ }
+ TreeIter ci;
+ if (store.IterChildren (out ci, it)) {
+ if (UpdateProperty (pd, ci, instance))
+ return true;
+ }
+ }
+ while (store.IterNext (ref it));
+ return false;
+ }
+
+ protected void AppendProperty (PropertyDescriptor prop, object instance)
+ {
+ AppendProperty (TreeIter.Zero, prop, new InstanceData (instance));
+ }
+
+ protected void AppendProperty (TreeIter piter, PropertyDescriptor prop, object instance)
+ {
+ AppendProperty (piter, prop, new InstanceData (instance));
+ }
+
+ void AppendProperty (TreeIter piter, PropertyDescriptor prop, InstanceData idata)
+ {
+ TreeIter iter;
+
+ if (piter.Equals (TreeIter.Zero))
+ iter = store.AppendValues (prop.DisplayName, prop, false, idata);
+ else
+ iter = store.AppendValues (piter, prop.DisplayName, prop, false, idata);
+ propertyRows [prop] = store.GetStringFromIter (iter);
+
+ TypeConverter tc = prop.Converter;
+ if (typeof (ExpandableObjectConverter).IsAssignableFrom (tc.GetType ())) {
+ object cob = prop.GetValue (idata.Instance);
+ foreach (PropertyDescriptor cprop in TypeDescriptor.GetProperties (cob))
+ AppendProperty (iter, cprop, cob);
+ }
+ }
+
+ protected virtual void OnObjectChanged ()
+ {
+ // Delay the notification of the change. There may be problems if the
+ // handler of this event starts its own gui loop.
+ GLib.Timeout.Add (0, delegate {
+ if (Changed != null)
+ Changed (this, EventArgs.Empty);
+ return false;
+ });
+ }
+
+ void OnSelectionChanged (object s, EventArgs a)
+ {
+ TreePath[] rows = tree.Selection.GetSelectedRows ();
+ if (!tree.dragging && rows != null && rows.Length > 0) {
+ tree.SetCursor (rows[0], editorColumn, true);
+ }
+ TreeIter iter;
+ if (tree.Selection.GetSelected (out iter)) {
+ PropertyDescriptor prop = (PropertyDescriptor) store.GetValue (iter, 1);
+ if (prop != null)
+ parentGrid.SetHelp (prop.DisplayName, prop.Description);
+ else
+ parentGrid.SetHelp (string.Empty, string.Empty);
+ } else {
+ parentGrid.SetHelp (string.Empty, string.Empty);
+ }
+ }
+
+ internal void NotifyChanged ()
+ {
+ OnObjectChanged ();
+ }
+
+ void PropertyData (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
+ {
+ CellRendererProperty rc = (CellRendererProperty) cell;
+ bool group = (bool) model.GetValue (iter, 2);
+ if (group) {
+ rc.SetData (null, null, null);
+ } else {
+ PropertyDescriptor prop = (PropertyDescriptor) model.GetValue (iter, 1);
+ PropertyEditorCell propCell = editorManager.GetEditor (prop);
+ InstanceData idata = (InstanceData) model.GetValue (iter, 3);
+ propCell.Initialize (tree, editorManager, prop, idata.Instance);
+ rc.SetData (idata.Instance, prop, propCell);
+ }
+ }
+
+ void GroupData (Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
+ {
+ CellRendererPropertyGroup rc = (CellRendererPropertyGroup) cell;
+ rc.IsGroup = (bool) model.GetValue (iter, 2);
+ rc.Text = (string) model.GetValue (iter, 0);
+
+ PropertyDescriptor prop = (PropertyDescriptor) model.GetValue (iter, 1);
+ if (prop != null)
+ rc.SensitiveProperty = !prop.IsReadOnly;
+ else
+ rc.SensitiveProperty = true;
+ }
+
+ private class SortByCat : IComparer
+ {
+ public int Compare (object x, object y)
+ {
+ int catcomp = ((PropertyDescriptor)x).Category.CompareTo (((PropertyDescriptor)y).Category);
+
+ if (catcomp == 0)
+ return ((PropertyDescriptor)x).DisplayName.CompareTo (((PropertyDescriptor)y).DisplayName);
+ else
+ return catcomp;
+ }
+ }
+
+ private class SortByName : IComparer
+ {
+ public int Compare(object x, object y)
+ {
+ return ((PropertyDescriptor)x).DisplayName.CompareTo (((PropertyDescriptor)y).DisplayName);
+ }
+ }
+ }
+
+ class InternalTree: TreeView
+ {
+ internal ArrayList Groups = new ArrayList ();
+ Pango.Layout layout;
+ bool editing;
+ TreeIter editingIter;
+ PropertyGridTree tree;
+ internal bool dragging;
+ int dragPos;
+ Gdk.Cursor resizeCursor = new Gdk.Cursor (CursorType.SbHDoubleArrow);
+
+ public InternalTree (PropertyGridTree tree, TreeModel model): base (model)
+ {
+ this.tree = tree;
+ layout = new Pango.Layout (this.PangoContext);
+ layout.Wrap = Pango.WrapMode.Char;
+ }
+
+ public bool Editing {
+ get { return editing; }
+ set { editing = value; }
+ }
+
+ public TreeIter EditingIter {
+ get { return editingIter; }
+ set { editingIter = value; }
+ }
+
+ public PropertyGridTree PropertyTree {
+ get { return tree; }
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose e)
+ {
+ Groups.Clear ();
+
+ bool res = base.OnExposeEvent (e);
+
+ foreach (TreeGroup grp in Groups) {
+ layout.SetMarkup ("<b>" + grp.Group + "</b>");
+ e.Window.DrawLayout (this.Style.TextGC (grp.State), grp.X, grp.Y, layout);
+ }
+
+ return res;
+ }
+
+ protected override void OnDestroyed ()
+ {
+ base.OnDestroyed ();
+ if (resizeCursor != null) {
+ resizeCursor.Dispose ();
+ resizeCursor = null;
+ }
+ }
+
+ protected override bool OnMotionNotifyEvent (EventMotion evnt)
+ {
+ if (dragging) {
+ int nw = (int)(evnt.X) + dragPos;
+ if (nw <= 40) nw = 40;
+ GLib.Idle.Add (delegate {
+ Columns[0].FixedWidth = nw;
+ return false;
+ });
+ } else {
+ int w = Columns[0].Width;
+ if (Math.Abs (w - evnt.X) < 5)
+ this.GdkWindow.Cursor = resizeCursor;
+ else
+ this.GdkWindow.Cursor = null;
+ }
+ return base.OnMotionNotifyEvent (evnt);
+ }
+
+ protected override bool OnButtonPressEvent (EventButton evnt)
+ {
+ int w = Columns[0].Width;
+ if (Math.Abs (w - evnt.X) < 5) {
+ TreePath[] rows = Selection.GetSelectedRows ();
+ if (rows != null && rows.Length > 0)
+ SetCursor (rows[0], Columns[0], false);
+ dragging = true;
+ dragPos = w - (int) evnt.X;
+ this.GdkWindow.Cursor = resizeCursor;
+ }
+ return base.OnButtonPressEvent (evnt);
+ }
+
+ protected override bool OnButtonReleaseEvent (EventButton evnt)
+ {
+ if (dragging) {
+ this.GdkWindow.Cursor = null;
+ dragging = false;
+ }
+ return base.OnButtonReleaseEvent (evnt);
+ }
+
+ public virtual void Update ()
+ {
+ }
+ }
+
+ class TreeGroup
+ {
+ public string Group;
+ public int X;
+ public int Y;
+ public StateType State;
+ }
+
+ class CellRendererProperty: CellRenderer
+ {
+ TreeView tree;
+ PropertyDescriptor property;
+ object instance;
+ int rowHeight;
+ PropertyEditorCell editorCell;
+ bool sensitive = true;
+ bool visible = true;
+
+ public CellRendererProperty (TreeView tree)
+ {
+ this.tree = tree;
+ Xalign = 0;
+ Xpad = 3;
+
+ Mode |= Gtk.CellRendererMode.Editable;
+ Entry dummyEntry = new Gtk.Entry ();
+ dummyEntry.HasFrame = false;
+ rowHeight = dummyEntry.SizeRequest ().Height;
+ }
+
+ public void SetData (object instance, PropertyDescriptor property, PropertyEditorCell editor)
+ {
+ this.instance = instance;
+ this.property = property;
+ if (property == null) {
+ this.CellBackgroundGdk = tree.Style.MidColors [(int) Gtk.StateType.Normal];
+ sensitive = true;
+ }
+ else {
+ this.CellBackground = null;
+ sensitive = !property.IsReadOnly || (editor != null && editor.EditsReadOnlyObject);
+ }
+
+ editorCell = editor;
+ }
+
+ public override void GetSize (Widget widget, ref Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
+ {
+ if (editorCell != null)
+ editorCell.GetSize ((int)(cell_area.Width - this.Xpad * 2), out width, out height);
+ else {
+ width = height = 0;
+ }
+
+ width += (int) this.Xpad * 2;
+ height += (int) this.Ypad * 2;
+
+ x_offset = 0;
+ y_offset = 0;
+
+ if (height < rowHeight)
+ height = rowHeight;
+ }
+
+ protected override void Render (Drawable window, Widget widget, Rectangle background_area, Rectangle cell_area, Rectangle expose_area, CellRendererState flags)
+ {
+ if (instance == null || !visible)
+ return;
+ int width = 0, height = 0;
+ int iwidth = cell_area.Width - (int) this.Xpad * 2;
+
+ if (editorCell != null)
+ editorCell.GetSize ((int)(cell_area.Width - this.Xpad * 2), out width, out height);
+
+ Rectangle bounds = new Rectangle ();
+ bounds.Width = width > iwidth ? iwidth : width;
+ bounds.Height = height;
+ bounds.X = (int) (cell_area.X + this.Xpad);
+ bounds.Y = cell_area.Y + (cell_area.Height - height) / 2;
+
+ StateType state = GetState (flags);
+
+ if (editorCell != null)
+ editorCell.Render (window, bounds, state);
+ }
+
+ public override CellEditable StartEditing (Gdk.Event ev, Widget widget, string path, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, CellRendererState flags)
+ {
+ if (property == null || editorCell == null || !sensitive)
+ return null;
+
+ StateType state = GetState (flags);
+ EditSession session = editorCell.StartEditing (cell_area, state);
+ if (session == null)
+ return null;
+ Gtk.Widget propEditor = (Gtk.Widget) session.Editor;
+ propEditor.Show ();
+ HackEntry e = new HackEntry (session, propEditor);
+ e.Show ();
+ session.Changed += delegate {
+ ((InternalTree)widget).PropertyTree.NotifyChanged ();
+ };
+ TreeIter it;
+ ((InternalTree)widget).Model.GetIterFromString (out it, path);
+ ((InternalTree)widget).EditingIter = it;
+ return e;
+ }
+
+ StateType GetState (CellRendererState flags)
+ {
+ if (!sensitive)
+ return StateType.Insensitive;
+ else if ((flags & CellRendererState.Selected) != 0)
+ return StateType.Selected;
+ else
+ return StateType.Normal;
+ }
+ }
+
+ class CellRendererPropertyGroup: CellRendererText
+ {
+ TreeView tree;
+ Pango.Layout layout;
+ bool isGroup;
+ bool sensitive = true;
+
+ public bool IsGroup {
+ get { return isGroup; }
+ set {
+ isGroup = value;
+ if (value)
+ this.CellBackgroundGdk = tree.Style.MidColors [(int) Gtk.StateType.Normal];
+ else
+ this.CellBackground = null;
+ }
+ }
+
+ public bool SensitiveProperty {
+ get { return sensitive; }
+ set { sensitive = value; }
+ }
+
+ public CellRendererPropertyGroup (TreeView tree)
+ {
+ this.tree = tree;
+ layout = new Pango.Layout (tree.PangoContext);
+ layout.Wrap = Pango.WrapMode.Char;
+ }
+
+ protected void GetCellSize (Widget widget, int availableWidth, out int width, out int height)
+ {
+ layout.SetMarkup (Text);
+ layout.Width = -1;
+ layout.GetPixelSize (out width, out height);
+ }
+
+ public override void GetSize (Widget widget, ref Rectangle cell_area, out int x_offset, out int y_offset, out int width, out int height)
+ {
+ GetCellSize (widget, (int)(cell_area.Width - this.Xpad * 2), out width, out height);
+ width += (int) this.Xpad * 2;
+ height += (int) this.Ypad * 2;
+
+ x_offset = y_offset = 0;
+
+ if (IsGroup)
+ width = 0;
+ }
+
+ protected override void Render (Drawable window, Widget widget, Rectangle background_area, Rectangle cell_area, Rectangle expose_area, CellRendererState flags)
+ {
+ int width, height;
+ GetCellSize (widget, (int)(cell_area.Width - this.Xpad * 2), out width, out height);
+
+ int x = (int) (cell_area.X + this.Xpad);
+ int y = cell_area.Y + (cell_area.Height - height) / 2;
+
+ StateType state;
+ if (!sensitive)
+ state = StateType.Insensitive;
+ else if ((flags & CellRendererState.Selected) != 0)
+ state = StateType.Selected;
+ else
+ state = StateType.Normal;
+
+ if (IsGroup) {
+ TreeGroup grp = new TreeGroup ();
+ grp.X = x;
+ grp.Y = y;
+ grp.Group = Text;
+ grp.State = state;
+ InternalTree tree = (InternalTree) widget;
+ tree.Groups.Add (grp);
+ } else {
+ window.DrawLayout (widget.Style.TextGC (state), x, y, layout);
+ int bx = background_area.X + background_area.Width - 1;
+ Gdk.GC gc = new Gdk.GC (window);
+ gc.RgbFgColor = tree.Style.MidColors [(int) Gtk.StateType.Normal];
+ window.DrawLine (gc, bx, background_area.Y, bx, background_area.Y + background_area.Height);
+ }
+ }
+ }
+
+ class HackEntry: Entry
+ {
+ EventBox box;
+ EditSession session;
+
+ public HackEntry (EditSession session, Gtk.Widget child)
+ {
+ this.session = session;
+ box = new EventBox ();
+ box.ButtonPressEvent += new ButtonPressEventHandler (OnClickBox);
+ box.ModifyBg (StateType.Normal, Style.White);
+ box.Add (child);
+ }
+
+ [GLib.ConnectBefore]
+ void OnClickBox (object s, ButtonPressEventArgs args)
+ {
+ // Avoid forwarding the button press event to the
+ // tree, since it would hide the cell editor.
+ args.RetVal = true;
+ }
+
+ protected override void OnParentSet (Gtk.Widget parent)
+ {
+ base.OnParentSet (parent);
+
+ if (Parent != null) {
+ if (this.ParentWindow != null)
+ box.ParentWindow = this.ParentWindow;
+ box.Parent = Parent;
+ box.Show ();
+ ((InternalTree)Parent).Editing = true;
+ }
+ else {
+ session.Dispose ();
+ ((InternalTree)parent).Editing = false;
+ if (box.Parent != null && box.Parent.IsRealized)
+ box.Unparent ();
+ }
+ }
+
+ protected override void OnShown ()
+ {
+ // Do nothing.
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle allocation)
+ {
+ base.OnSizeAllocated (allocation);
+ box.SizeRequest ();
+ box.Allocation = allocation;
+ }
+ }
+
+ class InstanceData
+ {
+ public InstanceData (object instance)
+ {
+ Instance = instance;
+ }
+
+ public object Instance;
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventArgs.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventArgs.cs
new file mode 100644
index 0000000000..789ac9fc79
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventArgs.cs
@@ -0,0 +1,65 @@
+/*
+ * PropertyValueChangedEventArgs.cs - The arguments for the PropertyGrid's PropertyValueChanged event
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+using System.ComponentModel;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ public class PropertyValueChangedEventArgs
+ {
+ private PropertyDescriptor changedItem;
+ private object oldValue;
+ private object newValue;
+
+ public PropertyValueChangedEventArgs (PropertyDescriptor changedItem, object oldValue, object newValue)
+ {
+ this.changedItem = changedItem;
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ public object OldValue {
+ get { return oldValue; }
+ }
+
+ public object NewValue
+ {
+ get { return newValue; }
+ }
+
+ public PropertyDescriptor ChangedItem {
+ get { return changedItem; }
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventHandler.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventHandler.cs
new file mode 100644
index 0000000000..d681b44fb1
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/PropertyValueChangedEventHandler.cs
@@ -0,0 +1,37 @@
+/*
+ * PropertyValueChangedEventHandler.cs - The delegate for the PropertyGrid's PropertyValueChanged event
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+ public delegate void PropertyValueChangedEventHandler (object sender, PropertyValueChangedEventArgs e);
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/SurrogateUITypeEditorAttribute.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/SurrogateUITypeEditorAttribute.cs
new file mode 100644
index 0000000000..a79751fdfd
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.PropertyGrid/SurrogateUITypeEditorAttribute.cs
@@ -0,0 +1,61 @@
+/*
+ * SurrogateUITypeEditorAttribute.cs - Marks a GTK# Visual Editor as a substitute
+ * for a particular System.Drawing.Design.UITypeEditor-derived SWF editor.
+ *
+ * Part of PropertyGrid - A Gtk# widget that displays and allows
+ * editing of all of an object's public properties
+ *
+ * Authors:
+ * Michael Hutchinson <m.j.hutchinson@gmail.com>
+ *
+ * Copyright (C) 2005 Michael Hutchinson
+ *
+ * This sourcecode is licenced under The MIT License:
+ *
+ * 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.
+ */
+
+using System;
+
+namespace MonoDevelop.Components.PropertyGrid
+{
+
+ [AttributeUsage (AttributeTargets.Class, AllowMultiple = true)]
+ public class SurrogateUITypeEditorAttribute : Attribute
+ {
+ public Type Type;
+ public SurrogateUITypeEditorAttribute (Type myType)
+ {
+ this.Type = myType;
+ }
+ }
+
+ /* TODO: Surrogates for...
+ *
+ * System.Drawing.Design.FontEditor
+ * System.Drawing.Design.ImageEditor
+ * System.Web.UI.Design.DataBindingCollectionEditor
+ * System.Web.UI.Design.UrlEditor
+ * System.Web.UI.Design.WebControls.DataGridColumnCollectionEditor
+ * System.Web.UI.Design.WebControls.RegexTypeEditor
+ * System.Web.UI.Design.XmlFileEditor
+ * System.Web.UI.Design.TreeNodeCollectionEditor *STUPID: isn't based on CollectionEditor*
+ */
+}