Click here to Skip to main content
15,892,746 members
Articles / Programming Languages / C#

Building a Refactoring Plug-in for VS.NET - the Sequel

Rate me:
Please Sign up or sign in to vote.
4.70/5 (31 votes)
31 Aug 20047 min read 158.2K   1.9K   95  
Describes how to extend the original refactor add-in with additional features.
using System;
using Microsoft.Office.Core;
using Extensibility;
using System.Runtime.InteropServices;
using EnvDTE;
using System.IO;

namespace RefactorAddIn
{
	/// <summary>
	/// CollectionGenerator
	/// Version: 0.1   draft
	/// Copyright 2004 (c) Stephan Meyn
	/// Role:
	/// Responsibilities:
	/// <list type="bullet">
	/// <item></item>
	/// </list>
	/// 
	/// 
	/// </summary>
	public class CollectionGenerator: VSPlugIn	
	{
		
		private CodeClass sourceClass;
		#region public Attributes
		public override string cmdName
		{
			get
			{
				return "GenerateCollection";
			}
		}
		public override string qualifiedName
		{
			get
			{
				return "RefactorAddIn.Connect.GenerateCollection";
			}
		}
		public override string shortDescription{get { return "Generate Collection Class";} }
		public override string longDescription { get {return "Generates Code for a collection class for current class"; }}
		public override int position { get {return  1;} }
		public override int iconId { get {return 54;} }


		#endregion

		#region construction
		public CollectionGenerator(_DTE applicationObject, AddIn addInInstance)
			: base(applicationObject, addInInstance)
		{		}
		#endregion

		#region public methods
		protected override EnvDTE.vsCommandStatus doQueryStatus()
		{
			vsCommandStatus status = vsCommandStatus.vsCommandStatusInvisible;
	
			CodeElement selection = selectedElement(vsCMElement.vsCMElementClass);

			if (selection != null)
			{
				// Show MenuItem
				status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled; 					
			}
			else 
				status = (vsCommandStatus)vsCommandStatus.vsCommandStatusInvisible;
			return status;
		}
		protected override bool doExec()
		{
			CodeClass selection = selectedElement(vsCMElement.vsCMElementClass) as CodeClass;
			if (selection != null)
				return generateCollectionClass(selection);
			else 
				return false;
		}

		#endregion

		#region private methods

		/// <summary>
		/// print out what is currently selected
		/// </summary>
		[Obsolete]private void whatIsSelected()
		{

			Object obj = _applicationObject.SelectedItems.SelectionContainer.Item(1);
				if (obj == null) return;
				
				CodeElement e = obj as CodeElement;
				if (e is CodeClass)
				{
					CodeClass cc =e as CodeClass;
					message("Selected is CodeClass {0}",  cc.Name);
				}
				else if (e is CodeAttribute)
				{
					CodeAttribute cc = e as CodeAttribute;
					message("Selected is CodeAttribute {0}",  cc.Name);
				}
				else if (e is CodeProperty)
				{
					CodeProperty cc = e as CodeProperty;
					message("Selected is CodeProperty {0}",  cc.Name);
				}
				else 
				{
					message("Selected[{0}] is {1}", e.Name, e.Kind);
				}
			
		}


		private bool generateCollectionClass(CodeClass classElement)
		{
			sourceClass = classElement;
			try
			{
				string baseClassName = classElement.Name;
				CollectionBuilder gen = new CollectionBuilder(baseClassName);
				string classCode = gen.Generate();
				InsertNewCodeFileForClass(gen.CollectionClassName, classCode);
//				System.Windows.Forms.Clipboard.SetDataObject(classCode, true);
//				message("the code has been placed onto the clipboard");
			} 
			catch (Exception ex)
			{
				string msg = ex.Message;
				message (msg);
			}
			return true;
		}

		/// <summary>
		/// insert a new class item
		/// </summary>
		/// <remarks>Doesn't worl as AddClass is not implemented</remarks>
		/// <param name="CollectionClassName"></param>
		/// <param name="classCode"></param>
		private void InsertNewCodeFileForClass(string CollectionClassName, string classCode)
		{
			//a replacement for this call.
//			CodeClass result = projectItem.ContainingProject.CodeModel.AddClass(
//				CollectionClassName, CollectionClassName+".cs", 0, 0,0,vsCMAccess.vsCMAccessPublic);
			string sourceClassPath =sourceClass.ProjectItem.Document.Path;
			string targetPathRoot = System.IO.Path.GetDirectoryName(sourceClassPath);
			string newFileName = uniqueFileName(CollectionClassName + ".cs", targetPathRoot);
			using (StreamWriter sw = File.CreateText(newFileName))
			{
				sw.WriteLine ("using System.Collections;");
				sw.WriteLine();
				sw.WriteLine(classCode);
			}
			
			ProjectItems items = projectItem.ContainingProject.ProjectItems;
			items.AddFromFile(newFileName);
		}
		/// <summary>
		/// generate a unique filename to avoid clashes with existing filenames
		/// </summary>
		/// <returns></returns>
		private string uniqueFileName(string proposedFileName, string targetDirectory)
		{
			string extension = Path.GetExtension(proposedFileName);
			string baseFileName = Path.GetFileNameWithoutExtension(proposedFileName);
			int verNumber = 0;
			string fileName = proposedFileName;
			string result = Path.Combine(targetDirectory, fileName);
			while (File.Exists(result))
			{
				verNumber++;
				fileName = string.Format("{0}_{1}{2}",baseFileName, verNumber, extension);
				result =Path.Combine(targetDirectory, fileName);
			}
			return result;
		}
		#endregion
	}
}

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Australia Australia
I am a Software Engineer/Consultant. My work is focussed on helping teams to get more out of their work. So I teach how to do requirements, analysis and design in a format that is easy to understand and apply.
I help with testing too, from starting developers on automated unit testing to running whole testing teams and how they cooperate with development.

For really big projects I provide complete methodologies that support all of the lifecycle.

For relaxation I paddle a sea kayak around Sydney and the Central Coast or write utilities on rainy days to make my life easier.

Comments and Discussions