--- /dev/null
+/* $Id$ $Revision$ */\r
+/* vim:set shiftwidth=4 ts=8: */\r
+\r
+/**********************************************************\r
+* This software is part of the graphviz package *\r
+* http://www.graphviz.org/ *\r
+* *\r
+* Copyright (c) 1994-2008 AT&T Corp. *\r
+* and is licensed under the *\r
+* Common Public License, Version 1.0 *\r
+* by AT&T Corp. *\r
+* *\r
+* Information and Software Systems Research *\r
+* AT&T Research, Florham Park NJ *\r
+**********************************************************/\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.ComponentModel;\r
+using System.IO;\r
+using System.Text;\r
+using System.Windows.Forms;\r
+using System.Windows.Forms.Design;\r
+using System.Xml;\r
+using System.Xml.XPath;\r
+\r
+namespace Graphviz\r
+{\r
+ public partial class AttributeInspectorForm : Form\r
+ {\r
+ public static Form Instance\r
+ {\r
+ get\r
+ {\r
+ return _instance;\r
+ }\r
+ }\r
+ \r
+ public AttributeInspectorForm()\r
+ {\r
+ InitializeComponent();\r
+ \r
+ /* remove existing tabs and add in our attribute property tabs */\r
+ List<Type> tabsToRemove = new List<Type>();\r
+ foreach (PropertyTab tabToRemove in attributePropertyGrid.PropertyTabs)\r
+ tabsToRemove.Add(tabToRemove.GetType());\r
+ foreach (Type tabToRemove in tabsToRemove)\r
+ attributePropertyGrid.PropertyTabs.RemoveTabType(tabToRemove);\r
+ attributePropertyGrid.PropertyTabs.AddTabType(typeof(GraphPropertyTab), PropertyTabScope.Static);\r
+ attributePropertyGrid.PropertyTabs.AddTabType(typeof(NodePropertyTab), PropertyTabScope.Static);\r
+ attributePropertyGrid.PropertyTabs.AddTabType(typeof(EdgePropertyTab), PropertyTabScope.Static);\r
+ \r
+ /* inspect the graph when the handle has been created */\r
+ /* NOTE: if we set the SelectedObject BEFORE the handle has been created, this damages the property tabs, a Microsoft bug */\r
+ if (attributePropertyGrid.IsHandleCreated)\r
+ InspectMainForm();\r
+ else\r
+ attributePropertyGrid.HandleCreated += delegate(object sender, EventArgs e)\r
+ {\r
+ InspectMainForm();\r
+ };\r
+ \r
+ /* inspect the graph when the main form changes */\r
+ FormController.Instance.MainFormChanged += delegate(object sender, EventArgs e)\r
+ {\r
+ InspectMainForm();\r
+ };\r
+ }\r
+\r
+ protected override void OnFormClosing(FormClosingEventArgs e)\r
+ {\r
+ /* instead of closing, we hide ourselves */\r
+ Hide();\r
+ e.Cancel = true;\r
+ }\r
+ \r
+ private class GraphPropertyTab : ExternalPropertyTab\r
+ {\r
+ public GraphPropertyTab() : base("Graph Attributes", Properties.Resources.GraphAttributes, _graphProperties)\r
+ {\r
+ }\r
+ }\r
+\r
+ private class NodePropertyTab : ExternalPropertyTab\r
+ {\r
+ public NodePropertyTab() : base("Node Attributes", Properties.Resources.NodeAttributes, _nodeProperties)\r
+ {\r
+ }\r
+ }\r
+\r
+ private class EdgePropertyTab : ExternalPropertyTab\r
+ {\r
+ public EdgePropertyTab() : base("Edge Attributes", Properties.Resources.EdgeAttributes, _edgeProperties)\r
+ {\r
+ }\r
+ }\r
+\r
+ private void InspectMainForm()\r
+ {\r
+ /* if the main form has a graph, show its properties */\r
+ GraphForm graphForm = FormController.Instance.MainForm as GraphForm;\r
+ if (graphForm != null)\r
+ {\r
+ Text = "Attributes of " + graphForm.Text;\r
+ attributePropertyGrid.SelectedObject = graphForm.Graph;\r
+ }\r
+ }\r
+ \r
+ private static PropertyDescriptorCollection GetComponentProperties(XPathNavigator schema, string component)\r
+ {\r
+ PropertyDescriptorCollection properties = new PropertyDescriptorCollection(new PropertyDescriptor[0]);\r
+ \r
+ XmlNamespaceManager namespaces = new XmlNamespaceManager(schema.NameTable);\r
+ namespaces.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");\r
+ namespaces.AddNamespace("html", "http://www.w3.org/1999/xhtml");\r
+ \r
+ /* look for each attribute with the graph component */\r
+ XPathNodeIterator componentElements = schema.Select(\r
+ string.Format("/xsd:schema/xsd:complexType[@name='{0}']/xsd:attribute", component),\r
+ namespaces);\r
+ while (componentElements.MoveNext()) {\r
+ List<Attribute> descriptorAttributes = new List<Attribute>();\r
+ string name = componentElements.Current.GetAttribute("ref", string.Empty);\r
+ \r
+ /* add default attribute for any defaults */\r
+ string descriptorDefault = componentElements.Current.GetAttribute("default", string.Empty);\r
+ if (!string.IsNullOrEmpty (descriptorDefault))\r
+ descriptorAttributes.Add(new DefaultValueAttribute(descriptorDefault));\r
+ \r
+ /* add description attribute for any documentation (we'll need to preserve paragraph breaks though) */\r
+ StringBuilder description = new StringBuilder();\r
+ XPathNodeIterator paragraphs = schema.Select (\r
+ string.Format("/xsd:schema/xsd:attribute[@name='{0}']/xsd:annotation/xsd:documentation/html:p", name), namespaces);\r
+ while (paragraphs.MoveNext ()) {\r
+ if (description.Length > 0)\r
+ description.Append("\r\n");\r
+ description.Append((string)paragraphs.Current.Evaluate("normalize-space(.)", namespaces));\r
+ }\r
+ if (description.Length > 0)\r
+ descriptorAttributes.Add(new DescriptionAttribute(description.ToString()));\r
+ \r
+ /* add standard values and type converter attribute for xsd:boolean or any enumerations */\r
+ string type = (string)schema.Evaluate(\r
+ string.Format("string(/xsd:schema/xsd:attribute[@name='{0}']/@type)", name), namespaces);\r
+ switch (type) {\r
+ case "xsd:boolean":\r
+ descriptorAttributes.Add(new StandardValuesTypeConverter.Attribute(new string[]{"false", "true"}));\r
+ descriptorAttributes.Add(new TypeConverterAttribute(typeof(StandardValuesTypeConverter)));\r
+ break;\r
+ default:\r
+ if (!type.StartsWith("xsd")) {\r
+ XPathNodeIterator enumeration = schema.Select(\r
+ string.Format("/xsd:schema/xsd:simpleType[@name='{0}']/xsd:restriction/xsd:enumeration/@value", type),\r
+ namespaces);\r
+ if (enumeration.Count > 0) {\r
+ List<string> standardValues = new List<string>();\r
+ while (enumeration.MoveNext())\r
+ standardValues.Add(enumeration.Current.Value);\r
+ \r
+ descriptorAttributes.Add(new StandardValuesTypeConverter.Attribute(standardValues));\r
+ descriptorAttributes.Add(new TypeConverterAttribute(typeof(StandardValuesTypeConverter)));\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ \r
+ /* now create and add the property to the collection */\r
+ properties.Add(new GraphPropertyDescriptor(component, name, descriptorAttributes.ToArray()));\r
+ }\r
+ return properties;\r
+ }\r
+ \r
+ static AttributeInspectorForm()\r
+ {\r
+ /* read the schema from our application directory */\r
+ /* NOTE: we use XPathDocument instead of XmlDocument since it is faster in the read-only case */\r
+ XPathNavigator schema = new XPathDocument(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "attributes.xml")).CreateNavigator();\r
+ \r
+ /* scan attribute schema for graph components */\r
+ _graphProperties = GetComponentProperties(schema, "graph");\r
+ _nodeProperties = GetComponentProperties(schema, "node");\r
+ _edgeProperties = GetComponentProperties(schema, "edge");\r
+\r
+ // NOTE: this has to run AFTER we set up the graph, node & edge properties so the external property tabs can read them in\r
+ _instance = new AttributeInspectorForm();\r
+ }\r
+ \r
+ private static AttributeInspectorForm _instance;\r
+ private static PropertyDescriptorCollection _graphProperties;\r
+ private static PropertyDescriptorCollection _nodeProperties;\r
+ private static PropertyDescriptorCollection _edgeProperties;\r
+ }\r
+}
\ No newline at end of file