// Smart Baseline Comparison
/*
The values for each selected attribute are compared and included in the report if they
differ. The export contains a row for each attribute change made between the selected
baselines. Attributes that do not exist in the older baseline are identified at the top of
the report. New and deleted objects are identified in the right-hand column.
Inclusion of tables cells is optional.
New and deleted cells objcts are identified, but deleted rows are not.
Change History
-----------------
24-MAY-2011 Tony Goodman Standalone version.
07-NOV-2012 Tony Goodman Ensure that filtering and sorting are turned off.
18-AUG-2015 Tony Goodman Added toggle to turn Redline Markup on/off
*/
pragma runLim, 0
/***********************************
SITE SPECIFIC CONFIGURATION
***********************************/
string OUTPUT_FOLDER = "U:\\"
// location of browser or other program used to display the html report
string INTERNET_EXPLORER = "C:\\Program Files\\Internet Explorer\\iexplore.exe"
// Attribute to display in addition to the obejct identifier
string REQ_ATTR = "Req ID"
string EXTRA_ATTR = ""
bool includeExtraAttr = false
Buffer textBuf2 = create
Buffer tempBuf = create
Buffer bSource = create
Buffer bTarget = create
Buffer bResult = create
bool showMarkup = false
/******************************************************************************
getRedLineMarkup
******************************************************************************/
void getRedLineMarkup()
{
setempty(bResult)
diff(bResult, bSource, bTarget)
}
/******************************************************************************
emitHeader
******************************************************************************/
void emitHeader(Stream out)
{
out << "\n"
out << "\n"
out << "
\n"
out << "\n"
out << "\n"
out << "\n"
}
/******************************************************************************
emitFooter
******************************************************************************/
void emitFooter(Stream out)
{
out << "\n"
out << "\n"
out << "\n"
}
/******************************************************************************
convertRichText
******************************************************************************/
void convertRichText(Buffer& b, string s)
{
RichTextParagraph rp = null
RichText rt = null
bool limitText = false
int ind = 0
int i = 0
setempty(b)
for rp in s do
{
ind = rp.indentLevel
for (i = 0; i < ind; i += 360) b += ""
if (rp.isBullet) b += "- "
for rt in rp do
{
setempty(textBuf2)
textBuf2 += rt.text
safeHTMLBuffer(textBuf2, true, true)
if (rt.bold) b += ""
if (rt.underline)
{
b += ""
b += ""
}
if (rt.italic) b += ""
if (rt.strikethru)
{
b += ""
b += "
"
}
if (rt.superscript) b += ""
if (rt.subscript) b += ""
if (rt.charset == charsetSymbol) b += ""
b += textBuf2
if (rt.charset == charsetSymbol) b += ""
if (rt.subscript) b += ""
if (rt.superscript) b += ""
if (rt.strikethru)
{
b += ""
b += ""
}
if (rt.italic) b += ""
if (rt.underline)
{
b += ""
b += ""
}
if (rt.bold) b += ""
if (rt.newline) b += "
"
}
if (rp.isBullet) b += " "
for (i = 0; i < ind; i += 360) b += "
"
}
}
/******************************************************************************
emitFileHeader
******************************************************************************/
void emitFileHeader(Stream out, string moduleName, Skip newAttributes, bool newAttrs)
{
string attr = ""
out << "\n"
// header row
out << "\n"
out << "\n"
out << "Baseline Comparison Report"
out << "Module: " moduleName " "
out << "Exported from DOORS on: " stringOf(today) " "
out << " | \n"
out << "
\n"
if (newAttrs)
{
out << "\n"
out << "\n"
out << "The following attributes are new since the older baseline, so have not been compared: "
for attr in newAttributes do
{
out << attr " "
}
out << " | \n"
out << "
\n"
}
out << "
\n"
}
/******************************************************************************
emitTableHeader
******************************************************************************/
void emitTableHeader(Stream out, string ver1, string ver2)
{
out << "\n"
out << "" "Object ID" " | \n"
out << "" REQ_ATTR " | \n"
out << "" "Change" " | \n"
out << "" ver1 " | \n"
out << "" ver2 " | \n"
if (includeExtraAttr)
{
out << "" EXTRA_ATTR " | \n"
}
out << "
\n"
}
string reqID(Object o)
{
string s = probeAttr_(o, REQ_ATTR)
if (s == "")
{
return("
")
}
return(s)
}
/******************************************************************************
emitNewObject
******************************************************************************/
void emitNewObject(Stream out, Object o)
{
// new object
out << "\n"
out << "" identifier(o) " | \n"
out << "" reqID(o) " | \n"
out << "NEW OBJECT | \n"
out << "
| "
out << ""
if (o."Object Heading" "" != "")
{
out << ""
out << ""
out << "" number(o) " " o."Object Heading" " "
out << ""
out << ""
}
convertRichText(tempBuf, probeRichAttr_(o, "Object Text"))
out << ""
out << ""
out << tempBuf
if (o."Object Heading" "" == "" && o."Object Text" "" == "")
{
out << " "
}
out << ""
out << ""
out << " | \n"
if (includeExtraAttr)
{
out << "" probeAttr_(o, EXTRA_ATTR) " | \n"
}
out << "
\n"
}
/******************************************************************************
emitDeletedObject
******************************************************************************/
void emitDeletedObject(Stream out, Object o)
{
out << "\n"
out << "" identifier(o) " | \n"
out << "" reqID(o) " | \n"
out << "OBJECT DELETED | \n"
out << ""
if (o."Object Heading" "" != "")
{
out << "" number(o) " " o."Object Heading" " "
}
convertRichText(tempBuf, probeRichAttr_(o, "Object Text"))
out << tempBuf
if (o."Object Heading" "" == "" && o."Object Text" "" == "")
{
out << " "
}
out << " | \n"
out << "
| "
if (includeExtraAttr)
{
out << "" probeAttr_(o, EXTRA_ATTR) " | \n"
}
out << "
\n"
}
/******************************************************************************
emitChangedObject
******************************************************************************/
void emitChangedObject(Stream out, Object o1, Object o2, string attr)
{
out << "\n"
out << "" identifier(o2) " | \n"
out << "" reqID(o2) " | \n"
out << "Attribute "" attr "" Changed | "
out << ""
if (o1.attr "" == "")
{
out << " "
}
else
{
convertRichText(tempBuf, probeRichAttr_(o1, attr))
out << tempBuf
}
out << " | \n"
out << ""
if (o2.attr "" == "")
{
out << " "
}
else
{
if (showMarkup)
{
setempty(bSource)
setempty(bTarget)
bSource += o1.attr ""
bTarget += o2.attr ""
getRedLineMarkup()
convertRichText(tempBuf, stringOf(bResult))
//convertRichText(tempBuf, probeRichAttr_(o2, attr))
out << tempBuf
}
else
{
out << o2.attr ""
}
}
out << " | \n"
if (includeExtraAttr)
{
out << "" probeAttr_(o2, EXTRA_ATTR) " | \n"
}
out << "
\n"
}
/******************************************************************************
compareTableCells
******************************************************************************/
void compareTableCells(Stream out, Module bm1, Skip selectedAttributes, Object oTable)
{
int absno = 0
Object oRow = null
Object o2 = null
Object o1 = null
string attr = ""
for oRow in table(oTable) do
{
if (isDeleted oRow) continue
for o2 in row(oRow) do
{
if (isDeleted o2) continue
absno = o2."Absolute Number"
o1 = object(absno, bm1)
if (null o1)
{
emitNewObject(out, o2)
continue
}
for attr in selectedAttributes do
{
if (o1.attr "" == o2.attr "") continue
emitChangedObject(out, o1, o2, attr)
}
}
}
}
/******************************************************************************
checkDeletedCells
******************************************************************************/
void checkDeletedCells(Stream out, Module bm2, Object oTable)
{
int absno = 0
Object oRow = null
Object o2 = null
Object o1 = null
for oRow in table(oTable) do
{
if (isDeleted oRow) continue
for o1 in row(oRow) do
{
if (isDeleted o1) continue
absno = o1."Absolute Number"
o2 = object(absno, bm2)
if (null o2)
{
emitDeletedObject(out, o1)
continue
}
}
}
}
/******************************************************************************
exportChangeReport
******************************************************************************/
string exportChangeReport(Module m, Baseline b1, Baseline b2, Skip selectedAttributes, bool includeTableCells, string outputFile)
{
string res = ""
Module bm1 = null
Module bm2 = null
Object o1 = null
Object o2 = null
int absno = 0
string s = ""
AttrDef ad = null
string ver1 = ""
string ver2 = ""
string attr = ""
bool newAttrs = false
Skip newAttributes = createString
out = write(outputFile)
if (null out)
{
return("failed to open file for writing: " outputFile "")
}
if (null b1)
{
bm1 = m
ver1 = "Current Version"
}
else
{
bm1 = load(m, b1, true)
ver1 = "Baseline " (major b1) "." (minor b1) (suffix b1 "" != "" ? " (" (suffix b1) ")" : "")
}
if (null bm1)
{
return(ver1 " not found for module")
}
filtering off
sorting off
if (null b2)
{
bm2 = m
ver2 = "Current Version"
}
else
{
bm2 = load(m, b2, true)
ver2 = "Baseline " (major b2) "." (minor b2) (suffix b2 "" != "" ? " (" (suffix b2) ")" : "")
}
if (null bm2)
{
return(ver2 " not found for module.")
}
filtering off
sorting off
// check for attributes that do not exist in the first baseline
for attr in selectedAttributes do
{
ad = find(bm1, attr)
if (null ad)
{
put(newAttributes, attr, attr)
newAttrs = true
}
}
for attr in newAttributes do
{
if (find(selectedAttributes, attr))
{
delete(selectedAttributes, attr)
}
}
emitHeader(out)
emitFileHeader(out, fullName(m), newAttributes, newAttrs)
out << "\n"
emitTableHeader(out, ver1, ver2)
for o2 in document(bm2) do
{
if (isDeleted(o2))
{
continue
}
if (table(o2))
{
if (includeTableCells)
{
compareTableCells(out, bm1, selectedAttributes, o2)
}
}
else
{
// find this object in the older baseline
absno = o2."Absolute Number"
o1 = object(absno, bm1)
if (null o1)
{
emitNewObject(out, o2)
continue
}
for attr in selectedAttributes do
{
if (o1.attr "" == o2.attr "") continue
emitChangedObject(out, o1, o2, attr)
}
}
}
// Deleted Objects
for o1 in document(bm1) do
{
if (isDeleted(o1)) continue
if (table(o1))
{
if (includeTableCells)
{
checkDeletedCells(out, bm2, o1)
}
}
else
{
// find this object in the older baseline
absno = o1."Absolute Number"
o2 = object(absno, bm2)
if (null o2)
{
emitDeletedObject(out, o1)
}
}
}
out << "
\n"
emitFooter(out)
close(out)
noError
close(bm1)
if (bm2 != m)
{
close(bm2)
}
lastError
return("")
}
//< Export Change Report Dialog
/*
18-MAR-2011 Tony Goodman
*/
DB dbMain = null
DBE dbeLabel = null
DBE dbeFrame = null
DBE dbebaselinesFrame = null
DBE dbeBaseline1 = null
DBE dbeBaseline2 = null
DBE dbeAttributesFrame = null
DBE dbeAttributes = null
DBE dbeSelectAll = null
DBE dbeClearAll = null
DBE dbeIncludeTableCells = null
DBE dbeExtraAttribute = null
DBE dbeExportFrame = null
DBE dbeFileName = null
DBE exportBtn = null
DBE dbeShowMarkup = null
string dummy[] = { }
Skip skipBaselines = create
Skip skipAttributes = createString
/******************************************************************************
getBaselines
******************************************************************************/
void getBaselines(Module currMod)
{
Baseline b = null
int index = 0
for b in currMod do
{
put(skipBaselines, index, b)
insert(dbeBaseline1, index, major(b) "." minor(b) " " suffix(b), iconNone)
insert(dbeBaseline2, index, major(b) "." minor(b) " " suffix(b), iconNone)
index++
}
put(skipBaselines, index, null)
insert(dbeBaseline1, index, "Current", iconNone)
insert(dbeBaseline2, index, "Current", iconNone)
if (index > 0)
{
set(dbeBaseline1, index-1, true)
}
else
{
set(dbeBaseline1, index, true)
}
set(dbeBaseline2, index, true)
}
/******************************************************************************
getAttributes
******************************************************************************/
void getAttributes(Module currMod)
{
AttrDef ad = null
string attr = ""
int index = 0
for ad in currMod do
{
if (!ad.object) continue
if (ad.system) continue
put(skipAttributes, ad.name, ad.name)
}
put(skipAttributes, "Object Text", "Object Text")
put(skipAttributes, "Object Heading", "Object Heading")
for attr in skipAttributes do
{
insert(dbeAttributes, index, attr, iconNone)
if (attr == "Object Heading" || attr == "Object Text")
{
setCheck(dbeAttributes, index, true)
}
index++
}
}
/******************************************************************************
doExport
******************************************************************************/
void doExport(DB db)
{
Baseline b1 = null
Baseline b2 = null
string attr = ""
string outputFile = ""
string res = ""
int i = 0
bool includeTableCells = false
Skip selectedAttributes = createString
includeTableCells = get(dbeIncludeTableCells)
showMarkup = get(dbeShowMarkup)
EXTRA_ATTR = get(dbeExtraAttribute)
if (EXTRA_ATTR "" != "")
{
includeExtraAttr = true
}
i = get(dbeBaseline1)
find(skipBaselines, i, b1)
i = get(dbeBaseline2)
find(skipBaselines, i, b2)
if (b1 == b2)
{
infoBox("Please select two different baselines")
return
}
for (i = 0; i < noElems(dbeAttributes); i++)
{
if (getCheck(dbeAttributes, i))
{
attr = getColumnValue(dbeAttributes, i, 0)
put(selectedAttributes, attr, attr)
}
}
outputFile = get(dbeFileName)
res = exportChangeReport(current Module, b1, b2, selectedAttributes, includeTableCells, outputFile)
if (res "" != "")
{
infoBox(res)
return
}
if (fileExists_(INTERNET_EXPLORER))
{
system("\"" INTERNET_EXPLORER "\" \"" outputFile "\"")
}
else
{
infoBox("Report complete. Please see file\n" outputFile)
}
release(dbMain)
}
/******************************************************************************
doSelectAll
******************************************************************************/
void doSelectAll(DBE dbe)
{
int i = 0
for (i = 0; i < noElems(dbeAttributes); i++)
{
setCheck(dbeAttributes, i, true)
}
}
/******************************************************************************
doClearAll
******************************************************************************/
void doClearAll(DBE dbe)
{
int i = 0
for (i = 0; i < noElems(dbeAttributes); i++)
{
setCheck(dbeAttributes, i, false)
}
}
/******************************************************************************
doClose
******************************************************************************/
void doClose(DB db)
{
release(dbMain)
}
/******************************************************************************
buildDialog
******************************************************************************/
void buildDialog(Module currMod)
{
dbMain = create(currMod, "Smart Baseline Comparison", styleCentered|styleFixed)
dbeLabel = label(dbMain, "This utility exports a baseline comparison report to an HTML file.")
dbeFrame = frame(dbMain, "", 400, 500)
dbeFrame->"top"->"flush"->dbeLabel
dbeFrame->"left"->"form"
dbeFrame->"right"->"form"
dbeFrame->"bottom"->"form"
dbeBaselinesFrame = frame(dbMain, "Baselines to compare", 400, 100)
dbeBaselinesFrame->"top"->"inside"->dbeFrame
dbeBaselinesFrame->"left"->"inside"->dbeFrame
dbeBaselinesFrame->"right"->"inside"->dbeFrame
dbeBaselinesFrame->"bottom"->"unattached"
dbeBaseline1 = listView(dbMain, 0, 190, 5, dummy)
dbeBaseline1->"top"->"inside"->dbeBaselinesFrame
dbeBaseline1->"left"->"inside"->dbeBaselinesFrame
dbeBaseline1->"right"->"unattached"
dbeBaseline1->"bottom"->"inside"->dbeBaselinesFrame
dbeBaseline2 = listView(dbMain, 0, 190, 5, dummy)
dbeBaseline2->"top"->"inside"->dbeBaselinesFrame
dbeBaseline2->"left"->"flush"->dbeBaseline1
dbeBaseline2->"right"->"inside"->dbeBaselinesFrame
dbeBaseline2->"bottom"->"inside"->dbeBaselinesFrame
dbeAttributesFrame = frame(dbMain, "Attributes to compare", 400, 100)
dbeAttributesFrame->"top"->"flush"->dbeBaselinesFrame
dbeAttributesFrame->"left"->"inside"->dbeFrame
dbeAttributesFrame->"right"->"inside"->dbeFrame
dbeAttributesFrame->"bottom"->"unattached"
dbeAttributes = listView(dbMain, listViewOptionCheckboxes | listViewOptionMultiselect, 190, 5, dummy)
dbeAttributes->"top"->"inside"->dbeAttributesFrame
dbeAttributes->"left"->"inside"->dbeAttributesFrame
dbeAttributes->"right"->"inside"->dbeAttributesFrame
dbeAttributes->"bottom"->"inside"->dbeAttributesFrame
dbeSelectAll = button(dbMain, "Select All", doSelectAll)
dbeSelectAll->"top"->"flush"->dbeAttributes
dbeSelectAll->"left"->"inside"->dbeAttributesFrame
dbeSelectAll->"right"->"unattached"
dbeSelectAll->"bottom"->"unattached"
dbeClearAll = button(dbMain, "Clear All", doClearAll)
dbeClearAll->"top"->"flush"->dbeAttributes
dbeClearAll->"left"->"flush"->dbeSelectAll
dbeClearAll->"right"->"unattached"
dbeClearAll->"bottom"->"inside"->dbeAttributesFrame
dbeExportFrame = frame(dbMain, "Export options", 400, 50)
dbeExportFrame->"top"->"flush"->dbeAttributesFrame
dbeExportFrame->"left"->"inside"->dbeFrame
dbeExportFrame->"right"->"inside"->dbeFrame
dbeExportFrame->"bottom"->"inside"->dbeFrame
dbeIncludeTableCells = toggle(dbMain, "Include Table Cells", false)
dbeIncludeTableCells->"top"->"inside"->dbeExportFrame
dbeIncludeTableCells->"left"->"inside"->dbeExportFrame
dbeIncludeTableCells->"right"->"unattached"
dbeIncludeTableCells->"bottom"->"unattached"
dbeShowMarkup = toggle(dbMain, "Show Markup", showMarkup)
dbeShowMarkup->"top"->"flush"->dbeIncludeTableCells
dbeShowMarkup->"left"->"inside"->dbeExportFrame
dbeShowMarkup->"right"->"unattached"
dbeShowMarkup->"bottom"->"unattached"
dbeExtraAttribute = field(dbMain, "Extra Attribute", EXTRA_ATTR, 30, false)
dbeExtraAttribute->"top"->"flush"->dbeShowMarkup
dbeExtraAttribute->"left"->"inside"->dbeExportFrame
dbeExtraAttribute->"right"->"unattached"
dbeExtraAttribute->"bottom"->"unattached"
dbeFileName = fileName(dbMain, "Export to:", OUTPUT_FOLDER name(currMod) "_baseline_comparison.html", "*.html", "HTML Files", false)
dbeFileName->"top"->"flush"->dbeExtraAttribute
dbeFileName->"left"->"inside"->dbeExportFrame
dbeFileName->"right"->"unattached"
dbeFileName->"bottom"->"inside"->dbeExportFrame
exportBtn = apply(dbMain, "Export", doExport)
realize(dbMain)
insertColumn(dbeBaseline1, 0, "Older Baseline", 160, iconNone)
insertColumn(dbeBaseline2, 0, "Newer Baseline", 160, iconNone)
insertColumn(dbeAttributes, 0, " ", 160, iconNone)
getBaselines(currMod)
getAttributes(currMod)
block(dbMain)
destroy(dbMain)
dbMain = null
}
/******************************************************************************
exportBaselineComparison
******************************************************************************/
void exportBaselineComparison()
{
Module currMod = null
currMod = current Module
if (null currMod)
{
infoBox("This utility can only be run from a formal module.")
return
}
(current ModuleRef__) = currMod
filtering off
sorting off
buildDialog(currMod)
}
exportBaselineComparison()