Using Add-In we are creating EA Elements in some random alphabetical order.
The sequence for EA elements in the project browser is shown in the below figure:
While fetching the EA Elements using the below mentioned code, the sequence is: a, c, D, E, g, H, J, B, f, i (B, f, i is of type Enumeration class and others are of type Class).
for (short k = 0; k < getElement.Elements.Count; k++)
{
EA.Element dataTypeEle = getElement.Elements.GetAt(k);
}
But the required output should be as per EA Elements sequence present in the Project browser as shown in the above figure.
How can we read EA Elements as per the sequence present in the project browser ?
EA.Element.Treepos contains the position in the project browser.
If that is all 0, or does not correspond with the order you are seeing then it might be that you have the option not to allow free sorting in the project browser on, which means everything is ordered alphabetically like set the underlying database (there can be tricky settings with umlaut etc.).
In that case you'll have to use the name to sort the collection.
Another thing is that EA has a strange way of grouping element types (such as diagrams, packages, elements, enumerations) which is probably hardcoded somewhere in the EA code, but it is always the same. So if you can't use Treepos then you'll have to figure it out yourself using the name and the grouping EA uses.
Related
I'd like to use EA to generate Requirement elements programatically. I need to use the same sequence numbering (REQ00000xy), as with the GUI when pressing "Auto" button in "Add Element ..." dialog in order to keep´consistent numbering for Requirement elements created either from GUI or from API.
Selecting the last used sequence number from already existing Requierement elements won't help, as it don't move the sequence number up and next Requirement created from GUI .
Is there a way to get (and properly use) the sequence number via EA API or EA SQL?
The table you're looking for is t_trxtypes. This contains something like (EA's output)
Description;NumericWeight;Notes;TRX;TRX_ID;Style;
Autocount;1,00;prefix=bla;suffix=x;active=1;active_a=0;counter=126;;Class;1; ;
You're interested in the column Notes which holds as CSV list like
prefix=bla;suffix=x;active=1;active_a=0;counter=126;
This is a test setting for a class which currently has the number 126. So the next created class would be named bla126x and the entry would change to
prefix=bla;suffix=x;active=1;active_a=0;counter=127;
Just keep the columne t_trxtypes.notes in synch with your creations.
Note EA does not (seem to) allow direct DB access. However, it has a proven back door:
Repository.Execute("UPDATE t_trxtypes SET Notes='prefix=bla;suffix=x;active=1;active_a=0;counter=127;' WHERE TRX_ID=<your id>")
will do the update (replace <your id> with the appropriate key). Though Execute is undocumented it works ever since and for sure Sparx will not limit it as nowadays everyone relies on it.
As a side note: This counter is not safe. There are lots of ways (the easiest is a simple rename) to break it. You'd need some script/add-in to have regular checks your numbering is still consistent. If you rely on requirement numbering you better use an external system like, I dare to say, DOORS.
Finally, RTFM....
For elements, where sequence is defined, if you use empty name in set =AddNew() function, EA generates the sequence upon .Update(). Not earlier. So if you plan to use the generated sequence and add some description, you need to create the element with empty name first, then Update() it and after that append your description to the content of the Name field.
As easy as this.
In my code, I have a structure and in a field of it, I want to sort its values.
For instance, in the field of File_Neg.name there are the following values, and They should be sorted as the right values.
File_Neg.name --> Sorted File_Neg.name
'-10.000000.dcm' '-10.000000.dcm'
'-102.500000.dcm' '-12.500000.dcm'
'-100.000000.dcm' '-100.000000.dcm'
'-107.500000.dcm' '-102.500000.dcm'
'-112.500000.dcm' '-107.500000.dcm'
'-110.000000.dcm '-110.000000.dcm'
'-12.500000.dcm' '-112.500000.dcm'
There is a folder that there are some pictures with negative labels in it (above example are labels of pictures). I want to get them in the same order as present in the folder(that's mean the Sorted File_Neg.name). But when running the following code the values of Files_Neg.name load as the above example (left: File_Neg.name), while I want the right form.
I have also seen this and that but they didn't help me.
How to sort values of a field in a structure in Matlab?
Files_Neg = dir('D:\Rename-RealN');
File_Neg = dir(strcat('D:\Rename-RealN\', Files_Neg.name, '\', '*.dcm'));
% when running the code the values of Files_Neg.name load as the above example (left: File_Neg.name)
File_Neg.name:
This answer to one of the questions linked in the OP is nearly correct for the problem in the OP. There are two issues:
The first issue is that the answer assumes a scalar value is contained in the field to be sorted, whereas in the OP the values are char arrays (i.e. old-fashioned strings).
This issue can be fixed by adding 'UniformOutput',false to the arrayfun call:
File_Neg = struct('name',{'-10.000000.dcm','-102.500000.dcm','-100.000000.dcm','-107.500000.dcm','-112.500000.dcm','-110.000000.dcm','-12.500000.dcm'},...
'folder',{'a','b','c','d','e1','e2','e3'});
[~,I] = sort(arrayfun(#(x)x.name,File_Neg,'UniformOutput',false));
File_Neg = File_Neg(I);
File_Neg is now sorted according to dictionary sort (using ASCII letter ordering, meaning that uppercase letters come first, and 110 still comes before 12).
The second issue is that OP wants to sort according to the magnitude of the number in the file name, not using dictionary sort. This can be fixed by extracting the value in the anonymous function applied using arrayfun. We use str2double on the file name, minus the last 4 characters '.dcm':
[~,I] = sort(arrayfun(#(x)abs(str2double(x.name(1:end-4))),File_Neg));
File_Neg = File_Neg(I);
Funnily enough, we don't want to use 'UniformOutput',false any more, since the anonymous function now returns a scalar value.
I create a model using EA Scripting. The model consists of interfaces and each interface has operations. I also add these interfaces in a composition diagram , how can I not show the operations in diagram in EA.
Is it possible by some settings in EA or I need to do it programatically
Thanks
Doing it for single elements manually is simple:
From the context menu in the diagram choose Features/...Visibility
In Operation Visibility click Custom
Choose the operations you need to suppress
Now for the tricky part, if you need to do that for many diagrams at once. The information is stored in t_diagram.StyleEx. This contains a semicolon separated list of entries. One of those entries might look like
SPL=S_E4BB5A=69A30E,2A49EF:;
Now E4BB5A are the first 6 nibbles of the element GUID which is affected. 69A30E and 2A49EF are those of attributes or operations which shall be suppressed. So in order to suppress an operation on all diagrams you need to do the following:
oGuid = operation.methodGuid.substring(1,6) // get "69A30E" from "{69A30E-..."
eGuid = element.elementGuid.substring(1,6) // E4BB5A
sup = "SPL=S_" + eGuid + "=" + oGuid + ":;"
for dia in allDiagramsInRepos { // you need to build that on your own
dia.styleEx += sup
dia.update()
}
Of course you need to merge with existing SPL entries rather than simply adding them. But you should get the idea.
A processor 'a' takes care the header 'a' of a message 'a_b_c_d' and passes the payload 'b_c_d' to the another processor in the next level as following:
msg(a, b_c_d).
pro(a;b;c;d).
msg(b, c_d) :- pro(X), msg(X, b_c_d).
msg(c, d) :- pro(X), msg(X, c_d).
msg(d) :- pro(X), msg(X, d).
#hide. #show msg/2. #show msg/1.
How should I represent list 'a_b_c_d' in ASP, and change the above to general cases?
No, official way, but I think most people don't realize you can construct cons-cells in ASP.
For instance, here's how you can get items for all lists of length 5 from elements 1..6
element(1..6).
listLen(empty, 0).
listLen(cons(E, L), K + 1) :- element(E); listLen(L, K); K < 5.
is5List(L) :- listLen(L, 5).
#show is5List/1.
resulting in
is5List(cons(1,cons(1,cons(1,cons(1,cons(1,empty))))))
is5List(cons(1,cons(1,cons(1,cons(1,cons(2,empty))))))
is5List(cons(1,cons(1,cons(1,cons(1,cons(3,empty))))))
...
There is no 'official' way to handle lists in ASP as far as I know. But, DLV has built-in list handling similar to Prolog's.
The way you implement a list, the list itself cannot be used as a term and thus what if you want to bind between variables in the list and other elements of a rule? Perhaps you would like something such as p(t, [q(X), q(Y)]) :- X != Y.
You can try implementing a list as (a, b, c) and an append predicate but the problem is ASP requires grounding before computing answer-sets. Consequently a list defined in this way whilst more like lists in Prolog would mean the ground-program contains all ground-instances of all possible lists (explosion) regardless of whether they are used or not.
I therefore come back to my first point, try using DLV instead of Clingo if possible (for this task, at least).
By using index, I do have a way to walk a list, however, I do not know this is the official way to handle a list in ASP. Could someone has more experience in ASP give us a hand? Thanks.
index(3,a). index(2,b). index(1,c). index(0,d).
pro(a;b;c;d). msg(3,a).
msg(I-1,N) :- pro(P), msg(I,P), index(I,P), I>0, index(I-1,N).
#hide. #show msg/2.
You can use s(ASP) or s(CASP) ASP systems. Both of them support list operations like prolog. You might need to define the list built-in in ASP .
Some context before the question.
Imagine file FileA having around 50 fields of different types. Instead of all programs using the file, I tried having a service program, so the file could only be accessed by that service program. The programs calling the service would then receive a DataStructure based on the file structure, as an ExtName. I use SQL to recover the information, so, basically, the procedure would go like this :
Datastructure shared by service program :
D FileADS E DS ExtName(FileA) Qualified
Procedure called by programs :
P getFileADS B Export
D PI N
D PI_IDKey 9B 0 Const
D PO_DS LikeDS(FileADS)
D LocalDS E DS ExtName(FileA) Qualified
D NullInd S 5i 0 Array(50) <-- Since 50 fields in fileA
//Code
Clear LocalDS;
Clear PO_DS;
exec sql
SELECT *
INTO :LocalDS :nullind
FROM FileA
WHERE FileA.ID = :PI_IDKey;
If SqlCod <> 0;
Return *Off;
EndIf;
PO_DS = LocalDS;
Return *On;
P getFileADS E
So, that procedure will return a datastructure filled with a record from FileA if it finds it.
Now my question : Is there any way I can assign the %nullind(field) = *On without specifying EACH 50 fields of my file?
Something like a loop
i = 1;
DoW (i <= 50);
if nullind(i) = -1;
%nullind(datastructure.field) = *On;
endif;
i++;
EndDo;
Cause let's face it, it'd be a pain to look each fields of each file every time.
I know a simple chain(n) could do the trick
chain(n) PI_IDKey FileA FileADS;
but I really was looking to do it with SQL.
Thank you for your advices!
OS Version : 7.1
First, you'll be better off in the long run by eliminating SELECT * and supplying a SELECT list of the 50 field names.
Next, consider these two web pages -- Meaningful Names for Null Indicators and Embedded SQL and null indicators. The first shows an example of assigning names to each null indicator to match the associated field names. It's just a matter of declaring a based DS with names, based on the address of your null indicator array. The second points out how a null indicator array can be larger than needed, so future database changes won't affect results. (Bear in mind that the page shows a null array of 1000 elements, and the memory is actually relatively tiny even at that size. You can declare it smaller if you think it's necessary for some reason.)
You're creating a proc that you'll only write once. It's not worth saving the effort of listing the 50 fields. Maybe if you had many programs using this proc and you had to create the list each time it'd be a slight help to use SELECT *, but even then it's not a great idea.
A matching template DS for the 50 data fields can be defined in the /COPY member that will hold the proc prototype. The template DS will be available in any program that brings the proc prototype in. Any program that needs to call the proc can simply specify LIKEDS referencing the template to define its version in memory. The template DS should probably include the QUALIFIED keyword, and programs would then use their own DS names as the qualifying prefix. The null indicator array can be handled similarly.
However, it's not completely clear what your actual question is. You show an example loop and ask if it'll work, but you don't say if you had a problem with it. It's an array, so a loop can be used much like you show. But it depends on what you're actually trying to accomplish with it.
for old school rpg just include the nulls in the data structure populated with the select statement.
select col1, ifnull(col1), col2, ifnull(col2), etc. into :dsfilewithnull where f.id = :id;
for old school rpg that can't handle nulls remove them with the select statement.
select coalesce(col1,0), coalesce(col2,' '), coalesce(col3, :lowdate) into :dsfile where f.id = :id;
The second method would be easier to use in a legacy environment.
pass the key by value to the procedure so you can use it like a built in function.
One answer to your question would be to make the array part of a data structure, and assign *all'0' to the data structure.
dcl-ds nullIndDs;
nullInd Ind Dim(50);
end-ds;
nullIndDs = *all'0';
The answer by jmarkmurphy is an example of assigning all zeros to an array of indicators. For the example that you show in your question, you can do it this way:
D NullInd S 5i 0 dim(50)
/free
NullInd(*) = 1 ;
Nullind(*) = 0 ;
*inlr = *on ;
return ;
/end-free
That's a complete program that you can compile and test. Run it in debug and stop at the first statement. Display NullInd to see the initial value of its elements. Step through the first statement and display it again to see how the elements changed. Step through the next statement to see how things changed again.
As for "how to do it in SQL", that part doesn't make sense. SQL sets the values automatically when you FETCH a row. Other than that, the array is used by the host language (RPG in this case) to communicate values back to SQL. When a SQL statement runs, it again automatically uses whatever values were set. So, it either is used automatically by SQL for input or output, or is set by your host language statements. There is nothing useful that you can do 'in SQL' with that array.