Index: src/DeltaShell/DeltaShell.Gui/DeltaShell.Gui.csproj =================================================================== diff -u -r2ff69dfc67c77d80c1ed2f4f1f9bc0172e28e518 -rc4fb042f3ea7c21852fba8fdc21bdeac96da6419 --- src/DeltaShell/DeltaShell.Gui/DeltaShell.Gui.csproj (.../DeltaShell.Gui.csproj) (revision 2ff69dfc67c77d80c1ed2f4f1f9bc0172e28e518) +++ src/DeltaShell/DeltaShell.Gui/DeltaShell.Gui.csproj (.../DeltaShell.Gui.csproj) (revision c4fb042f3ea7c21852fba8fdc21bdeac96da6419) @@ -42,7 +42,7 @@ true bin\Debug\ - 4 + 4 x86 false MinimumRecommendedRules.ruleset @@ -52,7 +52,7 @@ bin\Release\ - 4 + 4 x86 MinimumRecommendedRules.ruleset false @@ -61,7 +61,7 @@ bin\application\ - 4 + 4 x86 false MinimumRecommendedRules.ruleset @@ -143,7 +143,7 @@ ProgressDialog.cs - + Component Index: src/DeltaShell/DeltaShell.Gui/Forms/MainWindow/MainWindow.xaml.cs =================================================================== diff -u -r50d4f9e34ad8050478c2d63675b1f17a376fb43d -rc4fb042f3ea7c21852fba8fdc21bdeac96da6419 --- src/DeltaShell/DeltaShell.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision 50d4f9e34ad8050478c2d63675b1f17a376fb43d) +++ src/DeltaShell/DeltaShell.Gui/Forms/MainWindow/MainWindow.xaml.cs (.../MainWindow.xaml.cs) (revision c4fb042f3ea7c21852fba8fdc21bdeac96da6419) @@ -62,7 +62,7 @@ private bool resetDefaultLayout; private MessageWindow.MessageWindow messageWindow; - private PropertyGridView propertyGrid; + private PropertyGridView.PropertyGridView propertyGrid; private WindowInteropHelper windowInteropHelper; private IEnumerable ribbonCommandHandlers; @@ -267,7 +267,7 @@ { if ((propertyGrid == null) || (propertyGrid.IsDisposed)) { - propertyGrid = new PropertyGridView(Gui); + propertyGrid = new PropertyGridView.PropertyGridView(Gui); } propertyGrid.Text = Properties.Resources.Properties; Index: src/DeltaShell/DeltaShell.Gui/Forms/PropertyGridView/PropertyGridView.cs =================================================================== diff -u --- src/DeltaShell/DeltaShell.Gui/Forms/PropertyGridView/PropertyGridView.cs (revision 0) +++ src/DeltaShell/DeltaShell.Gui/Forms/PropertyGridView/PropertyGridView.cs (revision c4fb042f3ea7c21852fba8fdc21bdeac96da6419) @@ -0,0 +1,321 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Security.Permissions; +using System.Windows.Forms; +using DelftTools.Controls; +using DelftTools.Shell.Core; +using DelftTools.Shell.Gui; +using DelftTools.Shell.Gui.Forms; +using DelftTools.Utils.PropertyBag.Dynamic; +using DeltaShell.Gui.Properties; +using log4net; + +namespace DeltaShell.Gui.Forms.PropertyGridView +{ + public class PropertyGridView : PropertyGrid, IPropertyGrid, IObserver + { + /// + /// This delegate enabled asynchronous calls to methods without arguments. + /// + private delegate void ArgumentlessDelegate(); + + private static readonly ILog Log = LogManager.GetLogger(typeof(PropertyGridView)); + + /// + /// todo: This is still an unwanted dependency. PropertyGrid uses gui to subscribe to the SelectionChanged + /// delegate and in responce queries the gui.Selection + /// nicer? : custom public delegate in IPropertyGrid with selection as parameter + /// + private readonly IGui gui; + + private IObservable observable; + + public PropertyGridView(IGui gui) + { + HideTabsButton(); + + this.gui = gui; + PropertySort = PropertySort.Categorized; + + gui.SelectionChanged += GuiSelectionChanged; + } + + public void UpdateObserver() + { + if (InvokeRequired) + { + ArgumentlessDelegate d = UpdateObserver; + Invoke(d, new object[0]); + } + else + { + Refresh(); + } + } + + public object GetObjectProperties(object sourceData) + { + if (sourceData == null) + { + return null; + } + + // Obtain all property information + var propertyInfos = gui.Plugins.SelectMany(p => p.GetPropertyInfos()).ToList(); + + // 1. Match property information based on ObjectType and on AdditionalDataCheck + propertyInfos = propertyInfos.Where(pi => pi.ObjectType.IsInstanceOfType(sourceData) && (pi.AdditionalDataCheck == null || pi.AdditionalDataCheck(sourceData))).ToList(); + + // 2. Match property information based on object type inheritance + propertyInfos = FilterPropertyInfoByTypeInheritance(propertyInfos, pi => pi.ObjectType); + + // 3. Match property information based on property type inheritance + propertyInfos = FilterPropertyInfoByTypeInheritance(propertyInfos, pi => pi.PropertyType); + + if (propertyInfos.Count == 0) + { + // No (or multiple) object properties found: return 'null' so that no object properties are shown in the property grid + return null; + } + + if (propertyInfos.Count > 1) + { + // 4. We assume that the propertyInfos with AdditionalDataCheck are the most specific + propertyInfos = propertyInfos.Where(pi => pi.AdditionalDataCheck != null).ToList(); + } + + if (propertyInfos.Count == 1) + { + return CreateObjectProperties(propertyInfos.ElementAt(0), sourceData); + } + + Log.Debug(Resources.PropertyGrid_GetObjectProperties_Multiple_object_property_instances_found_for_the_same_data_object__no_object_properties_are_displayed_in_the_property_grid); + return null; + } + + /// + /// Raises the event. + /// + /// A that contains the event data. + protected override void OnPropertySortChanged(EventArgs e) + { + // Needed for maintaining property order + if (PropertySort == PropertySort.CategorizedAlphabetical) + { + PropertySort = PropertySort.Categorized; + } + + base.OnPropertySortChanged(e); + } + + protected override void Dispose(bool disposing) + { + if (gui != null) + { + gui.SelectionChanged -= GuiSelectionChanged; + } + + if (observable != null) + { + observable.Detach(this); + } + + base.Dispose(disposing); + } + + private void HideTabsButton() + { + // Removing "property tabs" button and separator before it + var strip = Controls.OfType().ToList()[0]; + strip.Items[3].Visible = false; + strip.Items[4].Visible = false; + } + + private void GuiSelectionChanged(object sender, EventArgs e) + { + if (observable != null) + { + observable.Detach(this); + } + + var selection = gui.Selection; + if (selection == null) + { + SelectedObject = null; + return; + } + + observable = selection as IObservable; + if (observable != null) + { + observable.Attach(this); + } + + SelectedObject = GetObjectProperties(selection); + } + + private List FilterPropertyInfoByTypeInheritance(List propertyInfo, Func getTypeAction) + { + var propertyInfoCount = propertyInfo.Count; + var propertyInfoWithUnInheritedType = propertyInfo.ToList(); + + for (var i = 0; i < propertyInfoCount; i++) + { + var firstType = getTypeAction(propertyInfo.ElementAt(i)); + + for (var j = 0; j < propertyInfoCount; j++) + { + if (i == j) + { + continue; + } + + var secondType = getTypeAction(propertyInfo.ElementAt(j)); + + if (firstType != secondType && firstType.IsAssignableFrom(secondType)) + { + propertyInfoWithUnInheritedType.Remove(propertyInfo.ElementAt(i)); + + break; + } + } + } + + return propertyInfoWithUnInheritedType.Any() + ? propertyInfoWithUnInheritedType.ToList() // One or more specific property information objects found: return the filtered list + : propertyInfo; // No specific property information found: return the original list + } + + private object CreateObjectProperties(PropertyInfo propertyInfo, object sourceData) + { + try + { + // Try to create object properties for the source data + var objectProperties = propertyInfo.CreateObjectProperties(sourceData); + + // Return a dynamic property bag containing the created object properties + return new DynamicPropertyBag(objectProperties); + } + catch (Exception) + { + Log.Debug(Resources.PropertyGrid_CreateObjectProperties_Could_not_create_object_properties_for_the_data); + + return null; + } + } + + #region IPropertyGrid Members + + public object Data + { + get + { + return SelectedObject; + } + set + { + SelectedObject = value; + } + } + + public Image Image + { + get + { + return Resources.PropertiesHS; + } + set {} + } + + public void EnsureVisible(object item) {} + + public ViewInfo ViewInfo { get; set; } + + #endregion + + #region Enable tab key navigation on property grid + + /// + /// Do special processing for Tab key. + /// http://www.codeproject.com/csharp/wdzPropertyGridUtils.asp + /// + /// + /// + /// + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if ((keyData == Keys.Tab) || (keyData == (Keys.Tab | Keys.Shift))) + { + var selectedItem = SelectedGridItem; + var root = selectedItem; + if (selectedItem == null) + { + return false; + } + while (root.Parent != null) + { + root = root.Parent; + } + // Find all expanded items and put them in a list. + var items = new ArrayList(); + AddExpandedItems(root, items); + + // Find selectedItem. + int foundIndex = items.IndexOf(selectedItem); + if ((keyData & Keys.Shift) == Keys.Shift) + { + foundIndex--; + if (foundIndex < 0) + { + foundIndex = items.Count - 1; + } + SelectedGridItem = (GridItem) items[foundIndex]; + if (SelectedGridItem.GridItems.Count > 0) + { + SelectedGridItem.Expanded = false; + } + } + else + { + foundIndex++; + if (items.Count > 0) + { + if (foundIndex >= items.Count) + { + foundIndex = 0; + } + SelectedGridItem = (GridItem) items[foundIndex]; + } + if (SelectedGridItem.GridItems.Count > 0) + { + SelectedGridItem.Expanded = true; + } + } + + return true; + } + return base.ProcessCmdKey(ref msg, keyData); + } + + private static void AddExpandedItems(GridItem parent, IList items) + { + if (parent.PropertyDescriptor != null) + { + items.Add(parent); + } + if (parent.Expanded) + { + foreach (GridItem child in parent.GridItems) + { + AddExpandedItems(child, items); + } + } + } + + #endregion + } +} \ No newline at end of file Fisheye: Tag c4fb042f3ea7c21852fba8fdc21bdeac96da6419 refers to a dead (removed) revision in file `src/DeltaShell/DeltaShell.Gui/PropertyGridView.cs'. Fisheye: No comparison available. Pass `N' to diff? Index: test/DeltaShell/DeltaShell.Tests/Gui/Forms/PropertyGrid/PropertyGridTest.cs =================================================================== diff -u -r185b3a30353d2daf39ff8cf4d838cafdb2984732 -rc4fb042f3ea7c21852fba8fdc21bdeac96da6419 --- test/DeltaShell/DeltaShell.Tests/Gui/Forms/PropertyGrid/PropertyGridTest.cs (.../PropertyGridTest.cs) (revision 185b3a30353d2daf39ff8cf4d838cafdb2984732) +++ test/DeltaShell/DeltaShell.Tests/Gui/Forms/PropertyGrid/PropertyGridTest.cs (.../PropertyGridTest.cs) (revision c4fb042f3ea7c21852fba8fdc21bdeac96da6419) @@ -4,6 +4,7 @@ using DelftTools.TestUtils; using DelftTools.Utils.PropertyBag.Dynamic; using DeltaShell.Gui; +using DeltaShell.Gui.Forms.PropertyGridView; using NUnit.Framework; using Rhino.Mocks;