// Link tools /* One overlaoded routine for checking attribute exiastence Two routines for returning the linked module's names and a bunch of routines for displaying nested links See the last routine (exampleNestedLinks) for an example. */ // bool exists(Module m, string attrName) { // Overload "exist" routine for checking attribute's // existence in modules different than the current // // If Module m is null, we'll return null of course if (null m) return false bool returnValue // Temporarily save the current Module Module c = current // Set the current Module to be the passed Module (current ModuleRef__) = m // Check existence using the built-in routine returnValue = exists attribute attrName // Re-set the current Module to the original value if (!null c){(current ModuleRef__) = c} return returnValue } // string linkMod(LinkRef lr, bool fullPath) { // Return Link Module name for LinkRef if (null lr){return ""} Module m = module lr string modName if (fullPath){modName = fullName(m)} else {modName = name(m)} return modName } string linkMod(LinkRef lr){return linkMod(lr, true) ""} string linkMod(Link l, bool fullPath) { // Return Link Module name for Link if (null l){return ""} Module m = module l string modName if (fullPath){modName = fullName(m)} else {modName = name(m)} return modName } string linkMod(Link l){return linkMod(l, true) ""} string sourceMod(LinkRef lr, bool fullPath) { // Return Module name of source object string sourceModuleName = null if (!null lr) { ModName_ sourceModuleRef = source(lr) if (!null sourceModuleRef) { if (fullPath){sourceModuleName = fullName(sourceModuleRef)} else {sourceModuleName = name(sourceModuleRef)} } } return sourceModuleName } // Return Module name of source object string sourceMod(LinkRef lr){return sourceMod(lr, true) ""} string targetMod(Link l, bool fullPath) { // Return Module name of target object string targetModuleName = null if (!null l) { ModName_ targetModuleRef = target(l) if (!null targetModuleRef) { if (fullPath){targetModuleName = fullName(targetModuleRef)} else {targetModuleName = name(targetModuleRef)} } } return targetModuleName } // Return Module name of target object string targetMod(Link l){return targetMod(l, true) ""} // Link link(Object targetObj, LinkRef lr) { // Return the link for a given LinkRef Link l = null string sourceModName, linkModName sourceModName = sourceMod(lr, true) linkModName = linkMod(lr, true) Module sm = read(sourceModName, false) Object so int son int absNum if (!null sm) { son = sourceAbsNo(lr) // Find object in module // The 'object' perm takes into acount filtering, therefore // we use the 'for obj in entire module' loop //so = object(son, sm) so = null for so in entire sm do { if (null so){continue} absNum = so."Absolute Number" if (absNum == son){break} } if (!null so) { Object t for l in so -> linkModName do { t = target(l) if (t == targetObj){break} } } else {print dxlHere() " Null object " son " in Module " sourceModName "\n"} } else {print dxlHere() " Null Module " sourceModName "\n"} return l } // ****************************************************** // The following perms allow the display of nested links // with far greater flexibility than the built-in // traceability wizard. // The general principle is as follows: // // In the first step, criterias for recursively following the // links are defined in the form of two string and one bool // arrays, defining at each recursion level // - the Link Module to be used // - the formal Module to which the links should point, and // - whether incoming or outgoing links should be followed // As for link Modules, possible entries are "*" for any link // Module or the relative or full name of an existing link // Module. // As for formal Modules, the same applies. // // In the second step, a nested Skip list is created. At // each recursion level, its keys are the linked Objects // fulfilling the above criterias; the values are the Skip // lists for the next recursion level. At the last level, // the values are null. // // In the third step, the nested Skip list is used to create // the actual strings to be displayed. // Again, a Skip list is used to control the actual display. // Its keys must be integers (defining the recursion level, // starting from 0), its values string arrays. At each recursion // level, if an appropriate entry exists in the Skip list, it is // interpreted as follows: For each object at this level and for // each entry in the appropriate string array, the display string // is appended by // - the appropriate attribute, if the string array element is a // valid attribute name, or // - the string array element itself otherwise. // // This allows the creation of key: value pairs, even supporting // richText elements, e.g. by defining the string array as follows: // {"Key: ", "{\\b ", "Object Text", "}"} // // The display strings again are returned as Skip list. This allows // the subsequent sorting or removal of duplicate entries. // // An example is given below (exampleNestedLinks) // ****************************************************** // // -------------------------------------------------------------------- void delete_skip(Skip s) { // recursive deletion of nested Skip list if (null s){return} Skip t for t in s do {if (!null t){delete_skip t}} delete s } // -------------------------------------------------------------------- Buffer linkString(string attName, Module currMod, Object currObj) { Buffer returnValue = create // Check if attName is an object or module attribute AttrDef ad = find(currMod, attName) if (!null ad) { if (ad.object){returnValue = richTextFragment richTextWithOle currObj.attName} else if (ad.module){returnValue = richTextFragment richTextWithOle currMod.attName} } else { // attName is neither an object or module attribute. It might // still be a pseudo attribute if (attName == "level"){returnValue = (level currObj) ""} else if (attName == "identifier"){returnValue = (identifier currObj) ""} else if (attName == "number"){returnValue = (number currObj) ""} else if (attName == "description"){returnValue = (description currMod) ""} else if (attName == "name"){returnValue = (name currMod) ""} else if (attName == "fullName"){returnValue = (fullName currMod) ""} else if (attName == "path"){returnValue = (path currMod) ""} else if (attName == "type"){returnValue = (type currMod) ""} // No, so we just copy the string into the return string else {returnValue = attName} } return returnValue } // -------------------------------------------------------------------- Skip followLinks( Object o, int Level, string LnkMod[], ModName[], bool inComing[] ) { // Recursively follow links and create nested Skip list int MaxLevel = sizeof LnkMod Link l LinkRef lr Object linkedObj Skip returnValue = create Skip value = null bool LinkFound = null // Collect all matching links in Skip list to avoid // doubling code lines for incoming and outgoing links Skip objList = create int i = 0 if (inComing[Level]) { // Check incoming / outgoing links for lr in o <- LnkMod[Level] do { if (!open module sourceMod(lr)){read(sourceMod(lr), false)} } for l in o <- LnkMod[Level] do { // Check Link module linkedObj = source l put(objList, i++, linkedObj) } } else { // Check Link module for l in o -> LnkMod[Level] do { if (!open module targetMod(l)){read(targetMod(l), false)} linkedObj = target l put(objList, i++, linkedObj) } } for linkedObj in objList do { // Loop through matching links string linkedModName = null if (exists module ModName[Level]) {linkedModName = fullName item ModName[Level]} if (ModName[Level] == "*" || linkedModName == fullName module linkedObj) { // Check if Module name matches if (Level < (MaxLevel-1)) { // If we are not at the deepest recursion level, call // the routine for the linked Object value = followLinks(linkedObj, Level+1, LnkMod, ModName, inComing) } else {value = null} LinkFound = true // Add the Skip list for the linked Object to the return list put(returnValue, linkedObj, value) } } delete objList if (LinkFound) {return returnValue} else {return value} } // -------------------------------------------------------------------- void linkedAtts( Skip linkSkip, attSkip, int level, Skip &displaySkip, int &index, string dispSoFar ) { // Fill a Skip list of strings with attribute values from // the linked Objects. The Skip list (displaySkip) is passed // by reference, a new key/value pair is added each time a leaf // link is reached (i.e. an object from which no link matching the // criterias is found / an object whose Skip list value is null) // As consistency must be ensured through the differernt recusion // levels, the display Skip list and the index are passed by reference. if (null linkSkip){return} string attList[], attName string disp int n, i Skip tmpSkip Object o Module m for tmpSkip in linkSkip do { // Loop through linked Objects / Skip lists // The display strings of the links leading // to this link are stored in "dispSoFar" disp = dispSoFar // Get the linked Object o = (Object key linkSkip) m = module o if (find(attSkip, level, attList)) { // Check, whether display criterias exist at this // recursion level n = sizeof attList for i in 0:n-1 do { // Create string for this recursion level // Check attribute names in the following order of priority: // 1) Object attributes // 2) Module attributes // Pseudo atributes à la 'name', 'fullName', 'level' are also // supported. // If none of the above is true, the attribute name is taken // as a desriptor and is added as plain text to the string. Buffer tmp = linkString(attList[i], m, o) if (length tmp > 0){disp = disp (tempStringOf tmp)} delete tmp } } if (!null tmpSkip) { // If subsequent links exist, recursively call the // routine for the nested Skip list int l = level + 1 linkedAtts(tmpSkip, attSkip, l, displaySkip, index, disp) } else { // We found a leaf link, therefore a // new string is added to the display List put(displaySkip, index++, disp) } } } Skip linkedAtts(Skip linkList, attList) { // Easy wrapper routine; returns the // display Skip list int index = 0 Skip dispList = create linkedAtts(linkList, attList, 0, dispList, index, "") return dispList } // -------------------------------------------------------------- void exampleNestedLinks() { // Define criteria for Link and formal Modules and for the // link direction string LnkMod[] = {"*", "*", "*"} string ModName[] = {"*", "*", "*"} bool inComing[] = {false, false, false} // Create the Skip list for the linked Objects Skip linkSkip = followLinks(obj, 0, LnkMod, ModName, inComing) // Create the Skip list controlling the display Skip attSkip = create //string a0[] = {"{\\b ", "Object Text", "}"} string a0[] = {"{\\b ", "-> ", "Object Text", "}"} string a1[] = {" -> ", "Object Text"} string a2[] = {" -> ", "Object Text"} put(attSkip, 0, a0) put(attSkip, 1, a1) put(attSkip, 2, a2) // Get the Skip list with the display strings Skip dispSkip = linkedAtts(linkSkip, attSkip) // Display elements string disp for disp in dispSkip do {displayRich disp} // Delete all Skip lists delete_skip linkSkip delete attSkip delete dispSkip } e attSkip delete dispSkip