// Build Hierarchy after import from spreadsheet
/*
Description:
Moves objects into a proper hierarchy after import from
spreadsheet.
Assumes that the "main" column in the spreadsheet that contains
object text is prefixed with a paragraph number for heading objects.
The first object in the module must be a level one object.
This paragraph number is parsed and used to determine the level of the
object in the hierarchy.
These paragraph numbers are removed and the remaining text is moved
into the Object Heading.
smartdxl.com
*/
pragma runLim, 0
const string ATTR_LEVEL_INDICATOR = "Object Text"
const string ATTR_NEW_LEVEL = "New Level"
/******************************************************************************
createLevelAttr
******************************************************************************/
void createLevelAttr(Module m)
{
AttrDef ad = null
(current ModuleRef__) = m
if (!exists attribute ATTR_NEW_LEVEL)
{
ad = create(object type "Integer" attribute ATTR_NEW_LEVEL)
}
}
/******************************************************************************
flattenHierarchy
******************************************************************************/
string flattenHierarchy(Module m)
{
Object o = null
Object oFirst = null
Object oPrev = null
int count = 0
Skip objects = create
oFirst = first(m)
if (null oFirst || level(oFirst) != 1)
{
return("Module must begin with a level 1 object")
}
showExplorer(false)
showTables(false)
for o in m do
{
put(objects, count++, o)
}
for o in objects do
{
if (o == oFirst)
{
oPrev = o
}
else
{
//print("move " identifier(o) " after " identifier(oPrev) "\n")
move(o, oPrev)
oPrev = o
}
}
delete(objects)
return("")
}
/******************************************************************************
getLevel
Returns the proposed level of the object based on the contents of
its Object Text. If the object text is empty or does not start with
a digit then a level of zero is returned. Otherwise the level returned
is based on the number of digits separated by periods that are found
at the beginnign of the object text.
******************************************************************************/
int getLevel(Object o)
{
string s = ""
string levelString = ""
int len = 0
int i = 0
int depth = 0
s = o.ATTR_LEVEL_INDICATOR ""
len = length(s)
// empty string, return zero
if (len == 0)
{
return(0)
}
// does not start with a number, return zero
if (!isdigit(s[0]))
{
return(0)
}
// extract the legal number from the beginning of the
// string. Add an extra period at the end to make the next bit easier
for (i = 0; i < len; i++)
{
if (s[i] != '.' && !isdigit(s[i]))
{
levelString = s[0:i-1] "."
break
}
}
// count the periods to determine the depth
for (i = 0; i < length(levelString); i++)
{
if (levelString[i] == '.') depth++
}
return(depth)
}
/******************************************************************************
getHeading
******************************************************************************/
string getHeading(string s)
{
int len = 0
int i = 0
len = length(s)
for (i = 0; i < len; i++)
{
if (isalpha(s[i]))
{
return(s[i:])
}
}
return(s)
}
/******************************************************************************
setInitialLevel
populate level new level attribute based on contents of
level indicator attribute (usually object text)
******************************************************************************/
void setInitialLevel(Module m)
{
Object o = null
for o in m do
{
o.ATTR_NEW_LEVEL = getLevel(o)
}
}
/******************************************************************************
refineLevels
change new level attribute for objects with new level of zero.
If new level attribute is zero then set it to level below previous object
that had a non-zero level.
******************************************************************************/
void refineLevels(Module m)
{
Object o = null
int prevLevel = 0
int thisLevel = 0
for o in m do
{
thisLevel = o.ATTR_NEW_LEVEL
if (thisLevel == 0)
{
o.ATTR_NEW_LEVEL = prevLevel + 1
}
else
{
o."Object Heading" = getHeading(o."Object Text" "")
o."Object Text" = ""
prevLevel = thisLevel
}
}
}
/******************************************************************************
moveObjects
******************************************************************************/
void moveObjects(Object oParent)
{
}
/******************************************************************************
moveObjects
******************************************************************************/
void moveObjects(Module m)
{
Object o = null
Object oParent = null
int prevLevel = 0
int thisLevel = 0
int count = 0
int l = 0
int maxLevel = 0
Skip objects = create
for o in m do
{
put(objects, count++, o)
}
for o in objects do
{
thisLevel = o.ATTR_NEW_LEVEL
if (thisLevel > maxLevel)
{
maxLevel = thisLevel
}
}
for (l = maxLevel; l > 1; l--)
{
for o in objects do
{
thisLevel = o.ATTR_NEW_LEVEL
if (thisLevel == l - 1)
{
oParent = o
}
else if (thisLevel == l)
{
move(o, last below oParent)
}
}
}
delete(objects)
}
/******************************************************************************
MAIN
******************************************************************************/
Module currModule = current Module
string res = ""
if (!isEdit(currModule))
{
infoBox("This utility can only be run in exclusive edit mode")
halt
}
// check that the required level indicator attribute exists
createLevelAttr(currModule)
// ensure flat module hierarchy before starting - i.e. all objects at level 1
res = flattenHierarchy(currModule)
if (res != "")
{
infoBox(res)
halt
}
setInitialLevel(currModule)
refineLevels(currModule)
moveObjects(currModule)
sitemap