using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.Win32;
using Clifton.Tools.Strings;
using Clifton.Tools.Strings.Extensions;
using Clifton.Windows.Forms;
using Clifton.Windows.Forms.XmlTree;
using MyXaml.Core;
using XTreeInterfaces;
using ROPLib;
// Original article here: http://www.codeproject.com/KB/tree/XTreeII.aspx
namespace XTreeDemo
{
public class Program
{
[MyXamlAutoInitialize]
XTree sdTree = null;
[MyXamlAutoInitialize]
PropertyGrid pgProperties = null;
protected Form form;
protected string caption;
protected string schemaFilename;
// protected SchemaDef schemaDef;
protected Schema schemaDef;
protected TreeNode rootNode;
protected static PropertyGrid pgProps;
public static PropertyGrid Properties
{
get { return pgProps; }
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new Program();
}
public Program()
{
Parser.AddExtender("MyXaml.WinForms", "MyXaml.WinForms", "WinFormExtender");
Parser p = new Parser();
p.AddReference("App", this);
form = (Form)p.Instantiate("schemaEditor.myxaml", "*");
p.InitializeFields(this);
pgProps = pgProperties;
schemaFilename = String.Empty;
caption = form.Text;
form.Shown += new EventHandler(OnShown);
Application.Run(form);
}
protected void OnShown(object sender, EventArgs e)
{
CreateRootNode();
}
protected void CreateRootNode()
{
IXtreeNode sc = new GenericController<Schema>();
//schemaDef = (SchemaDef)((GenericController<SchemaDef>)sc).Instance;
//rootNode = sdTree.AddNode(sc, null);
//pgProperties.SelectedObject = schemaDef;
schemaDef = (Schema)((GenericController<Schema>)sc).Instance;
rootNode = sdTree.AddNode(sc, null);
pgProperties.SelectedObject = schemaDef;
sdTree.SelectedNode = sdTree.Nodes[0];
}
protected void OnNew(object sender, EventArgs e)
{
schemaFilename = String.Empty;
ClearAll();
pgProperties.SelectedObject = schemaDef;
sdTree.SelectedNode = sdTree.Nodes[0];
}
protected void OnOpen(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.RestoreDirectory = true;
ofd.CheckFileExists = true;
ofd.Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*";
ofd.Title = "Load Schema";
DialogResult res = ofd.ShowDialog();
if (res == DialogResult.OK)
{
schemaFilename = ofd.FileName;
ClearAll();
Load();
}
}
protected void OnSave(object sender, EventArgs e)
{
if (schemaFilename == String.Empty)
{
OnSaveAs(sender, e);
}
else
{
Save();
}
}
protected void OnSaveAs(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
sfd.OverwritePrompt = true;
sfd.Filter = "xml files (*.xml)|*.xml|All files (*.*)|*.*";
sfd.Title = "Save Schema";
DialogResult res = sfd.ShowDialog();
if (res == DialogResult.OK)
{
schemaFilename = sfd.FileName;
Save();
UpdateCaption();
}
}
protected void OnExit(object sender, EventArgs e)
{
Application.Exit();
}
/// <summary>
/// Updates the XML node with the name set in the property grid.
/// </summary>
protected void OnPropertyValueChanged(object sender, PropertyValueChangedEventArgs e)
{
if (e.ChangedItem.Label == "Name")
{
sdTree.SelectedNode.Text = e.ChangedItem.Value.ToString();
}
}
protected void OnGenerateEntityRelationships(object sender, EventArgs e)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("digraph G {");
Schema.Instance.RelationshipsContainer.ForEach(t=>t.Relationships.ForEach(r=>
{
sb.AppendFormat(" {0} -> {1} [label={2}, taillabel={3}, headlabel={4}, labeldistance=2.0];\r\n", r.EntityA.Quote(), r.EntityB.Quote(), r.Label.Quote(), r.CardinalityALabel.Quote(), r.CardinalityBLabel.Quote());
}));
sb.AppendLine("}");
Generate(sb);
}
protected void OnGenerateEntityAttributes(object sender, EventArgs eventArgs)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("digraph G { graph [rankdir=\"LR\"];\r\n");
// Define the entities and their attributes.
Schema.Instance.EntitiesContainer.ForEach(t => t.Entities.ForEach(e =>
{
sb.AppendFormat("{0} [ label = \"<f0> {1}", e.Name.Quote(), e.Name);
int n=1;
e.EntityAttributes.ForEach(a =>
{
sb.AppendFormat("| <f{0}> {1}", n.ToString(), a.Name);
++n;
});
sb.AppendLine("\" shape = \"record\"]; ");
}));
// Create the graph by inspecting the relationships
Schema.Instance.RelationshipsContainer.ForEach(t=>t.Relationships.ForEach(r=>
{
sb.AppendFormat(" {0} -> {1} [label={2}, taillabel={3}, headlabel={4}, labeldistance=2.0];\r\n", r.EntityA.Quote(), r.EntityB.Quote(), r.Label.Quote(), r.CardinalityALabel.Quote(), r.CardinalityBLabel.Quote());
}));
sb.AppendLine("}");
Generate(sb);
}
protected void Generate(StringBuilder sb)
{
string filename = Path.GetTempFileName() + ".dot";
File.WriteAllText(filename, sb.ToString());
string progFilePath = Environment.GetEnvironmentVariable("ProgramFiles");
string progFilex86 = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
progFilePath = progFilex86 ?? progFilePath;
Process.Start(progFilePath + @"\Graphviz 2.28\bin\dotty.exe", filename);
File.Delete(@"c:\temp\graph.png");
var pr = Process.Start(progFilePath + @"\Graphviz 2.28\bin\dot.exe", "-Tpng " + filename + @" -o c:\temp\graph.png");
while (!pr.HasExited)
{
Thread.Sleep(100);
}
// Process.Start(@"c:\temp\graph.png");
Clipboard.SetText(sb.ToString());
}
protected void UpdateCaption()
{
form.Text = caption + " - " + Path.GetFileName(schemaFilename);
}
protected void ClearAll()
{
sdTree.Clear();
UpdateCaption();
CreateRootNode();
}
protected void Load()
{
XmlSerializer xs = new XmlSerializer(typeof(Schema));
StreamReader sr = new StreamReader(schemaFilename);
schemaDef = (Schema)xs.Deserialize(sr);
((GenericController<Schema>)((NodeInstance)rootNode.Tag).Instance).Instance = schemaDef;
sr.Close();
PopulateTree();
}
protected void Save()
{
XmlSerializer xs = new XmlSerializer(typeof(Schema));
TextWriter tw = new StreamWriter(schemaFilename);
xs.Serialize(tw, schemaDef);
tw.Close();
}
protected void RecurseCollection(NodeDef node, dynamic collection, TreeNode tnCurrent)
{
if (node.Nodes.Count > 0)
{
// Collection is a Dictionary<string, dynamic> where dynamic is a List<T>
// obj is a KeyValuePair<string, dynamic>
foreach (var kvp in collection.Collection)
{
string collectionName = kvp.Key;
var collectionItems = kvp.Value;
// Doesn't matter what nodeDef we find, this is only to get the TypeName and number of child nodes on recursion.
// But it does allow us to separate the serialization order from the tree definition order.
NodeDef nodeDef = node.Nodes.Find(t => t.TypeName.Contains(collectionName));
foreach (var item in collectionItems)
{
// Do not create new instances for the items, as they have already been created!
IXtreeNode controller = (IXtreeNode)Activator.CreateInstance(Type.GetType(nodeDef.TypeName), new object[] {false});
controller.Item = item;
TreeNode tn = sdTree.AddNode(controller, tnCurrent);
string name = ((IHasCollection)item).Name;
tn.Text = (String.IsNullOrWhiteSpace(name) ? tn.Text : name);
RecurseCollection(nodeDef, item, tn);
}
}
}
}
protected void PopulateTree()
{
sdTree.SuspendLayout();
// Remove all existing (such as required) nodes.
sdTree.Nodes[0].Nodes.Clear();
NodeDef nodeDef=sdTree.RootNode.Nodes[0]; // Get the child of the top level node.
RecurseCollection(nodeDef, schemaDef, rootNode);
sdTree.CollapseAll();
sdTree.Nodes[0].Expand();
sdTree.ResumeLayout();
pgProperties.SelectedObject = schemaDef;
sdTree.SelectedNode = sdTree.Nodes[0];
}
}
}