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.
Related
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
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...
I'm using grails with pdfbox plugin. I'd like to print checkboxes in pdf some are checked and some are not.
To print checkbox I did not a direct way(Even by using PDCheckbox class). So I've used the other way to print the checkbox with tick mark using the below code:
public static writeInputFieldToPDFPage( PDPage pdPage, PDDocument document, Float x, Float y, Boolean ticked) {
PDFont font = PDType1Font.HELVETICA
PDResources res = new PDResources()
String fontName = res.addFont(font)
String da = ticked?"/" + fontName + " 10 Tf 0 0.4 0 rg":""
COSDictionary acroFormDict = new COSDictionary()
acroFormDict.setBoolean(COSName.getPDFName("NeedAppearances"), true)
acroFormDict.setItem(COSName.FIELDS, new COSArray())
acroFormDict.setItem(COSName.DA, new COSString(da))
PDAcroForm acroForm = new PDAcroForm(document, acroFormDict)
acroForm.setDefaultResources(res)
document.getDocumentCatalog().setAcroForm(acroForm)
PDGamma colourBlack = new PDGamma()
PDAppearanceCharacteristicsDictionary fieldAppearance =
new PDAppearanceCharacteristicsDictionary(new COSDictionary())
fieldAppearance.setBorderColour(colourBlack)
if(ticked) {
COSArray arr = new COSArray()
arr.add(new COSFloat(0.89f))
arr.add(new COSFloat(0.937f))
arr.add(new COSFloat(1f))
fieldAppearance.setBackground(new PDGamma(arr))
}
COSDictionary cosDict = new COSDictionary()
COSArray rect = new COSArray()
rect.add(new COSFloat(x))
rect.add(new COSFloat(new Float(y-5)))
rect.add(new COSFloat(new Float(x+10)))
rect.add(new COSFloat(new Float(y+5)))
cosDict.setItem(COSName.RECT, rect)
cosDict.setItem(COSName.FT, COSName.getPDFName("Btn")) // Field Type
cosDict.setItem(COSName.TYPE, COSName.ANNOT)
cosDict.setItem(COSName.SUBTYPE, COSName.getPDFName("Widget"))
if(ticked) {
cosDict.setItem(COSName.TU, new COSString("Checkbox with PDFBox"))
}
cosDict.setItem(COSName.T, new COSString("Chk"))
//Tick mark color and size of the mark
cosDict.setItem(COSName.DA, new COSString(ticked?"/F0 10 Tf 0 0.4 0 rg":"/FF 1 Tf 0 0 g"))
cosDict.setInt(COSName.F, 4)
PDCheckbox checkbox = new PDCheckbox(acroForm, cosDict)
checkbox.setFieldFlags(PDCheckbox.FLAG_READ_ONLY)
checkbox.setValue("Yes")
checkbox.getWidget().setAppearanceCharacteristics(fieldAppearance)
pdPage.getAnnotations().add(checkbox.getWidget())
acroForm.getFields().add(checkbox)
}
This code is working fine in my application, this method is adding checkboxes with tick marks also.
But I can see those rectangle checkboxes or tick marks in only pdf readers, not in all other readers(Like chrome default pdf viewer), and even when I try to print the pdf its not printing the checkboxes, rather its printing some random ASCII numbers.
Please let me know if there is any other way to do this or even if I have to refactor the code.
What is wrong
Your AcroForm checkbox field construction is wrong: You treat it as a text field for which a PDF reader should create an appearance based on the default appearance (DA) value of the field in particular if NeedAppearances is true.
Checkboxes are different, though: you do have to supply an appearance stream at least for the on state, cf. the specification ISO 32000-1:
A check box field represents one or more check boxes that toggle between two states, on and off, when manipulated by the user with the mouse or keyboard. Its field type shall be Btn and its Pushbutton and Radio flags (see Table 226) shall both be clear. Each state can have a separate appearance, which shall be defined by an appearance stream in the appearance dictionary of the field’s widget annotation (see 12.5.5, “Appearance Streams”). The appearance for the off state is optional but, if present, shall be stored in the appearance dictionary under the name Off. Yes should be used as the name for the on state.
(ISO 32000-1 section 12.7.4.2.3 "Check Boxes")
Thus, instead of constructing a DA entry you have to construct an AP ("appearances") entry, itself a dictionary with at least a N ("normal appearances") entry, itself a dictionary with at least an entry for the on state appearance which is recommended to be called Yes.
The specification provides an example which shows a typical check box definition:
1 0 obj
<< /FT /Btn
/T (Urgent)
/V /Yes
/AS /Yes
/AP << /N << /Yes 2 0 R /Off 3 0 R>>
>>
endobj
2 0 obj
<< /Resources 20 0 R
/Length 104
>>
stream
q
0 0 1 rg
BT
/ZaDb 12 Tf
0 0 Td
(4) Tj
ET
Q
endstream
endobj
3 0 obj
<< /Resources 20 0 R
/Length 104
>>
stream
q
0 0 1 rg
BT
/ZaDb 12 Tf
0 0 Td
(8) Tj
ET
Q
endstream
endobj
(The resources in 20 0 obj appear to include a font resource named ZaDb referencing ZapfDingbats.)
By the way, you mention that there is a PDF viewer which actually displays a tick for your document as is. You might want to inform their development that they are doing the wrong thing there.
An example
In a comment you asked for sample code and indicated that it was ok if it were for a current 2.0.x version of PDFBox. So I tried it and came up with this code:
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDAcroForm acroForm = new PDAcroForm(document);
document.getDocumentCatalog().setAcroForm(acroForm);
COSDictionary normalAppearances = new COSDictionary();
PDAppearanceDictionary pdAppearanceDictionary = new PDAppearanceDictionary();
pdAppearanceDictionary.setNormalAppearance(new PDAppearanceEntry(normalAppearances));
pdAppearanceDictionary.setDownAppearance(new PDAppearanceEntry(normalAppearances));
PDAppearanceStream pdAppearanceStream = new PDAppearanceStream(document);
pdAppearanceStream.setResources(new PDResources());
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(document, pdAppearanceStream))
{
pdPageContentStream.setFont(PDType1Font.ZAPF_DINGBATS, 14.5f);
pdPageContentStream.beginText();
pdPageContentStream.newLineAtOffset(3, 4);
pdPageContentStream.showText("\u2714");
pdPageContentStream.endText();
}
pdAppearanceStream.setBBox(new PDRectangle(18, 18));
normalAppearances.setItem("Yes", pdAppearanceStream);
pdAppearanceStream = new PDAppearanceStream(document);
pdAppearanceStream.setResources(new PDResources());
try (PDPageContentStream pdPageContentStream = new PDPageContentStream(document, pdAppearanceStream))
{
pdPageContentStream.setFont(PDType1Font.ZAPF_DINGBATS, 14.5f);
pdPageContentStream.beginText();
pdPageContentStream.newLineAtOffset(3, 4);
pdPageContentStream.showText("\u2718");
pdPageContentStream.endText();
}
pdAppearanceStream.setBBox(new PDRectangle(18, 18));
normalAppearances.setItem("Off", pdAppearanceStream);
PDCheckBox checkBox = new PDCheckBox(acroForm);
acroForm.getFields().add(checkBox);
checkBox.setPartialName("CheckBoxField");
checkBox.setFieldFlags(4);
List<PDAnnotationWidget> widgets = checkBox.getWidgets();
for (PDAnnotationWidget pdAnnotationWidget : widgets)
{
pdAnnotationWidget.setRectangle(new PDRectangle(50, 750, 18, 18));
pdAnnotationWidget.setPage(page);
page.getAnnotations().add(pdAnnotationWidget);
pdAnnotationWidget.setAppearance(pdAppearanceDictionary);
}
// checkBox.setReadOnly(true);
checkBox.check();
// checkBox.unCheck();
document.save(new File(RESULT_FOLDER, "CheckBox.pdf"));
document.close();
(CreateCheckBox test testCheckboxForSureshGoud)
Be sure to use either
checkBox.check();
or
checkBox.unCheck();
as otherwise the state of the box is undefined.
#mkl has a good answer, but I think it can be simplified a little bit in case you already have a Document and just want to add a PDCheckbox (scala):
def addCheckboxField(
doc: PDDocument,
form: PDAcroForm,
name: String,
pg: Int, // page number
x: Float,
y: Float,
width: Float,
height: Float
) = {
val normalAppearances = new COSDictionary()
normalAppearances.setItem(
"Yes", {
val appearanceStream = new PDAppearanceStream(doc)
appearanceStream.setResources(new PDResources())
appearanceStream
}
)
val appearanceDictionary = new PDAppearanceDictionary()
appearanceDictionary.setNormalAppearance(new PDAppearanceEntry(normalAppearances))
appearanceDictionary.setDownAppearance(new PDAppearanceEntry(normalAppearances))
val field = new PDCheckBox(form)
field.setPartialName(name)
val widget = field.getWidgets.get(0)
widget.setAppearance(appearanceDictionary)
form.getFields.add(field)
val page = doc.getPage(pg)
widget.setRectangle(new PDRectangle(x, y, width, height))
widget.setPage(page)
widget.setPrinted(true)
page.getAnnotations().add(widget)
// do what you want with it
field.unCheck()
}
It's likely there are other simplifications that can be made, but this is what worked for me.
PdfBox version: 2.0.21
In the following code I create 3 boxes with the text 1 to 3, in a fourth box I'd like to show the text of the box my mouse is hovering over. So i set an onMouseEnter FProperty for each of the boxes where I change the string of the fourth box and tell it to redraw.
bool redraw = false;
str s = "0";
Figure getTextbox() {
return computeFigure(bool() {bool temp = redraw; redraw = false; return temp; },
Figure() {
return text(str() {return s; });
});
}
list[Figure] boxes = [];
for (i <- [1..4]) {
boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}
Figure changer = box(getTextbox());
render(vcat(boxes + changer));
However, for some odd reason all three boxes will tell the onMouseEnter method to change the text of the fourth box into "3" (the value of the last box) instead of their individual value.
Any clue why? Thanks!
Ah yes, this is the variable capturing closure problem with for loops, also known from other languages which have this particular feature like Javascript. This is the code with the issue:
for (i <- [1..4]) {
boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}
The variable i is bound by the void closure and not its value. So every time the function which is created and passed to onMouseEnter it will read the latest value of the i variable. Since the callback is called after the loop terminates, all calls to the mouse enter function will have the value 3.
To fix this and "do what you want", the following code would work I believe:
for (i <- [1..4]) {
newS = toString(i);
boxes += box(text(toString(i)), onMouseEnter(void () {s = newS; redraw = true; }));
}
This works because for every pass of the for loop a new environment is created which binds the newS variable. So you'll get a fresh newS for every loop instead of the reused i.
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