Is there a way to view the last modified date of the the Object Text in DOORS? - ibm-doors

I'm new to using DOORS and am trying to create a column/attribute that has the date of the last modification to the Object Text. I found the below code which uses "Last Modified On", but that that includes all attributes and I'm only concerned about the Object Text. Maybe there's a way to specifiy an attribute for this?
Date dMod
dMod = obj."Last Modified On"
dMod = dateAndTime(dMod)
display dMod ""

There's no such attribute on an attribute.
The only way to determine this is via the object's history. Below is the example script from DXL manual. The idea is to loop through the object's history until the history record's typeis modifyObjectand it's attrName equals 'Object Text'. Keep in mind, though, that the history in a module only goes back to the last baseline. So, you may have to browse through all baselines to find the history record you need. See Tony's "Smart History Viewer" at http://www.smartdxl.com/content/?page_id=125 for details.
// history DXL Example
/*
Example history DXL program.
Generate a report of the current Module's
history.
*/
// print a brief report of the history record
void print(History h) {
HistoryType ht = h.type
print h.author "\t" h.date "\t" ht "\t"
if (ht == createType ||
ht == modifyType ||
ht == deleteType) { // attribute type
print h.typeName
} else if (ht == createAttr ||
ht == modifyAttr ||
ht == deleteAttr) {
// attribute definition
print h.attrName
} else if (ht == createObject ||
ht == clipCopyObject ||
ht == modifyObject) { // object
print h.absNo
if (ht==modifyObject) {
// means an attribute has changed
string oldV = h.oldValue
string newV = h.newValue
print " (" h.attrName ":" oldV " -> " newV ")"
}
}
print "\n"
}
// Main program
History h
print "All history\n\n"
for h in current Module do print h
print "\nHistory for current Object\n\n"
for h in current Object do print h
print "\nNon object history\n\n"
for h in top current Module do print h

Related

How to get object and lower hierarchical objects from a DXL

