|
using System;
using Extensibility;
using EnvDTE;
using System.Collections;
namespace RefactorAddIn
{
/// <summary>
/// Move a selected function to the superclass
/// </summary>
public class MoveToSuperClass : RefactorAddIn.VSPlugIn
{
public MoveToSuperClass(_DTE applicationObject, AddIn addInInstance)
: base(applicationObject, addInInstance)
{ }
#region private vars
CodeElement element2Move = null;
CodeFunction function2Move = null;
CodeProperty property2Move = null;
CodeVariable Variable2Move = null;
CodeClass targetClass = null;
CodeClass sourceClass = null;
#endregion
#region overrides
public override string longDescription
{
get
{
return "Move the selected item into the superclass";
}
}
public override string cmdName
{
get
{
return "MoveFunctionToSuperclass";
}
}
public override string qualifiedName
{
get
{
return "RefactorAddIn.Connect.MoveFunctionToSuperclass";
}
}
public override string shortDescription
{
get
{
return "Move item to super class";
}
}
public override int iconId
{
get
{
return 54;
}
}
public override int position
{
get
{
return 1;
}
}
#endregion
#region connect calls
protected override bool doExec()
{
if (!isMoveableItem())
return false;
switch (element2Move.Kind)
{
case vsCMElement.vsCMElementFunction:
copyFunction();
break;
case vsCMElement.vsCMElementProperty:
copyProperty();
break;
case vsCMElement.vsCMElementVariable:
copyVariable();
break;
}
sourceClass.RemoveMember(element2Move);
return true;
}
/// <summary>
/// can we do this?
/// </summary>
/// <returns></returns>
protected override EnvDTE.vsCommandStatus doQueryStatus()
{
identifySelectedItem();
if (isMoveableItem())
{
// superclass must not have a class of this signature
if(alreadyHasElement(targetClass,(CodeElement) element2Move))
return vsCommandStatus.vsCommandStatusUnsupported;
else
return vsCommandStatus.vsCommandStatusEnabled | vsCommandStatus.vsCommandStatusSupported;
}
return vsCommandStatus.vsCommandStatusUnsupported;
}
#endregion
#region worker stuff
/// <summary>
/// determine what it actually is that has been selected.
/// sets element2Move and SourceClass
/// </summary>
private void identifySelectedItem()
{
element2Move = null;
property2Move = (CodeProperty) this.selectedElement(vsCMElement.vsCMElementProperty);
if (property2Move != null)
{
element2Move = (CodeElement)property2Move;
sourceClass = property2Move.Parent;
}
function2Move = (CodeFunction) this.selectedElement(vsCMElement.vsCMElementFunction);
if (function2Move != null)
{
element2Move = (CodeElement)function2Move;
sourceClass = (CodeClass)function2Move.Parent;
}
Variable2Move = (CodeVariable) this.selectedElement(vsCMElement.vsCMElementVariable);
if (Variable2Move != null)
{
element2Move = (CodeElement)Variable2Move;
sourceClass = (CodeClass)Variable2Move.Parent;
}
}
/// <summary>
/// get the detail of the item to move and its target.
/// sets Element2Move and targetClass
/// </summary>
/// <returns>true if circumstances allow moving it</returns>
private bool isMoveableItem()
{
//condition something must be a selectied
if (element2Move == null)
return false;
// condition 2: it must be part of a CodeClass
if (sourceClass == null)
return false;
// condition 3: it must have a super class
if (sourceClass.Bases.Count == 0)
return false;
for (int idx = 1; idx <= sourceClass.Bases.Count; idx++)
{
CodeElement base1 = sourceClass.Bases.Item(idx);
// the base must be a class, not an interface
if (base1.Kind == vsCMElement.vsCMElementClass)
{
targetClass = base1 as CodeClass;
return (IsPartOfProject(targetClass));
}
}
return false;
}
/// <summary>
/// check if a Class is part of the project or not
/// </summary>
/// <param name="parent"></param>
/// <returns></returns>
private bool IsPartOfProject(CodeClass parent)
{
try
{
ProjectItem project = parent.ProjectItem;
}
catch (Exception) {return false;}
return true;
}
/// <summary>
/// identify if the parent classs already has anelement of this signature
/// </summary>
/// <param name="parent"></param>
/// <param name="elementToMove"></param>
/// <returns></returns>
private bool alreadyHasElement(CodeClass parent, CodeElement elementToMove)
{
foreach (CodeElement member in parent.Members)
{
if ((member.Kind == elementToMove.Kind)
&&(member.Name == elementToMove.Name))
{
switch (elementToMove.Kind)
{
case vsCMElement.vsCMElementFunction:
return FunctionsHaveSameSignature((CodeFunction)elementToMove, (CodeFunction)member);
case vsCMElement.vsCMElementProperty:
return true;
case vsCMElement.vsCMElementVariable:
return true;
default:
return true;
}
}
}
return false;
}
/// <summary>
/// compare the signature of two function. This means checking the parameters
/// for their types. The return value is not checked
/// </summary>
/// <param name="func1"></param>
/// <param name="func2"></param>
/// <returns>true if the signatures are the same</returns>
private bool FunctionsHaveSameSignature(CodeFunction func1, CodeFunction func2)
{
bool sameSoFar = (func1.Parameters.Count == func2.Parameters.Count);
if (sameSoFar)
{
IEnumerator func1Params = func1.Parameters.GetEnumerator();
IEnumerator func2Params = func2.Parameters.GetEnumerator();
while (func1Params.MoveNext())
{
func2Params.MoveNext();
CodeParameter func1Param = (CodeParameter)(func1Params.Current);
CodeParameter func2Param = (CodeParameter)(func2Params.Current);
if (func1Param.Type.TypeKind != func2Param.Type.TypeKind)
return false;
}
return true;
}
else return false;
}
/// <summary>
/// create a copy of the function in the targetclass
/// </summary>
private void copyFunction()
{
CodeFunction cf = (CodeFunction)element2Move;
EditPoint src =cf.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint();
string text = src.GetText(cf.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes));
string filename = targetClass.ProjectItem.get_FileNames(0);
CodeFunction newCF = targetClass.AddFunction(
element2Move.Name,vsCMFunction.vsCMFunctionFunction,cf.Type,-1,cf.Access, filename);
TextPoint tp = newCF.GetStartPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes);
EditPoint ep =tp.CreateEditPoint();
ep.ReplaceText(newCF.GetEndPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes),
text,3);
sourceClass.RemoveMember(element2Move);
}
private void copyVariable()
{
string filename = targetClass.ProjectItem.get_FileNames(0);
CodeVariable newVar = targetClass.AddVariable(
element2Move.Name, Variable2Move.Type , 1 ,Variable2Move.Access, filename);
EditPoint src =Variable2Move.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint();
string text = src.GetText(Variable2Move.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes));
TextPoint tp = newVar.GetStartPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes);
EditPoint ep =tp.CreateEditPoint();
ep.ReplaceText(newVar.GetEndPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes),
text,3);
sourceClass.RemoveMember(element2Move);
}
private void copyProperty()
{
string filename = targetClass.ProjectItem.get_FileNames(0);
CodeProperty newProperty = targetClass.AddProperty(
"A", "A", property2Move.Type , 1 ,property2Move.Access, filename);
newProperty.Name = property2Move.Name;
EditPoint src =property2Move.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).CreateEditPoint();
string text = src.GetText(property2Move.GetEndPoint(vsCMPart.vsCMPartWholeWithAttributes));
TextPoint tp = newProperty.GetStartPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes);
EditPoint ep =tp.CreateEditPoint();
ep.ReplaceText(newProperty.GetEndPoint(EnvDTE.vsCMPart.vsCMPartWholeWithAttributes),
text,3);
sourceClass.RemoveMember(element2Move);
}
#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.
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.