// 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 += "" } } /****************************************************************************** emitFileHeader ******************************************************************************/ void emitFileHeader(Stream out, string moduleName, Skip newAttributes, bool newAttrs) { string attr = "" out << "\n" // header row out << "\n" out << "\n" out << "\n" if (newAttrs) { out << "\n" out << "\n" out << "\n" } out << "
\n" out << "

Baseline Comparison Report

" out << "Module: " moduleName "
" out << "Exported from DOORS on: " stringOf(today) "
" 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" } /****************************************************************************** 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()