I'm new on DXL and working on something that is probably quite simple.
I would like to parse the current module, and get the following data for each object that has a given ID (calling IDNUM below) not empty:
IDNUM - Object text - all text with a lower hierarchic level and the same thing for all objects liked to this one.
It will probably be easier to understand with the code. So far, it looks like that:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
Basically, I have the ID and title of both an object and the one liked to it, but not the text below. In other words, my code will "mimic" the function right click>copy>copy with hierarchy
How can I do that? Unfortunately I didn't find anything very helpful.
Thanks a lot in advance,
Here is the sketch code you outlined:
Object o
Object ol
Link l
Module m = current Module
For o in entire(m) do{
if (o."IDNUM" != ""){
print o."IDNUM" ""
print o."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN o
for l in o --> "*" do{
ol = target(l)
print ol."text" ""
//HERE I WOULD LIKE TO ALSO PRINT EVERY TEXT IN OBJECT "LOWER" THAN ol
}
}
}
There are a few little syntax things that need to be changed here, but the big change is how you are handling linked items. Links 'live' in the source module, but they only store a limited amount of information, mostly the modules that are the source and target of the link, and the absolute numbers of the objects they touch. So you need to check if the module on the other side is open before you try and read text from it.
And since you are trying to go through the entire link structure, you'll need a recursive element to this.
I would probably end up with something like this:
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
//Iterate down structure
link_print ( next_obj )
}
} else {
//Iterate down structure
link_print ( next_obj )
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Note! Depending on the size of your link structure, i.e. how many levels you have (and if there are any circular link patterns), this could be a pretty resource intensive task, and would be better solved using something other than "print" commands (like appending it to a word file, for example, so you know how far it got before it errored out)
Good luck!
EDIT:
Rather than head down recursively, this script will now go a single level but should report child objects.
//turn off run limit timer- this might take a bit
pragma runLim , 0
Object o
Module m = current Module
// Recursive function- assumes each object has a text attribute- will error otherwise
void link_print(Object obj) {
print obj."text" "\n"
Link out_link
Object next_obj = null
Object child_obj = null
for out_link in obj -> "*" do {
// Set the next object in the chain
next_obj = target ( out_link )
// This might return null if the module is not loaded
if ( null next_obj ) {
// Load the module in read-only mode, displayed and in standard view
read ( fullName ( ModName_ target ( out_link ) ) , true , true )
// Try and resolve out 'target' again
next_obj = target ( out_link )
// If it doesn't work, print a message so we can figure it out
if ( null next_obj ) {
print "Error Accessing Object " ( targetAbsNo ( out_link ) )""
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
} else {
// Loop and report on child objects
for child_obj in next_obj do {
print child_obj."text" "\n"
}
}
}
}
for o in entire(m) do {
// Note that I cast the result of o."IDNUM" to a string type by appending ""
if (o."IDNUM" "" != ""){
print o."IDNUM" "\n"
// Recurse
link_print(o)
print "\n"
}
}
Dear Russell (and everyone else)
I've just went through the piece of code you provided me and it works.... but not for what I'm looking for. It seems my explanation wasn't very clear. I'm sorry (I'm not a native speaker).
I'm not looking to get all links, but just the Object text that is written just below the object pointed by the current link.
Here is what my files look like
object1 (with IDNUM) : "Title_doc_1" --> (link) objectA "Title_doc_2"
object2 : "some_text" objectB : "some_text"
object3 : "some_text" objectC : "some_text"
(object1 can point to many other objectA but I already deal with that.)
The code I provided above parses the "doc_1", and print "IDNUM" "Title_doc_1" "Title_doc_2"
What I'm looking for is to get, not only objectA but also objectB and objectC which are hierarchically below objectA (and object2 and object3 too but it will ve the same process).
Hopping I made myself understood...

dxl script to paste the clipboard contents in selected objects

I want to add clipboard contents in existing Object Text using dxl script.
I searched around, including dxl_reference_manual but nothing helped.
The object in selection has some text for example "Already existing text in this object" and clipboard contents for example "My Clipboard text" should add at the beginning and form as a single object.
(Output should be something like below in a single object.)
My Clipboard text
Already existing text in this object
My code:
Skip fGetSelectedObjects(Module in_mod)
{
Skip skpObjects = create() // Return KEY and DATA both 'Object'
if (null in_mod) return(skpObjects)
Object oCurr = current,
o
for o in entire (in_mod) do
{ if (isSelected(o) or
o == oCurr) put(skpObjects, o, o)
}
return(skpObjects)
} // end fGetSelectedObjects()
Skip skpObjects = fGetSelectedObjects(current Module)
Object o
for o in skpObjects do
{ // deal with the selected o
string s = o."Object text"
// I don't know the way to activate the object text attribute instead of manual click. Thus it loops through selection and pastes the clipboard contents.
pasteToEditbox
//For Single Indentation use 360 points, double indentation 720 points and so on...
o."Object text" = richText (applyTextFormattingToParagraph(richText s,false,360,0))
}
delete(skpObjects)
Not sure why you would be using a Skip for this. I would look to do the following:
// Create Variables
Module mod = current
Object obj = null
Buffer buf = create
string str = stringOf ( richClip )
// Loop through Module
for obj in entire ( mod ) do {
// Grab the rich text from the clip and reset the buffer
buf = str
// Check if it's selected and object heading is empty
if ( ( isSelected ( obj ) ) && ( obj."Object Heading" "" == "" ) ) {
// If it is, add the text to the buffer
buf += " " richText ( obj."Object Text" )
// Set the object text with the clip stuff in front
obj."Object Text" = richText ( buf )
}
}
delete buf
Of note, this only works on items that have been specifically selected.
Edit- added exclusion for objects with an Object Heading. Unfortunately, DOORS does not (as far as I know) allow for non-contiguous object selection (the equivalent of ctrl-left click in Windows) which can be very frustrating.

DOORS Layout DXL is reporting each link twice

I'm using the Analysis Wizard to create a LayoutDXL column which should list attributes (e.g. AbsoluteNumber) for each existing In-link in my current module. In one particular DOORS module, the resulting DXL code displays each of these attributes twice. This doesn't happen in other modules.
I did notice that the offending module doesn't have a defined set of LinkModules (as seen in File/ModuleProperties). Could that be causing some sort of loopback?
Update:
I've discovered that somehow the DXL code "thinks" there are two versions of a defined LinkModule, i.e. "Current" and "Baseline X" . These each link to different baseline numbers in the target DOORS module. I don't know how to fix that.
For reference, here's the DXL code generated with the Wizard. This is DOORS 9.6.1.11
// DXL generated by DOORS traceability wizard on 12 February 2019.
// Wizard version 2.0, DOORS version 9.6.1.11
pragma runLim, 0
string limitModules[1] = {"[serial number redacted]"}
void showIn(Object o, int depth) {
Link l
LinkRef lr
ModName_ otherMod = null
Module linkMod = null
ModuleVersion otherVersion = null
Object othero
string disp = null
string s = null
string plain, plainDisp
int plainTextLen
int count
bool doneOne = false
string linkModName = "*"
for lr in all(o<-linkModName) do {
otherMod = module (sourceVersion lr)
if (!null otherMod) {
if ((!isDeleted otherMod) && (null data(sourceVersion lr))) {
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
load((sourceVersion lr),false)
}
}
}
for l in all(o<-linkModName) do {
otherVersion = sourceVersion l
otherMod = module(otherVersion)
if (null otherMod || isDeleted otherMod) continue
if (!equal(getItem otherMod, (itemFromID limitModules[depth-1]))) continue
othero = source l
if (null othero) {
load(otherVersion,false)
}
othero = source l
if (null othero) continue
if (isDeleted othero) continue
doneOne = true
if (depth == 1) {
s = probeRichAttr_(othero,"Absolute Number", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
s = probeRichAttr_(othero,"Object Heading", false)
if (s == "")
displayRich("\\pard " " ")
else
displayRich("\\pard " s)
}
}
}
showIn(obj,1)
I've seen the situation where objects DID have two links between them, this is possible with different link modules (Object 1 of Module A SATISFIES Object 2 of Module B and Object 1 of Module A REFINES Object 2 of Module B). While there may be reasons for such a situation, most often this is caused by a "link move" script that was not used correctly.
You should augment your code by displaying the name of the link module as well (variable linkModName). Perhaps this shows the reason for your observation

How to control the Index in a for statement in DXL

For some reason the DXL interpreter does not take into account the fact that I am decrementing i at the end of the for loop. I am trying to navigate through the arrObj[] array by changing the value of "i". I have some buttons that increment(for next object) and decrement(for previous object) the value respectively. Doing the same thing with a while loop crashes the application.
Is there any way to control the index or will DXL always remember the previous value and increment it (even if the user changes it's value within the code).
Here's a snippet from my code:
for i in 0:(iTotalObj-1) do
{
sAuxType = arrObj[i]."ObjectType"
sAuxNr = number(arrObj[i]) " "
sAuxObjTxt = arrObj[i]."Object Text"
print "\nAfter FOR:"i ""
if sAuxType == "Test-Case" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Heading" "")
set(expectedResults, " ")
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
}
if sAuxType == "Test-Step" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Text" "")
set(expectedResults,richTextWithOle(arrObj[i]."ExpectedResult"))
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
}
if sAuxType == "Test-Case-Description" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Text" "")
set(expectedResults, "Please check the description throroughly")
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
arrObj[i].("TestResult " iTR "") = "n/a"
arrObj[i].("FR " iTR "") = "n/a"
}
i--
print "\nAfter DECREMENT:"i ""
}
On the output box I'll get the following:
After FOR:0
After DECREMENT:-1
After FOR:1
After DECREMENT:0
After FOR:2
After DECREMENT:1
With that type of for loop I believe DOORS is forcing i to the next value in the set. You should be able to use this type of loop instead:
for(i=0; i<(iTotalObj-1); i++) {
...
}
This loop will allow you to manipulate i inside the loop.

IBM DOORS Copy text from column

I'm new to DOORS and DXL scripting (not sure if it'll be needed here or not). What I'm looking to do is create a new column in two separate modules that will copy the Absolute Numbers. I know this sounds simple enough, but what I'm running into an issue with is that I use a tool to convert my modules into a PDF and it combines them into one module before doing so. Doing this messes up the Absolute Numbers and I can't afford to have that happen.
More descriptive:
I have a column that contains the following:
'REQ01: 4' where 'REQ01:' represents the module and '4' represents the Absolute Number. Similarly, I have 'REQ02: 4'. I need to copy those in their respective modules and make sure they don't change after the modules have been combined.
I've tried my hand at some DXL scripting and this is what I came up with:
displayRich("REQ01: " obj."Absolute Number" "")
This appropriately shows the column, but again will not work as the Absolute Number ends up changing when I merge the modules.
Thanks in advanced for your help and I apologize if I left any crucial information out.
Here is the code that ultimately worked for me.
// DXL generated on 11 June 2014 by Attribute DXL wizard, Version 1.0
// The wizard will use the following comments on subsequent runs
// to determine the selected options and attributes. It will not
// take account of any manual changes in the body of the DXL code.
// begin parameters (do not edit)
// One attribute/property per line: true
// Show attribute/property names: false
// Include OLE objects in text: true
// Attribute: Object Text
// end parameters (do not edit)
Module m
AttrDef ad
AttrType at
m = module obj
ad = find(m,attrDXLName)
if(!null ad && ad.object)
{
at = ad.type
if(at.type == attrText)
{
string s
Buffer val = create
Buffer temp = create
ad = find(m,"Object Text")
if(!null ad)
{
probeRichAttr_(obj,"Object Identifier", temp, true)
val += tempStringOf temp
}
obj.attrDXLName = richText (tempStringOf val)
delete val
delete temp
}
}
There's a builtin "Copy Attributes" script which does this. At least in the version installed at my company, it's in the PSToolbox, and also available in the menu PSToolbox/attributes/copy.../betweenattributes... Here you go:
// Copy values from one attribute to another
/*
*/
/*
PSToolbox Tools for customizing DOORS with DXL V7.1
-------------------------------------------------
DISCLAIMER:
This programming tool has been thoroughly checked
and tested at all stages of its production.
Telelogic cannot accept any responsibility for
any loss, disruption or damage to your data or
your computer system that may occur while using
this script.
If you do not accept these conditions, do not use
this customised script.
-------------------------------------------------
*/
if ( !confirm "This script copies values from one attribute to another in the same module.\n" //-
"Use this to assist in changing the types of attributes.\n\n" //-
"It asks you to select the source and destination attributes.\n\n" //-
"It works by ... well, copying attribute values!\n\n" //-
"Continue?"
)
{
halt
}
#include <addins/PSToolbox/utensils/dbs.inc>
const int MAXATTRS = 1000
DB copyAttrValsDB = null
DBE copyAttrValsFrom = null
DBE copyAttrValsTo = null
DBE copyAttrValsConfirm = null
DBE copyAttrValsButt = null
string attrListFrom[MAXATTRS]
string attrListTo[MAXATTRS]
string confirmOpts[] = { "Yes", "Yes to all", "No", "No to all", "Cancel" }
bool confirmDataLoss = true
bool noToDataLoss = false
///////////////////////////////////////////////////////////
// Call-backs
void doAttrValsCopy(DB db) {
// check attributes
string fromAn = attrListFrom[get copyAttrValsFrom]
string toAn = attrListTo [get copyAttrValsTo ]
if ( fromAn == toAn ) {
ack "Cannot copy attribute to itself."
return
}
// get confirmation
if ( !confirm "Confirm copy of attribute '" fromAn "' to attribute '" toAn "'." ) {
return
}
confirmDataLoss = get copyAttrValsConfirm
// do copy
Object o
for o in current Module do
{
Buffer oldVal = create()
Buffer newVal = create()
if ( fromAn == "Object Identifier" ) newVal = identifier(o)
else if ( fromAn == "Object Level" ) newVal = level(o) ""
else if ( fromAn == "Object Number" ) newVal = number(o)
else newVal = richText o.fromAn
oldVal = richText o.toAn
if ( confirmDataLoss && !noToDataLoss && length(oldVal) > 0 && oldVal != newVal )
{
current = o
refresh current
int opt = query("About to lose attribute '" toAn "' = '" stringOf(oldVal) "' on current object.", confirmOpts)
if ( opt == 1 ) confirmDataLoss = false
if ( opt == 2 ) continue
if ( opt == 3 ) noToDataLoss = true
if ( opt == 4 ) return
}
if ( !confirmDataLoss || !noToDataLoss || length(oldVal) == 0 ) o.toAn = richText stringOf(newVal)
delete(oldVal)
delete(newVal)
}
hide copyAttrValsDB
}
///////////////////////////////////////////////////////////
// Main program
int numAttrsFrom = 0
int numAttrsTo = 0
AttrDef ad
for ad in current Module do {
if ( ad.module ) continue
string an = ad.name
if ( canRead (current Module, an) ) attrListFrom[numAttrsFrom++] = an
if ( canWrite(current Module, an) ) attrListTo [numAttrsTo++ ] = an
}
attrListFrom[numAttrsFrom++] = "Object Identifier"
attrListFrom[numAttrsFrom++] = "Object Level"
attrListFrom[numAttrsFrom++] = "Object Number"
copyAttrValsDB = create "Copy attribute values"
copyAttrValsFrom = choice(copyAttrValsDB, "From:", attrListFrom, numAttrsFrom, 0)
copyAttrValsTo = choice(copyAttrValsDB, "To:", attrListTo, numAttrsTo, 0)
copyAttrValsButt = apply (copyAttrValsDB, "Copy", doAttrValsCopy)
copyAttrValsConfirm = toggle(copyAttrValsDB, "Confirm on loss of data", true)
show copyAttrValsDB

Resources