Sparx Systems Forum
Enterprise Architect => Automation Interface, Add-Ins and Tools => Topic started by: SiliconRancher on April 04, 2013, 07:33:11 am
-
Hello,
I'm trying to write a simple add-in (with C#) that allows user to copy selected element with some modifications pre-set in my add-in (e.g. with name change).
I'm totally new to EA (although with some experience in C#) and I have no idea how to enter into element's attributes, then change them and copy to new element.
As far as it goes I have only this:
public void EA_MenuClick(EA.Repository Repository, string Location, string
MenuName, string ItemName)
{
Object o = new Object();
o = Repository.GetContextItem(out o);
}
Poor, isn't it?
I've searched almost all the internet and didn't find a clue.
Thanks in advance for any help.
-
If you're completely new to EA's API I can recommend my book Scripting EA. If you are deeper in the matters you should check out Geerts EA Navigator addin: http://bit.ly/Y1pCwT
q.
-
Hmm, ok that is indeed a long way to go.
Now how to start... :-?
You now have an Object o, but I guess you really need an EA.Element. In that case you'll have to test if your o is of type EA.Element, and then cast it.
Something like:
if (o is EA.Element)
{
EA.Element selectedElement = (EA.Element)o;
}
So that's better already, you now have selectedElement of type EA.Element.
Then you might want to create a new element to copy to.
I'm not sure anymore if there are any 'clone' operations available in the API, you might want to search the forum for it.
But if you would want to copy your element manually you need a package or other element to add the new element to.
Suppose you want to add the element to the same package then you would need to do something like:
EA.Package parentPackage = Repository.GetPackageByID(selectedElement.PackageID);
EA.Element elementCopy = parentPackage.Elements.AddNew(selectedElement.Name + "_copy", selectedElement.ObjectType);
That gives you a copy of the Element. Now you need to copy the properties you need to your copy element (think stereotype, state, phase,etc...)
And then you might want to copy the features such as attributes.
To do this you need to loop the existing attributes and create a new attribute for each one of them something like:
foreach (EA.Attribute attribute in selectedElement.Attributes)
{
elementCopy.Attributes.AddNew(attribute.Name + "_copy", "Attribute);
}
And then of course don't forget to copy the other properties of your attributes.
I hope this helps. I have some more EA addin tutorials on my blog: http://geertbellekens.wordpress.com/ and a whole lot of example code on github: https://github.com/GeertBellekens/
Geert
PS. I haven't syntax checked the example code above, might not compile like that.
-
Thank you so much for your help, you make so much good work here; also your tutorials were the first (and yet only, except the documentation...) useful thing I found in the Internet aboud writing add-ins to EA.
I'm now able to copy my Element (particulary table, because this add-in is about tables), but still I can't copy attributes.
Now my copy method looks like this:
private void copyIt(EA.Repository Repository, EA.Diagram diagram)
{
Object o = new Object();
Repository.GetContextItem(out o).ToString();
if (o is EA.Element)
{
EA.Element selectedElement = (EA.Element)o;
if (selectedElement.Stereotype == "table")
{
EA.Package parentPackage = Repository.GetPackageByID(selectedElement.PackageID);
EA.Element elementCopy = parentPackage.Elements.AddNew(selectedElement.Name.ToString() + "_copy",selectedElement.Type.ToString());
MessageBox.Show(selectedElement.Properties.Count.ToString() + selectedElement.Methods.Count.ToString());
// element that I try to copy has 2 properties and 3 methods; also 3 attributes - table columns
elementCopy.Status = selectedElement.Status;
elementCopy.Phase = selectedElement.Phase;
elementCopy.Stereotype = selectedElement.Stereotype;
elementCopy.MetaType = selectedElement.MetaType;
elementCopy.Notes = selectedElement.Notes;
foreach (EA.Attribute attribute in selectedElement.Attributes)
{
elementCopy.Attributes.AddNew(attribute.Name + "_copy", "Attribute");
}
MessageBox.Show(elementCopy.Attributes.Count.ToString() + " " + selectedElement.Attributes.Count.ToString());
// new element doesn't get any new attributes
foreach (EA.Method method in selectedElement.Methods)
{
elementCopy.Methods.AddNew(method.Name + "_copy", "Method");
MessageBox.Show(elementCopy.Methods.Count.ToString());
// the same is true for methods
}
foreach (EA.CustomProperty customProperty in selectedElement.CustomProperties)
{
elementCopy.CustomProperties.AddNew(customProperty.Name + "_copy", "CustomProperty");
}
elementCopy.Update();
Repository.RefreshModelView(parentPackage.PackageID);
diagram.Update();
}
else
{
MessageBox.Show("That's not a table, that's "+selectedElement.Stereotype);
}
}
else
{
MessageBox.Show("That's not Element, that's "+o.GetType().ToString());
}
}
If you're completely new to EA's API I can recommend my book Scripting EA. If you are deeper in the matters you should check out Geerts EA Navigator addin: http://bit.ly/Y1pCwT
Someday I propably will, but not yet, I'm not even sure if I'll use EA anymore (that strongly depends of this particular add-in to be honest) :)
-
You need to call Update after the addnew. Further the 2nd parameter is taken as Type of the attr. I guess it should not be "Attribute" but rather blank or "int" or something.
q.
-
I added update and refresh, but it's not the case :( And I think it's not about the type of the attribute. I tried e.g. this:
foreach (EA.Attribute attribute in selectedElement.Attributes)
{
elementCopy.Attributes.AddNew(attribute.Name + "_copy", attribute.Type);
elementCopy.Attributes.Refresh();
elementCopy.Update();
}
I even tried doing it in ulgy way:
elementCopy = selectedElement;
But it didn't get me anywhere. I also thought that I sholud get "inside" each attribute:
short i = 0;
foreach (EA.Attribute att in elementCopy.Attributes)
{
att.Type = selectedElement.Attributes.GetAt(i).Type;
att.Style = selectedElement.Attributes.GetAt(i).Style;
att.Stereotype = selectedElement.Attributes.GetAt(i).Stereotype;
att.Containment = selectedElement.Attributes.GetAt(i).Containment;
att.Container = selectedElement.Attributes.GetAt(i).Container;
elementCopy.Attributes.Refresh();
elementCopy.Update();
i++;
}
But it also was pointless. I can't copy columns of my original element (table), maybe it's just not possible to do it this way? So maybe there's a different way - taking SQL code from the first element and "inserting" it into the copy? But then - how?
-
Here is a basic example of how I would copy an element and it's attributes:
EA.Element selectedElement = (EA.Element)repository.GetContextObject();
EA.Package thePackage = repository.GetPackageByID(selectedElement.PackageID);
EA.Element elementCopy = (EA.Element)thePackage.Elements.AddNew("Copy of " + selectedElement.Name, selectedElement.Type);
elementCopy.Notes = selectedElement.Notes;
//TODO: insert any other properties here that you need to copy for the element
elementCopy.Update();
for (short i = 0; i < selectedElement.Attributes.Count; i++)
{
EA.Attribute originalAtt = (EA.Attribute)selectedElement.Attributes.GetAt(i);
EA.Attribute copyAtt = (EA.Attribute)elementCopy.Attributes.AddNew(originalAtt.Name, originalAtt.Type);
copyAtt.Style = originalAtt.Style;
copyAtt.StereotypeEx = originalAtt.StereotypeEx;
copyAtt.Pos = originalAtt.Pos;
//TODO: insert any other properties here that you need to copy for the attribute
copyAtt.Update();
}
You do not need to call Refresh() on a collection unless there have been additions or deletions to the collection and you need to loop over it again. Never call Refresh() while in a loop.
-
Thanks, it did the trick :) Now I have to try with methods to make original table's PK aa FK in the copy and I will have fun with other attributes and such.
One last question - is there a way to make the copy appear in the diagram (the same diagram as the original element)?
-
Sure. You need to create diagram objects for the currently open diagram.
q.
-
Of course I'm stuck again :( Now I am able to copy attributes and methods, but while I'm copying parameters of methods:
for (short k = 0; k < originalMethod.Parameters.Count; k++)
{
EA.Parameter origParameter = (EA.Parameter)originalMethod.Parameters.GetAt(k);
EA.Parameter copyParameter = (EA.Parameter)copyParameter.Parameters.AddNew(origParameter.Name+"copy", origParameter.Type);
cV.Update();
cM.Update();
}
I receive an error:
(http://i47.tinypic.com/2eockki.jpg)
Also I tried to find out - without succes - which attribute of the column attribute holds the info about input data type (what type - eg. integer or char - is put inside a column) and how much data can user put inside (eg. char[15]). Also where can I set which column is primary key? And set the column's values as "unique" - or switch it off.
Thank you in advance.
P.S. about adding objects (in my case - link to object) to diagram:
Repository.GetCurrentDiagram().DiagramLinks.AddNew(elementCopy.Name, elementCopy.Type);
Repository.GetCurrentDiagram().Update();
Repository.RefreshOpenDiagrams(true);
Of course it doesn't work. What am I missing?
-
Have you once in a while thought of RTFM?
q.
-
I know this is a bit simplistic and may be missing the point but if you want to create a direct copy of an element on a diagram just ctrl drag it and give it a new name. No coding required.
-
Sure :-) But the reason for writing an add-in is to avoid doing it manually - for many reasons.
q.
-
Hi,
I just wondering if is it possible to copy elements between packages without this long way by copying attributes, tagged values, operations and so on?
Thanks.
-
See EaPackage.Clone()
q.
-
The Clone() function inserts a copy of the package into the same parent as the original package. Returns the newly-created package.
I'm asking about copy/clone elements such a classes, attributes, connectors and ect.
Thanks.
-
If the Clone does not return what you expect you have two choices: a) code it the way your expectations are fulfilled; b) ask Harry Potter to lend you his magic stick.
q.
-
;D, did you mean nobody needs to copy/clone elements? Such a pitty :(.
-
EA is targeted to support OO. So why in the world could someone have the idea that EAs API should be somehow OO, e.g. by providing a clone method not only for packages, but also for elements, diagram, etc.? Or to offer a Delete methods for all of them? Probably because nobody demands it (I asked the last question in the suggestions and got not a single response). And why is nobody asking for a strict OO API? I guess because people rather like GOTO and spaghetti code.
q.
-
I guess because people rather like GOTO and spaghetti code.
q.
Or people have given up asking for improvements, and just make due with what's available. :-/
Geert