|
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Workflow.Runtime;
using DDW;
using DDW.Collections;
using EnvDTE;
using EnvDTE80;
using Microsoft.CSharp;
using Pfactor.Extras;
using Pfactor.Workflow;
using CodeNamespace = System.CodeDom.CodeNamespace;
namespace Pfactor
{
public partial class DecoratorForm : Form
{
private readonly DTE2 app;
private Project currentProject;
/// <summary>
/// Ridiculous.
/// </summary>
private bool suppressTreeEvents;
private readonly Tooltip toolTip;
public DecoratorForm(DTE2 app)
{
InitializeComponent();
this.app = app;
toolTip = new Tooltip();
}
public TreeNode FindNode(string text)
{
foreach (TreeNode tn in theTree.Nodes)
{
if (tn.Text == text)
return tn;
TreeNode tn2 = FindNode(tn, text);
if (tn2 != null) return tn2;
}
return null;
}
private void AddFileToTree(string file)
{
if (!File.Exists(file))
return;
using (StreamReader sr = new StreamReader(file))
{
Lexer l = new Lexer(sr);
TokenCollection tc = l.Lex();
Parser p = new Parser(string.Empty);
CompilationUnitNode cun = p.Parse(tc, l.StringLiterals);
foreach (NamespaceNode nn in cun.Namespaces)
AddNamespaceToTree(nn, null);
}
}
private void AddNamespaceToTree(NamespaceNode nn, TreeNode parent)
{
if (nn == null) return;
if (nn.Structs.Count + nn.Classes.Count == 0) return;
// add the namespace itself
TreeNode nnNode = FindNode(nn.Name.GenericIdentifier);
if (nnNode == null)
{
if (parent == null)
nnNode = theTree.Nodes.Add(nn.Name.GenericIdentifier);
else
nnNode = parent.Nodes.Add(nn.Name.GenericIdentifier);
}
// tag nnNode
nnNode.Tag = nn;
nnNode.ImageIndex = 0;
// whoops!
foreach (NamespaceNode nn2 in nn.Namespaces)
AddNamespaceToTree(nn2, nnNode);
foreach (ClassNode cn in nn.Classes)
{
TreeNode classNode = nnNode.Nodes.Add(cn.Name.Identifier);
classNode.Tag = cn;
classNode.ImageIndex = 1;
}
foreach (StructNode sn in nn.Structs)
{
TreeNode structNode = nnNode.Nodes.Add(sn.Name.Identifier);
structNode.Tag = sn;
structNode.ImageIndex = 1;
}
}
private void btnOK_Click(object sender, EventArgs e)
{
MakeDecorators();
}
private void DecoratorForm_Load(object sender, EventArgs e)
{
LoadToolTips();
if (app.SelectedItems.Count == 1)
{
SelectedItem si = app.SelectedItems.Item(1);
currentProject = si.Project;
IEnumerable<string> files = Util.GetProjectFiles(currentProject);
// use existing files
List<string> faultyFiles = new List<string>();
foreach (string file in files)
{
try
{
AddFileToTree(file);
}
catch
{
faultyFiles.Add(file);
}
}
if (faultyFiles.Count > 0)
{
var sb = new StringBuilder();
sb.AppendLine("The following files could not be parsed:");
sb.AppendLine();
foreach (string file in faultyFiles)
sb.AppendLine(" - " + file);
MessageBox.Show(
sb.ToString(), "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
private void LoadToolTips()
{
toolTip.UseVisualStyle = toolTip.UseAnimation = toolTip.UseFading = true;
toolTip.MaximumWidth = 320;
toolTip.Opacity = 1.0f;
toolTip.InitialDelay = 500;
toolTip.FadeDelay = 250;
toolTip.SetToolTip(btnOK.Handle, "Click to create the decorator for the chosen items and add it to the project.");
toolTip.SetToolTip(tbClassName.Handle,
"Enter the name of the class to create here. A corresponding file with .cs extension will be created in the solution.");
}
private static void downRecursiveSetCheck(TreeNodeCollection tnc, bool state)
{
foreach (TreeNode tn in tnc)
{
tn.Checked = state;
downRecursiveSetCheck(tn.Nodes, state);
}
}
private static TreeNode FindNode(TreeNode parent, string text)
{
foreach (TreeNode tn in parent.Nodes)
if (tn.Text == text)
return tn;
return null;
}
private static void GetClassesAndStructsFromNodes(ICollection<ClassNode> classes, TreeNodeCollection nodes)
{
if (nodes == null) return;
foreach (TreeNode n in nodes)
{
if (n.Checked && n.Tag != null)
{
// StructNode derives from ClassNode
ClassNode cn = n.Tag as ClassNode;
if (cn != null) classes.Add(cn);
}
GetClassesAndStructsFromNodes(classes, n.Nodes);
}
}
private void MakeDecorators()
{
// get all classes and structs that this is about to decorate
var classes = new List<ClassNode>();
GetClassesAndStructsFromNodes(classes, theTree.Nodes);
// now build our new class
CodeNamespace cn = new CodeNamespace(
Util.GetProjectProperty(currentProject, "DefaultNamespace")
);
CodeTypeDeclaration decoratorClass = new CodeTypeDeclaration(tbClassName.Text)
{
IsClass = true
};
cn.Types.Add(decoratorClass);
/* not a good idea
foreach (ClassNode n in classes)
decoratorClass.BaseTypes.Add("I" + n.Name.Identifier); */
WorkflowRuntime wr = new WorkflowRuntime();
AutoResetEvent are = new AutoResetEvent(false);
wr.WorkflowCompleted += ((sender, e) => are.Set());
wr.WorkflowTerminated += ((sender, e) => MessageBox.Show(e.Exception.Message));
WorkflowInstance wi = wr.CreateWorkflow(
typeof (BuildDecorator), new Dictionary<string, object>
{
{"Decorator", decoratorClass},
{"Classes", classes}
});
wi.Start();
are.WaitOne();
// now the provider business
var sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeGenerator generator = provider.CreateGenerator(sw);
generator.GenerateCodeFromNamespace(cn, sw, new CodeGeneratorOptions());
// add this stuff to the solution
Util.SaveDataAndAddToProject(
app,
currentProject,
decoratorClass.Name + ".cs",
Util.RemoveEmptyLinesAndAt(sb.ToString()),
true);
Close();
}
private void theTree_AfterCheck(object sender, TreeViewEventArgs e)
{
if (!suppressTreeEvents)
{
downRecursiveSetCheck(e.Node.Nodes, e.Node.Checked);
upRecursiveSetCheck(e.Node);
updateOKButton();
}
}
/// <summary>
/// OK button is enabled only if at least one class/struct is
/// selected and the class name is not empty.
/// </summary>
private void updateOKButton()
{ // hack
var classes = new List<ClassNode>();
GetClassesAndStructsFromNodes(classes, theTree.Nodes);
btnOK.Enabled = classes.Count > 0 && tbClassName.Text.Length > 0;
}
private void upRecursiveSetCheck(TreeNode treeNode)
{
// if I have no parents, return
if (treeNode.Parent == null) return;
// are all my siblings checked
bool allSet = true;
foreach (TreeNode tn in treeNode.Parent.Nodes)
{
if (!tn.Checked) allSet = false;
}
// programmatically set parent
if (allSet)
{
suppressTreeEvents = true;
treeNode.Parent.Checked = true;
suppressTreeEvents = false;
upRecursiveSetCheck(treeNode.Parent);
}
else // some are unset
{
suppressTreeEvents = true;
treeNode.Parent.Checked = false;
suppressTreeEvents = false;
upRecursiveSetCheck(treeNode.Parent);
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I work primarily with the .NET technology stack, and specialize in accelerated code production via code generation (static or dynamic), aspect-oriented programming, MDA, domain-specific languages and anything else that gets products out the door faster. My languages of choice are C# and C++, though I'm open to suggestions.