Smart History Viewer

This script allows you to view object and module history across all baselines. The dialog displays history in listviews on three tabs, showing complete object, module and session history.

The object tab displays history for the current object. You can browse through objects using the Prev and Next buttons or select the object directly by selecting it in the module window. The module tab displays all module history as well as object deletions. The sessions tab displays the history of all editing sessions and baseline creations. All listviews can be sorted by any column.

This script demonstrates some very strange vaguaries of the history system such as the fact that module level attribute changes are recorded as modifyObject events, but with the object absolute number being zero! (see lines 924 and 971). Take a look at line 1009 to see how session numbers are handled.

For those of you that are interested, this script is a good example of how to use the DxlObject type together with skip lists to build practical data structures.

//  Smart History Viewer - Standalone version.

/*
    S M A R T   D X L   L I M I T E D

	Description:

	Provides a dialog to view history accross multiple baselines.

	Save this file, and tophat.bmp to <DOORS ADDINS>/SmartDXL

	Author:	Tony Goodman	 tony@smartdxl.com

    	Change History:

	25-NOV-2008		Tony Goodman	Initial version.

	24-FEB-2011		Tony Goodman	Locate bitmap from addins path.
											Add banner title and website url.
											Use more complex names for global variables.

	17-May-2011		Tony Goodman	Standalone version. Single DXL file for easy installation
											(With the exception of the optional logo bitmap file)
*/

pragma runLim, 0

/****************************
	Smart DXL logo bitmap file - this is loaded once when first dialog is displayed.
****************************/
Bitmap smartDxlLogo = null

string SMART_DXL_DB_TITLE      = "Smart DXL"
string SMART_DXL_BANNER_WEBSITE  = "www.smartdxl.com"
string SMART_DXL_BANNER_BITMAP    = "SmartDXL\\tophat.bmp"

DBE smartDxlBanner = null

bool smartDxlLogoFound = false

string smartDxlBannerText = ""

int   smartDxlLogoWidth   = 0
int   smartDxlLogoHeight  = 0

/****************************
	getAbsolutePath
****************************/
string getAbsolutePath(string sFileName)
{
	string sResult  = ""

	string sAddinsPathList      = (getenv "ADDINS") ";"
	string sDoorsAddinsPathList = (getenv "DOORSADDINS") ";"

	if (sAddinsPathList != sDoorsAddinsPathList)
	{
		sAddinsPathList = sDoorsAddinsPathList ";" sAddinsPathList
	}

	Regexp rPath = regexp "([^;]*);(.*)"

	string sLeft    = ""
	string sRight   = ""

	if (rPath sAddinsPathList)
	{
		// test each path in the semicolon separated list
		while (rPath sAddinsPathList)
		{
			  sLeft  = sAddinsPathList[match 1]
			  sRight = sAddinsPathList[match 2]

			  if (fileExists_ (sLeft "\\" sFileName))
			  {
					sResult  = sLeft "\\" sFileName
					break;
			  }
			  else
			  {
					sAddinsPathList = sRight
			  }
		}
	}
	return(sResult)
}

/*****************************
  smartDrawLogo
*****************************/
void smartDrawLogo(DBE cnvs)
{
	string smartDxlBitmapFile = ""
	Stat   st = null

	if (null smartDxlLogo)
	{
		// bitmap has not been loaded yet, so load it
		smartDxlBitmapFile = getAbsolutePath(SMART_DXL_BANNER_BITMAP)

		// check that the file exists
		st = create(smartDxlBitmapFile)

		if (!null st)
		{
			// file does exist so we can load the bitmap
			delete(st)

			smartDxlLogo = loadBitmap(cnvs, smartDxlBitmapFile, false, smartDxlLogoWidth, smartDxlLogoHeight)
		}
    }

    // draw the bitmap if it was successfully loaded
    if (!null smartDxlLogo)
    {
    	drawBitmap(cnvs, smartDxlLogo, 0, 0)
		smartDxlLogoFound = true
	}
}

/****************************
	doLogoMouse
****************************/
void doLogoMouse(DBE cnv, int but, bool ctrl, int x, int y)
{
	if (x > width(cnv) - width(cnv, SMART_DXL_BANNER_WEBSITE) - 5)
	{
		activateURL(SMART_DXL_BANNER_WEBSITE)
	}
}

/****************************
	doRepaintSmartDxlBanner
****************************/
void doRepaintSmartDxlBanner(DBE cnv)
{
	int canvasWidth  = width(cnv)
	int titleHeight  = 0
	int y = 0

	realBackground(cnv, realColor_White)

	smartDrawLogo(cnv)

	realColor(cnv, realColor_Black)
	font(cnv, 4, HeadingsFont)

	y = (height(cnv) / 2) + (height(cnv, smartDxlBannerText) / 2) - 3

	draw(cnv, smartDxlLogoWidth + 3, y, smartDxlBannerText)

	realColor(cnv, realColor_Blue)
	font(cnv, 9, HeadingsFont)
	draw(cnv, canvasWidth - width(cnv, SMART_DXL_BANNER_WEBSITE) - 5, y - 1, SMART_DXL_BANNER_WEBSITE)
	line(cnv, canvasWidth - width(cnv, SMART_DXL_BANNER_WEBSITE) - 5, y, canvasWidth - 5, y)
}

/****************************
	addSmartDxlBanner
****************************/
void addSmartDxlBanner(DB db)
{
	smartDxlBanner = canvas(db, 0, 32, doRepaintSmartDxlBanner)

	set(smartDxlBanner, doLogoMouse)
}

/****************************
	showHelp
****************************/
void showHelp(string helpFile)
{
	system("\"C:\\Program Files\\Internet Explorer\\iexplore.exe\" -nohome \"" (getAbsolutePath(helpFile)) "\"")
}

/****************************
	smartDialog
****************************/
DB smartDialog(string banner, int options)
{
	DB smartDb = null

	smartDb = create(SMART_DXL_DB_TITLE, options)

	smartDxlBannerText = banner

	addSmartDxlBanner(smartDb)

    return(smartDb)
}

/****************************
	smartDialog
****************************/
DB smartDialog(string dbTitle)
{
	return(smartDialog(dbTitle, styleCentered|styleFloating))
}	

/****************************
	smartDialog
****************************/
DB smartDialog(Module mParent, string banner, int options)
{
	DB smartDb = null

	smartDb = create(mParent, SMART_DXL_DB_TITLE, options)

	smartDxlBannerText = banner

	addSmartDxlBanner(smartDb)

    return(smartDb)
}

/****************************
	smartDialog
****************************/
DB smartDialog(Module mParent, string dbTitle)
{
	return(smartDialog(mParent, dbTitle, styleCentered|styleFloating))
}

/****************************
	smartDialog
****************************/
DB smartDialog(DB dbParent, string banner, int options)
{
	DB  smartDb     = null

	smartDb = create(dbParent, SMART_DXL_DB_TITLE, options)

	smartDxlBannerText = banner

	addSmartDxlBanner(smartDb)

    return(smartDb)
}

/****************************
	smartDialog
****************************/
DB smartDialog(DB dbParent, string banner)
{
	return(smartDialog(dbParent, banner, styleCentered|styleFloating))
}

//  Sort Callbacks for listViews

/****************************
	doSortString
****************************/
int doSortString(string s1, string s2)
{
	return(cistrcmp(s1, s2))
}

/****************************
	doSortDate
****************************/
int doSortDate(string s1, string s2)
{
	Date d1 = "1 January 1970"
	Date d2 = "1 January 1970"

	if (s1 != "")
	{
		d1 = date(s1)
	}

	if (s2 != "")
	{
		d2 = date(s2)
	}

	if (d1 > d2)
	{
		return(-1)
	}
	else if (d2 > d1)
	{
		return(1)
	}

	return(0)
}

/****************************
	doSortInteger
****************************/
int doSortInteger(string s1, string s2)
{
	int i1 = intOf(s1)
	int i2 = intOf(s2)

	if (i1 > i2)
	{
		return(1)
	}
	else if (i2 > i1)
	{
		return(-1)
	}

	return(0)
}

/****************************
	doSortLegal
****************************/
int doSortLegal(string s1, string s2)
{
	int i1 = 0
	int i2 = 0

	i1 = intOf(s1)
	i2 = intOf(s2)

	if (i1 > i2)
	{
		return(1)
	}
	else if (i2 > i1)
	{
		return(-1)
	}
	else
	{
		if (length(s1) > length(i1 ""))
		{
			if (length(s2) > length(i2 ""))
			{
				return(doSortLegal(s1[length(i1 "") + 1:], s2[length(i2 "") + 1:]))
			}

			return(1)
		}
		else if (length(s2) > length(i2 ""))
		{
			return(-1)
		}

		return(0)
	}

	return(0)
}

// columns in listview
const int BS_NAME_COLUMN       = 0
const int BS_CREATED_BY_COLUMN = 1
const int BS_CREATED_ON_COLUMN = 2
const int BS_DELETED_BY_COLUMN = 3
const int BS_DELETED_ON_COLUMN = 4

string bsListItems[] = {}

DB  bsMainDb       = null
DBE bsBaselinesDbe = null

// list of all baselines found in the module
Skip bsSelectedBaselinesSkip = null

// list of baselines selected in the listview by the user
Skip bsAllBaselinesSkip      = null

// true if the user selects one or more baselines.
// false if no baselines are selected or the user clicks cancel
bool bsBaselinesSelected = false

/****************************
	bsUpdateBaselineList

	Update the list view with entries for all baselines found in the given
	module. Also adds each baseline to the list of all baselines.
	This list is used later to get a handle on the selected baselines according
	to their position in the listview.
****************************/
void bsUpdateBaselineList(Module m)
{
    int      i            = 0
    Baseline b            = null
    string   strDate      = ""
    Date     baselineDate = null
    Date     deletedDate  = null

    // clear entries from the list view
    empty(bsBaselinesDbe)

    // loop through al baselines in the module
    for b in all m do
    {
        strDate = ""
        baselineDate = dateOf(b)

        if (!null baselineDate)
        {
            strDate = stringOf(baselineDate)
        }

        // add baseline to list of all baselines
        put(bsAllBaselinesSkip, i, b)

        // add an entry for this baseline to list view
        insert(bsBaselinesDbe, i, major(b) "." minor(b) " " suffix(b), iconNone)

        // set column values
        set(bsBaselinesDbe, i, BS_CREATED_BY_COLUMN, user(b))
        set(bsBaselinesDbe, i, BS_CREATED_ON_COLUMN, strDate)

        if (deleted(b))
        {
            strDate = ""
            deletedDate = deletedOn(b)

            if (!null deletedDate)
            {
                strDate = stringOf(deletedDate)
            }

            set(bsBaselinesDbe, i, BS_DELETED_BY_COLUMN, deletedBy(b))
            set(bsBaselinesDbe, i, BS_DELETED_ON_COLUMN, strDate)
        }
        i++
    }
}

/****************************
	bsDoCancel
	Callback for Cancel button.
****************************/
void bsDoCancel(DB db)
{
	bsBaselinesSelected = false
	release(bsMainDb)
}

/****************************
	bsDoApply
	Callback for OK button.
	Gets selections from the listview and updates the selected baseline list.
****************************/
void bsDoApply(DB db)
{
	int i = 0
	Baseline b = null

	bsBaselinesSelected = false

	// loop through entries in the list view
	for (i = 0; i < noElems(bsBaselinesDbe); i++)
	{
		// if the entry is checked (selected) ...
		if (getCheck(bsBaselinesDbe, i))
		{
			bsBaselinesSelected = true

			// look up the corresponding baseline
			if (find(bsAllBaselinesSkip, i, b))
			{
				// add to selected baseline list
				put(bsSelectedBaselinesSkip, i, b)
			}
		}
	}

	if (!bsBaselinesSelected)
	{
		infoBox("No baselines selected!")
		return
	}

	release(bsMainDb)
}

/****************************
	bsDoSelectAll

	Callback for the Select All button.
	Sets all the entries in the list to checked.
****************************/
void bsDoSelectAll(DB db)
{
	int i = 0

	for (i = 0; i < noElems(bsBaselinesDbe); i++)
	{
		setCheck(bsBaselinesDbe, i, true)
	}
}

/****************************
	bsDoDeselectAll

	Callback for the Deselect All button.
	Sets all the entries in the list to unchecked.
****************************/
void bsDoDeselectAll(DB db)
{
	int i = 0

	for (i = 0; i < noElems(bsBaselinesDbe); i++)
	{
		setCheck(bsBaselinesDbe, i, false)
	}
}

/****************************
	bsGetUserSelectedBaselines

	Launches a dialog displaying a list of baselines for the specified
	module. The user is able to select multiple baselines from the list.

	The selected baselines are returned in the skip list, indexed by an integer
	starting at zero.

	If selectAll is TRUE then the all entries in the list are initially checked.

	Returns TRUE if the user selects on or more baselines, otherwise FALSE.
****************************/
bool bsGetUserSelectedBaselines(Module m, Skip skip, string dbTitle, string msg, bool selectAll)
{
	Baseline b = null

	bsSelectedBaselinesSkip = create
	bsAllBaselinesSkip = create

	bsMainDb = smartDialog(m, dbTitle, styleCentered)

	label(bsMainDb, msg)

	bsBaselinesDbe = listView(bsMainDb, listViewOptionCheckboxes | listViewOptionSortText, 455, 10, bsListItems)

	close(bsMainDb, false, bsDoCancel)

	apply(bsMainDb, "Select All", bsDoSelectAll)
	apply(bsMainDb, "Deselect All", bsDoDeselectAll)
	apply(bsMainDb, bsDoApply)
	ok(bsMainDb, "Cancel", bsDoCancel)

	realize(bsMainDb)

	insertColumn(bsBaselinesDbe, BS_NAME_COLUMN,       "Baseline",    80, iconNone)
    insertColumn(bsBaselinesDbe, BS_CREATED_BY_COLUMN, "Created By",  80, iconNone)
    insertColumn(bsBaselinesDbe, BS_CREATED_ON_COLUMN, "Created On", 105, iconNone)
    insertColumn(bsBaselinesDbe, BS_DELETED_BY_COLUMN, "Deleted By",  80, iconNone)
    insertColumn(bsBaselinesDbe, BS_DELETED_ON_COLUMN, "Deleted On", 105, iconNone)

    set(bsBaselinesDbe, BS_NAME_COLUMN,       doSortLegal)
    set(bsBaselinesDbe, BS_CREATED_BY_COLUMN, doSortString)
    set(bsBaselinesDbe, BS_CREATED_ON_COLUMN, doSortDate)
    set(bsBaselinesDbe, BS_DELETED_BY_COLUMN, doSortString)
    set(bsBaselinesDbe, BS_DELETED_ON_COLUMN, doSortDate)

    bsUpdateBaselineList(m)

    if (selectAll)
    {
	    bsDoSelectAll(bsMainDb)
    }

	block(bsMainDb)

	hide(bsMainDb)
	destroy(bsMainDb)
	bsMainDb = null

	for b in bsSelectedBaselinesSkip do
	{
		put(skip, (int key bsSelectedBaselinesSkip), b)
	}

	delete(bsSelectedBaselinesSkip)
	delete(bsAllBaselinesSkip)

	return(bsBaselinesSelected)
}

/*

    Data structures and utilities for handling history records.

    History types:
	    const HistoryType unknown
		const HistoryType createType
		const HistoryType modifyType
		const HistoryType deleteType
		const HistoryType createAttr
		const HistoryType modifyAttr
		const HistoryType deleteAttr
		const HistoryType createObject
		const HistoryType copyObject
		const HistoryType modifyObject
		const HistoryType deleteObject
		const HistoryType unDeleteObject
		const HistoryType purgeObject
		const HistoryType moveObject
		const HistoryType clipCutObject
		const HistoryType clipMoveObject
		const HistoryType clipCopyObject
		const HistoryType createModule
		const HistoryType baselineModule
		const HistoryType partitionModule
		const HistoryType acceptModule
		const HistoryType returnModule
		const HistoryType rejoinModule
		const HistoryType createLink
		const HistoryType modifyLink
		const HistoryType deleteLink
		const HistoryType insertOLE
		const HistoryType removeOLE
		const HistoryType changeOLE
		const HistoryType pasteOLE
		const HistoryType cutOLE
		const HistoryType readLocked
		const HistoryType commentObject
		const HistoryType commentModule
*/

// indices to DxlObject structure
const string HIST_AUTHOR       = "author"
const string HIST_DATE         = "date"
const string HIST_BASELINE     = "baseline"
const string HIST_SESSION      = "session"
const string HIST_DESCRIPTION  = "description"
const string HIST_OLD_VALUE    = "oldvalue"
const string HIST_NEW_VALUE    = "newvalue"
const string HIST_TYPE         = "type"
const string HIST_LOCKED       = "locked"

// data structure for object history
Skip skipObjects        = create
Skip skipNumRecords     = create

// data structure for module history
Skip skipModuleHistory  = create
int  numModuleRecords   = 0

// data structure for session history
Skip skipSessionHistory = create
int  numSessionRecords  = 0

Module  currMod               = null
Object  currObj               = null
int     currObjNumber         = 0

/****************************
	printObjectHistory

	Use for degug only. Prints all data structures.
****************************/
void printObjectHistory()
{
	Object      o           = null
	Skip        skipHistory = null
	DxlObject   hist        = null
	HistoryType historyType = null
	int         objNo       = 0
	int         rec         = 0

	for skipHistory in skipObjects do
	{
		// get object number
		objNo = (int key skipObjects)

		// lookup number of history records stored for this object
		find(skipNumRecords, objNo, rec)

		print("Object " (int key skipObjects) " has " rec " history records\n")

		for hist in skipHistory do
		{
			print("\tHistory record " (int key skipHistory) "\n")

			if (!(bool hist->HIST_LOCKED))
			{
				print("\t\tDate: " (Date hist->HIST_DATE) "\n")
				print("\t\tAuthor: " (string hist->HIST_AUTHOR) "\n")
				print("\t\tSession: " (int hist->HIST_SESSION) "\n")
				print("\t\tBaseline: " (string hist->HIST_BASELINE) "\n")

				historyType = (HistoryType hist->HIST_TYPE)

				print("\t\tDescription: " (string hist->HIST_DESCRIPTION) "\n")
				print("\t\t\tFrom: " (string hist->HIST_OLD_VALUE) "\n")
				print("\t\t\tTo: " (string hist->HIST_NEW_VALUE) "\n")
			}
			else
			{
				print("Read Locked Data\n")
			}
		}
		return
	}
}

/****************************
	isObjectOperation
****************************/
bool isObjectOperation(HistoryType historyType)
{
    return((historyType == createObject)   ||
           (historyType == copyObject)     ||
           (historyType == deleteObject)   ||
           (historyType == unDeleteObject) ||
           (historyType == purgeObject)    ||
           (historyType == clipCutObject)  ||
           (historyType == clipCopyObject) ||
           (historyType == createLink)     ||
           (historyType == modifyLink)     ||
           (historyType == deleteLink)     ||
           (historyType == insertOLE)      ||
           (historyType == removeOLE)      ||
           (historyType == changeOLE)      ||
           (historyType == pasteOLE))
}

/****************************
	isModuleOperation

	This function deliberately includes the deleteObject and purgeObject
	operations as these do not appear in the object history.

	modifyObject is required for changes to module level attributes.
****************************/
bool isModuleOperation(HistoryType historyType)
{
	return(historyType == createModule ||
	       historyType == baselineModule ||
	       historyType == partitionModule ||
	       historyType == acceptModule ||
	       historyType == rejoinModule ||
	       historyType == returnModule ||
	       historyType == commentModule ||
	       historyType == createAttr ||
	       historyType == modifyAttr ||
	       historyType == deleteAttr ||
	       historyType == createType ||
	       historyType == modifyType ||
	       historyType == deleteType ||
	       historyType == deleteObject ||
	       historyType == purgeObject ||
	       historyType == modifyObject)
}

/****************************
	getObjectHistory
****************************/
void getObjectHistory(Module m, string currBaseline)
{
	Object      o            = null
	int         objNo        = 0
	int         rec          = 0
	bool        locked       = false
	History     h            = null
	HistoryType historyType  = null

	// loop through all objects in the module an extract object history
	for o in entire(m) do
	{
		objNo = o."Absolute Number"

		// skip list to hold history records for the object
		Skip skipHistory = null

		// see if the history list already exists, if not then create it
		if (find(skipObjects, objNo, skipHistory))
		{
			//print("skipHistory found for object " objNo "\n")
			// skip list exists - find next index to use
			if (find(skipNumRecords, objNo, rec))
			{
				//print("numrecords found = " rec "\n")
			}
			//rec++
		}
		else
		{
			skipHistory = create

			// new skip list, so first entry will be indexed at zero
			rec = 0
		}

		// loop through history records for the object
		for h in o do
		{
			// create structure to hold details of the history record
			DxlObject hist = new

			// history record may be read-locked
			locked = h.readlocked
			hist->HIST_LOCKED = locked

			// record the type
			historyType = h.type
			hist->HIST_TYPE = historyType

			// if it is not locked we can read the details
			if (!locked)
			{
				hist->HIST_DATE = h.date
				hist->HIST_AUTHOR = h.author
				hist->HIST_SESSION = h.sessionNo
				hist->HIST_BASELINE = currBaseline
				//hist->HIST_DETAILS = "<no further details>"

				if (historyType == modifyObject)
				{
					// object modification has old and new values
					hist->HIST_DESCRIPTION = "Modify Attribute: " h.attrName

					// TBD use buffers to hold old and new values.
					hist->HIST_OLD_VALUE = h.oldValue
					hist->HIST_NEW_VALUE = h.newValue
				}
				else if (historyType == moveObject or historyType == clipMoveObject)
				{
					// object was moved or copied and pasted
					hist->HIST_DESCRIPTION = "Move object from " h.position " to " h.newPosition ""
				}
				else if (historyType == clipCopyObject)
				{
					// object was created by copying another
					hist->HIST_DESCRIPTION = "Copy object from " h.oldAbsNo " to " h.absNo ""
				}
				else if (historyType == commentObject)
				{
					hist->HIST_DESCRIPTION = "Comment"
					hist->HIST_NEW_VALUE = h.newValue
				}
				else if (isObjectOperation(historyType))
				{
					hist->HIST_DESCRIPTION = goodStringOf(historyType)
				}
				else
				{
					hist->HIST_DESCRIPTION = "<unknown history type>"
				}
			}

			// add history structure to list of history records for this object
			put(skipHistory, rec++, hist)
		}

		// store the number of history records in the list
		delete(skipNumRecords, objNo)
		put(skipNumRecords, objNo, rec)

		// add list of history records for this object to the object list
		delete(skipObjects, objNo)
		put(skipObjects, objNo, skipHistory)
	}
}

/****************************
	getModuleHistory
****************************/
void getModuleHistory(Module m, string currBaseline)
{
	int         rec          = 0
	bool        locked       = false
	string      modification = ""
	History     h            = null
	HistoryType historyType  = null

	// loop through history records (this loops through ALL history
	// because we want the object delete and purge history records
	// in addition to the module specific history records.
	for h in m do
	{
		historyType = h.type

		if (!isModuleOperation(historyType))
		{
			continue
		}

		// filter out modifyObject records that are not for module level attributes
		if (historyType == modifyObject && h.absNo != 0)
		{
			continue
		}

		// create structure to hold details of the history record
		DxlObject hist = new

		// record the type
		hist->HIST_TYPE = historyType

		// history record may be read-locked
		locked = h.readlocked
		hist->HIST_LOCKED = locked

		// if it is not locked we can read the details
		if (!locked)
		{
			hist->HIST_DATE = h.date
			hist->HIST_AUTHOR = h.author
			hist->HIST_SESSION = h.sessionNo
			hist->HIST_BASELINE = currBaseline
			//hist->HIST_DETAILS = "<no further details>"

			modification = goodStringOf(historyType)
			hist->HIST_DESCRIPTION = modification

			if (historyType == createAttr || historyType == modifyAttr || historyType == deleteAttr)
			{
				// attribute modification
				hist->HIST_DESCRIPTION = modification ": " h.attrName
			}
			else if (historyType == createType || historyType == modifyType || historyType == deleteType)
			{
				// attribute type modification
				hist->HIST_DESCRIPTION = modification ": " h.typeName
			}
			else if (historyType == commentModule)
			{
				hist->HIST_DESCRIPTION = "Comment"
				hist->HIST_NEW_VALUE = h.newValue
			}
			else if (historyType == deleteObject || historyType == purgeObject)
			{
				hist->HIST_DESCRIPTION = modification ": " h.absNo ""
			}
			else if (historyType == modifyObject && (h.absNo == 0))
			{
				// it seems that modifications to module level attributes are stored
				// as modifyObject history records with an absolute number of zero.
				hist->HIST_DESCRIPTION = "Modify Attribute: " h.attrName

				// TBD use buffers to hold old and new values.
				hist->HIST_OLD_VALUE = h.oldValue
				hist->HIST_NEW_VALUE = h.newValue
			}
		}

		// store history structure in skip list
		put(skipModuleHistory, numModuleRecords++, hist)
	}
}

/****************************
	getSessionHistory
****************************/
void getSessionHistory(Module m)
{
	HistorySession hs        = null
	string         sBaseline = ""

	for hs in m do
	{
		// create structure to hold details of the history record
		DxlObject hist = new

		hist->HIST_DATE = when(hs)
		hist->HIST_AUTHOR = who(hs) 

		// Sessions are 0-based in the core;  the 1+ here is to account for the fact that
        // number(s) uses this 0-based scheme whereas sessionNo does
        // this 1+ internally.
		hist->HIST_SESSION = number(hs) + 1

		sBaseline = baseline(hs)

		if (!null sBaseline)
		{
			hist->HIST_BASELINE = sBaseline
			hist->HIST_DESCRIPTION = "Created baseline " sBaseline
		}			

		//hist->HIST_DETAILS = "<no details>"

		put(skipSessionHistory, numSessionRecords++, hist)
	}
}

/****************************
	getHistory
****************************/
void getHistory(Module m)
{
	string      currBaseline = ""
	string      s            = ""
	Baseline    b            = null

	// extract baseline information
	if (isBaseline(m))
	{
		b = baselineInfo(m)

		// only display the suffix if is is not empty
		s = (suffix b) ""

		if (s != "")
		{
			s = " (" s ")"
		}

		currBaseline = (major b) "." (minor b) "" s
	}
	else
	{
		currBaseline = "current"
	}

	// get object history records
	getObjectHistory(m, currBaseline)

	// get module history records
	getModuleHistory(m, currBaseline)
}

// listview column indices
const int HIST_AUTHOR_COLUMN        = 0
const int HIST_SESSION_COLUMN       = 1
const int HIST_DATE_COLUMN          = 2
const int HIST_BASELINE_COLUMN      = 3
const int HIST_DESCRIPTION_COLUMN   = 4
const int HIST_RECORD_COLUMN        = 5

// tab indices
const int TAB_OBJECT   = 0
const int TAB_MODULE   = 1
const int TAB_SESSIONS = 2

int selectedTab = TAB_OBJECT

// main dialog
DB      dbMain                = null
DBE     dbeTab                = null

// elements
DBE     dbeLabel        = null
DBE     dbeListView     = null
DBE     dbeDetailsFrame = null
DBE     dbeOldValue     = null
DBE     dbeNewValue       = null
DBE     btnPrev         = null
DBE     btnNext         = null

string  columnTitles[]        = {}

string tabLabels[] = { "Object", "Module", "Sessions" }

string details = ""

//Trigger g_mTrigger            = null
Trigger preSyncTrigger        = null
Trigger postSyncTrigger       = null

Skip skipOldValues = null
Skip skipNewValues = null

/****************************
	clearDetailSkips
****************************/
void clearDetailSkips()
{
	// dynamically store the old and new values in a skip list, referenced by
	// history record number. this allows us to look up the values for display
	// when the user selects an entry in the listview.
	if (!null skipOldValues)
	{
		delete(skipOldValues)
	}
	skipOldValues = create

	if (!null skipNewValues)
	{
		delete(skipNewValues)
	}
	skipNewValues = create
}

/****************************
	showObjectHistory

	Update the dialog with information read from the data structures.
****************************/
void showObjectHistory()
{
	Skip        skipHistory = null
	DxlObject   hist        = null
	HistoryType historyType = null
	int         objNo       = 0
	int         rec         = 0

	objNo = currObj."Absolute Number"

	clearDetailSkips()

	// check that there is an entry for this object in the list
	if (find(skipObjects, objNo, skipHistory) && find(skipNumRecords, objNo, rec))
	{
		if (rec > 0)
		{
			// there are history records for this object
			for hist in skipHistory do
			{
				rec = noElems(dbeListView)

				// insert a row in the list view
				insert(dbeListView, rec, "", iconNone)

				historyType = (HistoryType hist->HIST_TYPE)

				if (!(bool hist->HIST_LOCKED))
				{
					set(dbeListView, rec, HIST_AUTHOR_COLUMN,       (string hist->HIST_AUTHOR))
					set(dbeListView, rec, HIST_SESSION_COLUMN,      (int hist->HIST_SESSION) "")
					set(dbeListView, rec, HIST_DATE_COLUMN,         stringOf(Date hist->HIST_DATE) "")
					set(dbeListView, rec, HIST_BASELINE_COLUMN,     (string hist->HIST_BASELINE))
					set(dbeListView, rec, HIST_DESCRIPTION_COLUMN,  (string hist->HIST_DESCRIPTION))

					// used as an index to the details lists
					set(dbeListView, rec, HIST_RECORD_COLUMN,       rec "")

					// store details in lists - these can then be retrieved when user selects
					// an entry in the listview
					put(skipOldValues, rec, (string hist->HIST_OLD_VALUE))
					put(skipNewValues, rec, (string hist->HIST_NEW_VALUE))
				}
				else
				{
					set(dbeListView, rec, HIST_DESCRIPTION_COLUMN,  goodStringOf(historyType) ": <Read Locked Data>")
					set(dbeListView, rec, HIST_AUTHOR_COLUMN,       "<Read Locked Data>")
					set(dbeListView, rec, HIST_SESSION_COLUMN,      "<Read Locked Data>")
					set(dbeListView, rec, HIST_DATE_COLUMN,         "<Read Locked Data>")
					set(dbeListView, rec, HIST_BASELINE_COLUMN,     "<Read Locked Data>")
					set(dbeListView, rec, HIST_RECORD_COLUMN,       rec "")
				}
			}
		}
		else
		{
			// there are no history records for this object
			insert(dbeListView, 0, "", iconNone)
			set(dbeListView, 0, HIST_DATE_COLUMN, "<No history found>" "")
		}

	}
	else
	{
		// there is no entry for this object
		insert(dbeListView, 0, "", iconNone)
		set(dbeListView, 0, HIST_DESCRIPTION_COLUMN, "<Object not found>")
	}
}

/****************************
	showModuleHistory

	Update the dialog with information read from the data structures.
****************************/
void showModuleHistory()
{
	DxlObject   hist        = null
	HistoryType historyType = null
	int         rec         = 0

	clearDetailSkips()

	if (numModuleRecords > 0)
	{
		// there are history records for this object
		for hist in skipModuleHistory do
		{
			rec = noElems(dbeListView)

			// insert a row in the list view
			insert(dbeListView, rec, "", iconNone)

			historyType = (HistoryType hist->HIST_TYPE)

			if (!(bool hist->HIST_LOCKED))
			{
				set(dbeListView, rec, HIST_AUTHOR_COLUMN,       (string hist->HIST_AUTHOR))
				set(dbeListView, rec, HIST_SESSION_COLUMN,      (int hist->HIST_SESSION) "")
				set(dbeListView, rec, HIST_DATE_COLUMN,         stringOf(Date hist->HIST_DATE) "")
				set(dbeListView, rec, HIST_BASELINE_COLUMN,     (string hist->HIST_BASELINE))
				set(dbeListView, rec, HIST_DESCRIPTION_COLUMN,  (string hist->HIST_DESCRIPTION))
				set(dbeListView, rec, HIST_RECORD_COLUMN,       rec "")

				// store details in lists - these can then be retrieved when user selects
				// an entry in the listview
				put(skipOldValues, rec, (string hist->HIST_OLD_VALUE))
				put(skipNewValues, rec, (string hist->HIST_NEW_VALUE))

			}
			else
			{
				set(dbeListView, rec, HIST_DESCRIPTION_COLUMN,  goodStringOf(historyType) ": <Read Locked Data>")
				set(dbeListView, rec, HIST_AUTHOR_COLUMN,       "<Read Locked Data>")
				set(dbeListView, rec, HIST_SESSION_COLUMN,      "<Read Locked Data>")
				set(dbeListView, rec, HIST_DATE_COLUMN,         "<Read Locked Data>")
				set(dbeListView, rec, HIST_BASELINE_COLUMN,     "<Read Locked Data>")
				set(dbeListView, rec, HIST_RECORD_COLUMN,       rec "")
			}
		}
	}
	else
	{
		// there are no history records for this object
		insert(dbeListView, 0, "", iconNone)
		set(dbeListView, 0, HIST_DATE_COLUMN, "<No history found>")
	}

}

/****************************
	showSessionHistory

	Update the dialog with information read from the data structures.
****************************/
void showSessionHistory()
{
	DxlObject   hist        = null
	int         rec         = 0

	clearDetailSkips()

	if (numSessionRecords > 0)
	{
		// there are history records for this object
		for hist in skipSessionHistory do
		{
			rec = noElems(dbeListView)

			// insert a row in the list view
			insert(dbeListView, rec, "", iconNone)

			set(dbeListView, rec, HIST_AUTHOR_COLUMN,       (string hist->HIST_AUTHOR))
			set(dbeListView, rec, HIST_SESSION_COLUMN,      (int hist->HIST_SESSION) "")
			set(dbeListView, rec, HIST_DATE_COLUMN,         stringOf(Date hist->HIST_DATE) "")
			set(dbeListView, rec, HIST_BASELINE_COLUMN,     (string hist->HIST_BASELINE))
			set(dbeListView, rec, HIST_DESCRIPTION_COLUMN,  (string hist->HIST_DESCRIPTION))
		}
	}
	else
	{
		// there are no history records for this object
		insert(dbeListView, 0, "", iconNone)
		set(dbeListView, 0, HIST_DATE_COLUMN, "<No sessions found>")
	}
}

/****************************
	getBaselineHistory
****************************/
bool getBaselineHistory(Skip skipBaselines)
{
	Baseline thisBasline      = null
	Module   moduleBaseline   = null
	int      bCount           = 0
	int      numBaselines     = 0
	bool     autoShutdown     = false

	// count baselines for progress
	for thisBasline in skipBaselines do
	{
		numBaselines++
		//print("Baseline " (major b) "." (minor b) (suffix b) " " (user b) " " (dateOf b) " " (annotation b) "\n")
	}

	progressStart(dbMain, "Please Wait", "Reading history from baselines", numBaselines)

	// load history from current version
	getHistory(currMod)

	// get session history records
	getSessionHistory(currMod)

	// loop through list of baselines
	for thisBasline in skipBaselines do
	{
		progressStep(++bCount)
		progressMessage("Reading history from baseline " bCount " of " numBaselines "")

		if (progressCancelled)
		{
            if (confirm("Are you sure you want to cancel?"))
            {
	            progressStop
	            //delete(skipBaselines)
                return(false)
            }
        }

		// open the baseline in the background
		moduleBaseline = load(currMod, thisBasline, false)

		if (null moduleBaseline)
		{
			print("ERROR opening baseline " (major thisBasline) "." (minor thisBasline) " (" (suffix thisBaseline) ")\n")
			continue
		}

		// read history from baseline
		getHistory(moduleBaseline)

		close(moduleBaseline)
	}

	progressStop()

	return(true)
}

/****************************
	doCancel

	Callback on Cancel button on details dialog
****************************/
void doCancel(DB db)
{
	//release(dbDetails)
}

/****************************
	doHelp

	Callback on help button.
****************************/
void doHelp(DB db)
{

}

/****************************
	refreshDisplay
****************************/
void refreshDisplay()
{
	// refresh current selected object
	(current ModuleRef__) = currMod
    (current ObjectRef__) = currObj

    refresh(currMod)

    empty(dbeListView)
    set(dbeOldValue, "")
    set(dbeNewValue, "")

    if (selectedTab == TAB_OBJECT)
    {
    	// update dialog to show history records for the selected object
    	set(dbeLabel, "History for Object " identifier(currObj))

    	showObjectHistory()
    	show(btnPrev)
		show(btnNext)
		//show(btnDetails)
		//inactive(btnDetails)
	}
	else if (selectedTab == TAB_MODULE)
	{
		set(dbeLabel, "History for Module " fullName(currMod))

		showModuleHistory()
		hide(btnPrev)
		hide(btnNext)
		//hide(btnDetails)
	}
	else if (selectedTab == TAB_SESSIONS)
	{
		set(dbeLabel, "Session history for Module " fullName(currMod))

		showSessionHistory()
		hide(btnPrev)
		hide(btnNext)
		//hide(btnDetails)
	}
}

/****************************
	preSyncFn
****************************/
bool preSyncFn(Trigger t)
{
	// ensure correct current object and module BEFORE object sync
    (current ModuleRef__) = currMod
    (current ObjectRef__) = currObj

    return(true)
}

/****************************
	postSyncFn
****************************/
void postSyncFn(Trigger t)
{
	// we can safely do this because current module and object were
	// set BEFORE object sync.
	//print("post sync fired\n")

    currObj = current Object
    refreshDisplay()
}

/****************************
	doClose
****************************/
void doClose(DB db)
{
	//if (!null g_mTrigger)
	//{
	//	delete g_mTrigger
	//}

	if (!null preSyncTrigger)
	{
        delete preSyncTrigger
    }

    if (!null postSyncTrigger)
    {
        delete postSyncTrigger
    }

    // TBD delete data astructures

	hide(dbMain)
	destroy(dbMain)
	dbMain = null
}

/****************************
	fnTrigger
****************************/
bool fnTrigger(Trigger xx)
{
    doClose(dbMain)

    return true
}

/****************************
	doPrev
****************************/
void doPrev(DBE dbe)
{
	Object oPrev = previous currObj

    if (oPrev != null)
    {
        currObj = oPrev
        currObjNumber = currObj."Absolute Number"
        refreshDisplay()
    }
}

/****************************
	doNext
****************************/
void doNext(DBE dbe)
{
	Object oNext = next currObj

    if (oNext != null)
    {
        currObj = oNext
        currObjNumber = currObj."Absolute Number"
        refreshDisplay()
    }
}

/****************************
	doSelect

	In shareable edit mode the user may have moved to an object that is not
	locked. Therefore we must check that the current object is locked for edit.
****************************/
void doSelect(DBE dbe, int iSelected)
{
	string sNew = ""
	string sOld = ""

	// get record number from listview - this gives an index to old and new values lists
	int record = intOf(getColumnValue(dbeListView, iSelected, HIST_RECORD_COLUMN))

	if (find(skipNewValues, record, sNew))
	{
		set(dbeNewValue, sNew)

		if (find(skipOldValues, record, sOld))
		{
			set(dbeOldValue, sOld)
		}
	}
}

/****************************
	doUnselect
****************************/
void doUnselect(DBE dbe, int iSelected)
{
	set(dbeOldValue, "")
	set(dbeNewValue, "")
}

/****************************
	doActivate

	Callback when user double-clicks on entry in the list view
****************************/
void doActivate(DBE dbe, int iSelected)
{
    //doDetails(dbeListView)
}

/****************************
	doTabSelect
****************************/
void doTabSelect(DBE dbe)
{
	selectedTab = get(dbeTab)

	refreshDisplay()
}

/****************************
	showHistoryDialog
****************************/
void showHistoryDialog(Skip skip)
{
	string dispString = ""

	currMod = current Module

	// trigger to close dialog when module closes
	//g_mTrigger = trigger(module, close, 10, fnTrigger)

	dbMain = smartDialog(currMod, "Smart History Viewer", styleCentered | styleFloating)

	dbeTab = tab(dbMain, tabLabels, 690, 440, doTabSelect)
	dbeTab->"bottom"->"form"
	dbeTab->"right"->"form"

	dbeLabel = label(dbMain, "History for Object " identifier(currObj))
	dbeLabel->"top"->"inside"->dbeTab
	dbeLabel->"left"->"inside"->dbeTab

	dbeListView  = listView(dbMain, listViewOptionSortText, 650, 10, columnTitles)

	dbeListView->"top"->"spaced"->dbeLabel
    dbeListView->"left"->"inside"->dbeTab
    dbeListView->"right"->"inside"->dbeTab
    dbeListView->"bottom"->"unattached"

    dbeDetailsFrame = frame(dbMain, "Details of selected history record", 650, 100)
    dbeDetailsFrame->"top"->"spaced"->dbeListView
    dbeDetailsFrame->"left"->"inside"->dbeTab
    dbeDetailsFrame->"right"->"inside"->dbeTab
    dbeDetailsFrame->"bottom"->"unattached"

    dbeOldValue = richText(dbMain, "Old value", "", 325, 100, true)
    dbeOldValue->"top"->"inside"->dbeDetailsFrame
    dbeOldValue->"left"->"inside"->dbeDetailsFrame
    dbeOldValue->"right"->"unattached"
    dbeOldValue->"bottom"->"inside"->dbeDetailsFrame

    dbeNewValue = richText(dbMain, "New value", "", 325, 100, true)
    dbeNewValue->"top"->"inside"->dbeDetailsFrame
    dbeNewValue->"left"->"spaced"->dbeOldValue
    dbeNewValue->"right"->"inside"->dbeDetailsFrame
    dbeNewValue->"bottom"->"inside"->dbeDetailsFrame

	btnPrev = button(dbMain, "< Previous", doPrev, styleStandardSize)
    btnPrev->"top"->"spaced"->dbeDetailsFrame
    btnPrev->"left"->"inside"->dbeTab
    btnPrev->"bottom"->"inside"->dbeTab
    btnPrev->"right"->"unattached"

    // Next button
    btnNext = button(dbMain, "Next >", doNext, styleStandardSize)
    btnNext->"top"->"spaced"->dbeDetailsFrame
    btnNext->"left"->"spaced"->btnPrev
    btnNext->"bottom"->"inside"->dbeTab
    btnNext->"right"->"unattached"

	// hide the close button, but associate callback with dialog
	close(dbMain, false, doClose)
    // Help button
    ok(dbMain, "Close", doClose)
    apply(dbMain, "Help", doHelp)

	realize dbMain

	insertColumn(dbeListView, HIST_AUTHOR_COLUMN,        "Author",        120, null)
    insertColumn(dbeListView, HIST_SESSION_COLUMN,       "Session",        50, null)
    insertColumn(dbeListView, HIST_DATE_COLUMN,          "Date",          120, null)
    insertColumn(dbeListView, HIST_BASELINE_COLUMN,      "Baseline",       70, null)
    insertColumn(dbeListView, HIST_DESCRIPTION_COLUMN,   "Description",   250, null)
    insertColumn(dbeListView, HIST_RECORD_COLUMN,        "Record",         50, null)

	// associate sort callbacks with each column
	set(dbeListView, HIST_AUTHOR_COLUMN, doSortString)
	set(dbeListView, HIST_SESSION_COLUMN, doSortInteger)
	set(dbeListView, HIST_DATE_COLUMN, doSortDate)
	set(dbeListView, HIST_BASELINE_COLUMN, doSortString)
	set(dbeListView, HIST_DESCRIPTION_COLUMN, doSortString)
	set(dbeListView, HIST_RECORD_COLUMN, doSortInteger)

	setSortColumn(dbeListView, HIST_DATE_COLUMN)

	// callbacks on listview
	set(dbeListView, doSelect, doUnselect, doActivate)

	// resizing
	setExtraHeightShare(dbeListView, 1.0)
    setExtraWidthShare(dbeListView, 1.0)
    setExtraWidthShare(dbeOldValue, 0.5)
    setExtraWidthShare(dbeNewValue, 0.5)

	// load history from baselines
	if (getBaselineHistory(skip))
	{
		//printObjectHistory()

		// history loaded successfully - refresh display
		refreshDisplay()

		// It is important to reset the current module before creating the triggers
		(current ModuleRef__) = currMod

		// set up triggers for object sync
		if (!null preSyncTrigger)
		{
	        delete preSyncTrigger
	    }
	    preSyncTrigger = trigger(module->object, sync, 10, preSyncFn)

	    if (!null postSyncTrigger)
	    {
	        delete postSyncTrigger
	    }

	    postSyncTrigger = trigger(module->object, sync , 10, postSyncFn)

		show(dbMain)
	}
	else
	{
		// loading of history was cancelled by user
		hide(dbMain)
		destroy(dbMain)
		dbMain = null
	}
}

/****************************
	MAIN
****************************/
currMod = current Module
currObj = current Object

if (null currMod)
{
	infoBox("This utility can only be run from a formal module.")
	halt
}

if (null currObj)
{
	infoBox("No current Object!")
	halt
}

Skip skip = create

// lauch dialog for user to select baselines
if (!bsGetUserSelectedBaselines(currMod,
                                skip,
                                "Smart History Viewer",
                                "Please select the baselines for which you would like to view history.\n" //-
                                "Note that loading numerous baselines may take some time.",
                                true))
{
	halt
}

showHistoryDialog(skip)
Posted in Dialogs, History | Comments closed

Enhanced makeDir Function

Wrapper for mkdir that allows you to create a whole new path, not just a single directory. It also traps and reports errors generated by mkdir.

This is more useful than the builtin mkdir function that will throw a runtime error if the full path to the new directory does not already exist.

Usage:

string makeDir(string dirName)

Example:

string errors = ""
errors = makeDir("C:\\Temp\\tom\\dick\\harry")
print errors "\n"

Source code:

//  makeDir

/*
	Wrapper for mkdir that allows you to create a whole new path, not just
	a single directory.

	Usage:

		string makeDir(string dirName)

	Tony Goodman  23 June 2005
*/

/*************************************
	isDirectory

	Returns TRUE if string parameter is a valid directory.
**************************************/
bool isDirectory(string dn)
{
	Stat s = create dn

	if (null s) return false

	if (directory s)
	{
		delete s
		return true
	}
	delete s
	return false
}

/************************************
	getParentDirectory

	Returns parent directory of the given file or directory name.
*************************************/
string getParentDirectory(string fname)
{
    int i = (length fname) - 1

    while (i > 0)
    {
		if ((fname[i] == '\\') || (fname[i] == '/'))
		{
		    return fname[0:i - 1]
    	}

	    i--
    }

    return ""
}

/*************************************
	makeDir

	Creates a new directory path dPath.

	On success returns an empty string.
	On error returns an error message.
***************************************/
string makeDir(string dPath)
{
	string res     = ""
	string dParent = ""  

	// see if the directory already exists
	if (isDirectory(dPath))
	{
		return("Directory already exists!")
	}

	// get name of parent directory
	dParent = getParentDirectory(dPath)

	// check to see if parent exists
	if ((!isDirectory(dParent)) && (!null dParent))
	{
		// recurse
		res = makeDir(dParent)

	}

	if ((isDirectory(dParent)) || (dParent == null))
	{
		// parent directory exists so we can create dPath using mkdir
		// trap errors
		noError

		mkdir(dPath)

		res = lastError
	}

	return(res)
}
Posted in Files and Directories, System | Comments closed

Directory Selector

There is no built-in mechanism in DXL to create a dialog box element for capturing a directory name. This utility function provides you with functionality similar to the fileName perm, except that the selector window allows the user to select a directory rather than a file.

directoryName creates an element inside the specified dialog box for capturing a directory name. This consists of a field for the directory name and a Browse button to invoke a directory selector window. This function can be used in place of fileName whenever you want to capture a directory rather than a file.

Usage:

DBE directoryName(DB box, string label, string initial, bool readOnly)

Example:

#include "directoryName.inc"

DB db
DBE dbe

db = create("Demonstrate Directory Selector")

dbeDirectory = directoryName(db, "c:/Temp", "", false)

realize(db)
show(db)

Source code:

//  Directory Browser Facility

/*
    Directory Browser Facility.
    Adapted from Telelogic Kitchen.

    provides directoryName() which may be used in place of fileName()
    when browsing for a directory rather than a file.

    smartDXL.com
*/

DB     dnParentDialog = null

const string S_DRIVE_IS_EMPTY  = "This drive has no folders."

const string POSSIBLE_DRIVES[] = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
                                  "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"}

/************************************
	Field and Browse button that are created on the parent dialog box.
************************************/
DBE dbeBrowse         = null
DBE dbeDirectory      = null

/************************************
	Directory browser dialog
************************************/
DB  dbDirectorySelect = null
DBE dbeDirectoryTree  = null
DBE dbeDriveChoice    = null
DBE lblUserPrompt     = null
DBE dbeSelectOK       = null
DBE dbeSelectCancel   = null

string actualDrives[] = {"", "", "", "", "", "", "", "", "", "", "", "", "",
                         "", "", "", "", "", "", "", "", "", "", "", "", ""}
int numDrives = 0

string selectedDirectory = null

/************************************
	convertToBackSlashes

	Converts a directory path into a form suitable for the tree view DBE.
************************************/
string convertToBackSlashes(string s)
{
    string sRetval = null

    if (!isVoid_(s))
    {
        int i

        for (i = 0; i < length(s); i++)
        {
            sRetval = sRetval ((s[i] == '/') ? '\\' : s[i]) ""
        }
    }

    return sRetval
}

/************************************
	convertToForwardSlashes

	Converts a tree view entry into a valid directory path.
************************************/
string convertToForwardSlashes(string s)
{
    string sRetval = null

    if (!isVoid_(s))
    {
        int i

        for (i = 0; i < length(s); i++)
        {
            sRetval = sRetval ((s[i] == '\\') ? '/' : s[i]) ""
        }
    }

    return sRetval
}

/************************************
	getAvailableDrives

	Determines the list of available drives.
************************************/
int getAvailableDrives()
{
    int    cDrive  = 0
    int    i       = 0
    string sDrive  = ""
    string sErrMsg = ""

    // turn off error reporting
    noError

    // go through all possible drives
    for (i = 0; i < sizeof(POSSIBLE_DRIVES); i++)
    {
        sDrive = POSSIBLE_DRIVES[i] ":\\"

        if (sDrive == "A:\\")
        {
            // add to array
            actualDrives[numDrives++] = sDrive
        }
        else
        {
            Stat stat = create sDrive

            if (stat != null)
            {
                // this check is probably redundant
                if (directory stat)
                {
                    // add to array
                    actualDrives[numDrives] = sDrive

                    if (sDrive == "C:\\")
                    {
	                    cDrive = numDrives
                    }

                    numDrives++
                }

                delete stat
            }
        }
    }

    // turn error reporting back on
    sErrMsg = lastError

    return(cDrive)
}

/************************************
	doExpandDirectory
************************************/
bool doExpandDirectory(DBE db, string sTreeEntry)
{
	int    numSubDirs      = 0
    string s               = ""
    string sDummyEntry     = ""
    string sDirectory      = ""
    string f               = ""
	string sNewTreeEntry   = ""
	string sNewDummyEntry  = ""
	string sDriveIsEmpty   = ""
	string sErrMsg         = ""
	string sFullPath       = ""
	Stat   fStat           = null

    // convert backslashes
    sDirectory = convertToBackSlashes(sTreeEntry)

    sDummyEntry = sTreeEntry "/" dummyItem

    // turn off error reporting
    noError

    // process contents of directory
    for s in directory sDirectory do
    {
        // exclude
        if ( s == "." || s == ".." || isVoid_(s) )
        {
            continue
        }

        // get absolute location
        sFullPath = sDirectory FileSep_ s

        // it is possible to exceed max windows path if you use drive maps
        if (platform == "WIN32" && length(sFullPath) > 255)
        {
            continue
        }

        Stat stat = create sFullPath

        if (stat != null)
        {
            // only relevant for directories
            if (directory stat)
            {
                // count subdirectorys
                numSubDirs = 0

                for f in directory sFullPath do
                {
                    fStat = create sFullPath FileSep_ f

                    if (null fStat || !directory(fStat) || f == "." || f == "..")
                    {
	                    continue
                    }

                    numSubDirs++
                }

                sNewTreeEntry  = sTreeEntry "/" s
                sNewDummyEntry = sNewTreeEntry "/" dummyItem

                // check for dummy entry
                if (exists(db, sDummyEntry))
                {
                    //This entry was only added so that a '+' was displayed against a new directory (i.e. pre-expansion).
                    delete(db, sDummyEntry)
                }

                sDriveIsEmpty = sTreeEntry "/" S_DRIVE_IS_EMPTY

                // check for dummy entry
                if (exists(db, sDriveIsEmpty))
                {
                    delete(db, sDriveIsEmpty)
                }

                // only relevant if entry does not already exist
                if (!exists(db, sNewTreeEntry))
                {
                    // add to tree view
                    insert(db, sNewTreeEntry,  iconFolder, iconFolderOpen)

                    if (numSubDirs > 0)
                    {
	                    insert(db, sNewDummyEntry, iconFolder, iconFolderOpen)
                    }
                }
            }

            delete(stat)
        }
    }

    // turn error reporting back on
    sErrMsg = lastError

    return(true)
}

/************************************
	doSelectDrive
************************************/
void doSelectDrive(DBE db)
{
    string sDrive = get db

    // remove trailing slash
    if (sDrive[length(sDrive) - 1] == '\\')
    {
        sDrive = sDrive[0 : length(sDrive) - 2]
    }

    // clear existing structure
    empty(dbeDirectoryTree)

    // add drive and dummy entry
    insert(dbeDirectoryTree, sDrive, iconFolder, iconFolderOpen)
    insert(dbeDirectoryTree, (sDrive "/" S_DRIVE_IS_EMPTY), iconNone, iconNone)
}

/************************************
	doSelectOK

	Callback for dbeSelectOk
************************************/
void doSelectOK(DB db)
{
    selectedDirectory = convertToBackSlashes(get dbeDirectoryTree)

    // only relevant for root directories
    if (length(selectedDirectory) == 2)
    {
        // add trailing slash
        selectedDirectory = selectedDirectory "\\"
    }

    // update directory field on parent dialog
    set(dbeDirectory, selectedDirectory)	

    release dbDirectorySelect

}

/************************************
	doSelectCancel
************************************/
void doSelectCancel(DB db)
{
    selectedDirectory = null

    release dbDirectorySelect
}

/************************************
	doBrowse
************************************/
void doBrowse(DBE dbe)
{
	int cDriveIdx = 0

	// initialise available drives array and return index to C: drive
    cDriveIdx = getAvailableDrives()

    // Create Directory Browser dialog
    dbDirectorySelect = create(dnParentDialog, "Directory Selector", styleSubWindow)

  	// drop-down of available drives - set to drive C:\ by default
	dbeDriveChoice = choice(dbDirectorySelect, "Drive: ", actualDrives, numDrives, cDriveIdx)

    // directory tree
    dbeDirectoryTree = treeView(dbDirectorySelect, treeViewOptionSorted, 400, 15)

    close(dbDirectorySelect, true, doSelectCancel)
	apply(dbDirectorySelect, "OK", doSelectOK)

    realize dbDirectorySelect

    set(dbeDirectoryTree, doExpandDirectory)
    set(dbeDriveChoice, doSelectDrive)

    // initialise directory tree according to default drive setting
    doSelectDrive(dbeDriveChoice)

	// show the directory browser dialog
	block dbDirectorySelect
	hide dbDirectorySelect
	destroy dbDirectorySelect
}

/************************************
	directoryName
************************************/
DBE directoryName(DB     dbParent,
                  string sLabel,
                  string initDirectory,
                  bool   readOnly)
{
    // use default if parameter is null
    if (dbParent == null)
    {
        dnParentDialog = dbExplorer
    }
    else
    {
	    dnParentDialog = dbParent
	}

	// Create Field and Browse button on parent dialog
    dbeDirectory = field(dbParent, sLabel, initDirectory, 40, readOnly)
    beside(dbParent)
   	dbeBrowse = button(dbParent, "Browse...", doBrowse)
   	left(dbParent)

    // return handle on directory field dbe
    return(dbeDirectory)
}
Posted in Dialogs, Files and Directories | Comments closed

Export Attribute Values to Spreadsheet

exporters10This utility allows you to easily and quickly export the values of selected attributes for all objects to a spreadsheet file (CSV format).

//  Export Attributes to CSV File

/*
    Export Selected Attributes to CSV File.

    smartDXL.com
*/

DB      dbMain        = null
DBE     dbeAttrList   = null
DBE     dbeExport     = null
DBE     dbeExportPath = null

Module  currModule    = null
Skip    skipAttrs     = null
int     numVisible    = 0  

const  int    MAX_VISIBLE = 40    // maximal number of attributes visible in multilist
const  string dummy[]     = {}

string tempDir = getenv("TEMP")

/************************************
	getAttrs

	Fill a skip list with names of visible attributes.
*************************************/
void getAttrs()
{
	AttrDef ad = null

	skipAttrs = createString

	for ad in currModule do
	{
		if (isVisibleAttribute(ad))
		{
			put(skipAttrs, ad.name, ad)
			numVisible++
		}
	}

	// restrict the number of visible entries in the multilist
	if (numVisible > MAX_VISIBLE)
	{
		numVisible = MAX_VISIBLE
	}
}

/***************************************
	fillAttrList

	Populates a multilist with the attribute names from the skip list.

****************************************/
void fillAttrList()
{
	AttrDef ad = null
	int     i  = 0

	for ad in skipAttrs do
	{
		insert(dbeAttrList, i++, ad.name)
	}
}

/************************************
	doList
*************************************/
void doExport(DB db)
{
	int     i           = 0
	string  attr        = ""
	int     numSelected = 0
	Object  o           = null
	Stream  outFile     = null
	AttrDef      ad     = null
	AttrType     at     = null
	AttrBaseType abt    = null

	// count the number of attributes selected
    numSelected = 0
    for attr in dbeAttrList do numSelected++

    if (numSelected == 0)
    {
		infoBox("Please select some Attributes!")
		return
    }

	outFile = write(get(dbeExportPath))

	// write header row
	for attr in dbeAttrList do
	{
		outFile << "\"" attr "\","
	}

	outFile << "\n"

	// export attribute values
	for o in currModule do
	{
		for attr in dbeAttrList do
		{
			if (o.attr "" == "")
			{
				outFile << ","
			}
			else if (attr == "Object Heading")
			{
				outFile << "\"" << number(o) " " o.attr "\","
			}
			else
			{
				ad  = find(currModule, attr)
				at  = ad.type
				abt = at.type

				if (abt == attrInteger || abt == attrReal)
				{
					outFile << o.attr ","
				}
				else
				{
					outFile << "\"" << o.attr "\","
				}
			}
		}

		outFile << "\n"
	}	

	close(outFile)

	release db
}

/*********************************
	MAIN
*********************************/
currModule = current Module

if (null currModule)
{
	infoBox("This utility can only be run from a formal module.")
	halt
}

getAttrs()

dbMain = create(currModule, "Export Attributes to CSV File")

label(dbMain, "This utility exports selected attributes from the current module\n" //-
              "Output is to a CSV file.")

dbeAttrList = multiList(dbMain, "Attributes to Display:", numVisible, dummy)              

dbeExport     = field(dbMain, "Module", fullName(currModule), 50, true)
dbeExportPath = fileName(dbMain, "Report File", tempDir "\\" name(currModule) " Attributes.csv")

ok(dbMain, "Export", doExport)

realize dbMain

fillAttrList()

block(dbMain)

destroy(dbMain)
dbMain = null
Posted in Attributes, Export | Comments closed

Mini Explorer

Mini database explorer based on Telelogic’s global function fnMiniExplorer. Includes a fix for the fnMiniExplorer problem where it allows the user to select a folder even when the item filter is set to return a module. The OK button is now inactive until an item matching the filter is selected.

miniExplorer is intended to be used as a replacement for fnMiniExplorer where you want more control over what the user can select. The function is overloaded to give you a fexible range of parameter options.

Usage:

string miniExplorer([[DB dbParent,] [Folder fStart,] [int itemMask]])

Example:

DB  db
DBE dbeBrowse
DBE dbeModule

void doBrowse(DBE dbe)
{
	string mName = miniExplorer(db,
	                            current Folder,
	                            MINI_EXP_FORMAL_MODS)

	set(dbeModule, mName)
}

db = create("Demonstrate Mini Explorer")

dbeModule = field(db, "Module", "", 50, true)
beside db
dbeBrowse = button(db, "Browse...", doBrowse)

realize db
show db

Source code:

//  Enhanced Mini Database Explorer

/*
    Mini database explorer based on Telelogic builtin miniExplorer.

    Includes a fix for the builtin miniExplorer problem where it returns
    a folder name even when the item filter is set to return a formal
    module. The OK button is now inactive until an item matching the
    filter is selected.

    Usage:

    	string miniExplorer(DB dbParent, Folder fStart, int itemMask)

		string miniExplorer(DB dbParent, Folder fStart)

		string miniExplorer(Folder fStart, int itemMask)

		string miniExplorer(DB dbParent, int itemMask)   

		string miniExplorer()  

    Where:

	    	dbParent		Parent dialog box. Returns focus to this dialog
							on closing.

			fStart			Folder to open in the tree when the dialog is first
			                displayed.	

			itemMask		Mask used to filter items that are displayed.

								MINI_EXP_FP               - show folders and projects
								MINI_EXP_LINK_MODS        - show link modules
								MINI_EXP_FORMAL_MODS      - show formal modules
								MINI_EXP_DESCRIPTIVE_MODS - show descriptive modules
								MINI_EXP_SHOW_DELETED     - show deleted items

    smartDXL.com
*/

pragma runLim, 0

// item filters
const int MINI_EXP_FP                       = 1
const int MINI_EXP_LINK_MODS                = 2
const int MINI_EXP_FORMAL_MODS              = 4
const int MINI_EXP_DESCRIPTIVE_MODS         = 8
const int MINI_EXP_SHOW_DELETED             = 16

// item filters
const int MINI_EXP_SHOW_ALL_NO_DELETED      = 15
const int MINI_EXP_SHOW_ALL                 = 31

DB     dbMiniExplorer                       = null
DBE    dbeMiniExplorerTree                  = null
DBE    dbeMiniExplorerOkButton              = null

int    miniExplorerItemMask                 = MINI_EXP_FP
string miniExplorerSelectedItem             = ""

/**********************************
	itemMatchesMask
***********************************/
bool itemMatchesMask(Item itm)
{
	if (type(itm) == "Formal" && ((miniExplorerItemMask & MINI_EXP_FORMAL_MODS) == MINI_EXP_FORMAL_MODS))
	{
		return(true)
	}

	if (type(itm) == "Link" && ((miniExplorerItemMask & MINI_EXP_LINK_MODS) == MINI_EXP_LINK_MODS))
	{
		return(true)
	}

	if (type(itm) == "Descriptive" && ((miniExplorerItemMask & MINI_EXP_DESCRIPTIVE_MODS) == MINI_EXP_DESCRIPTIVE_MODS))
	{
		return(true)
	}

	return(false)
}

/************************************
	doOk
************************************/
void doOk(DB db)
{
    miniExplorerSelectedItem = getRealPath(dbSep get(dbeMiniExplorerTree))

    release(dbMiniExplorer)
    hide(dbMiniExplorer)
}

/***********************************
	doActivate
************************************/
void doActivate(DBE dbe)
{
	string sel = getRealPath(dbSep get(dbeMiniExplorerTree))

	if (itemMatchesMask(item(sel)))
	{
		miniExplorerSelectedItem = sel

		release(dbMiniExplorer)
    	hide(dbMiniExplorer)
	}
}

/**********************************
	doCancel
***********************************/
void doCancel(DB db)
{
    miniExplorerSelectedItem = ""

    release(dbMiniExplorer)
    hide(dbMiniExplorer)
}

/************************************
	doNothing
*************************************/
void doNothing(DB db)
{
	;
}

/**********************************
	addItem
************************************/
void addItem(DBE dbe, Item i)
{
    string displayPath = getDisplayPath(i)

    // check status
    if (exists(dbeMiniExplorerTree, displayPath) == false)
    {
        // check status
        if (isDeleted(i) == false || (isDeleted(i) == true && ((miniExplorerItemMask & MINI_EXP_SHOW_DELETED) == MINI_EXP_SHOW_DELETED)))
        {
            // check item type
            if (type(i) == "Folder" || type(i) == "Project")
            {
                Icon iconOpen, iconClosed
                string sDummyEntry = displayPath dbSep dummyItem

                // assign project or folder specific icons
                assignIcons(i, iconOpen, iconClosed)

                // add entry (plus dummy)
                insert(dbeMiniExplorerTree, displayPath, iconClosed, iconOpen)
                insert(dbeMiniExplorerTree, sDummyEntry, iconClosed, iconOpen)
            }
            else
            {
                if (itemMatchesMask(i))
                {
                	insert(dbeMiniExplorerTree, displayPath, getIcon(i), getIcon(i))
                }
            }
        }
    }
}

/**********************************
	displayBranch
************************************/
void displayBranch(DBE dbe, string sItemPath)
{
    Folder fStart = folder(getRealPath(sItemPath))

    if (fStart != null)
    {
        Item i

        for i in all fStart do
        {
            addItem(dbeMiniExplorerTree, i)
        }
    }
}

/**********************************
	doSelect
***********************************/
void doSelect(DBE dbe)
{
	string sel = getRealPath(dbSep get(dbeMiniExplorerTree))

	if (itemMatchesMask(item(sel)))
	{
		active(dbeMiniExplorerOkButton)
	}
	else
	{
		inactive(dbeMiniExplorerOkButton)
	}
}

/**********************************
	doExpand
************************************/
bool doExpand(DBE dbe, string sItem)
{
    string sItemPath = dbSep sItem
    string sDummyItem = sItemPath dbSep dummyItem

    // check status
    if (exists(dbeMiniExplorerTree, sDummyItem) == true)
    {
        // remove dummy
        delete(dbeMiniExplorerTree, sDummyItem)
    }

    // check status
    if (theCurrentView == DATABASE_VIEW)
    {
        // adjust view accordingly
        displayBranch(dbeMiniExplorerTree, sItemPath)
    }
    else
    {
        Project prjOldRoot = getRootProject_()

        setRootProject_(project(getRootOfPath sItemPath))

        // adjust view accordingly
        displayBranch(dbeMiniExplorerTree, sItemPath)

        setRootProject_(prjOldRoot)
    }

    return true
}

/*************************************
	fnChangeToStartFolder
**************************************/
void fnChangeToStartFolder(Folder fStart)
{
    if (!null fStart)
    {
        int iIndex

        // calculate max bound for loop
        int iFinish = length(rootName_(fStart))

        // prepare initial path
        string sFolderPath = ((theCurrentView == DATABASE_VIEW) ? dbDisplayRoot() : "")

        // process string
        for iIndex in 0 : iFinish by 1 do
        {
            // obtain character
            string sCharacter = (rootName_(fStart))[iIndex:iIndex]

            // check status
            if (sCharacter == dbSep || iIndex == iFinish)
            {
                // check status
                if (theCurrentView == PROJECT_VIEW && sFolderPath == dbSep)
                    continue

                // update explorer
                displayBranch(dbeMiniExplorerTree, sFolderPath)
            }

            sFolderPath = sFolderPath sCharacter
        }   

        // update explorer
        set(dbeMiniExplorerTree, sFolderPath)
    }
    else
    {
        // default to database level
        displayBranch(dbeMiniExplorerTree, dbDisplayRoot())
        set(dbeMiniExplorerTree, dbDisplayRoot())
    }
}

/************************************
	miniExplorer

	Provides a tree view for user to select an item from the database.

	Parameters:

		dbParent		Parent dialog box. Returns focus to this dialog
						on closing.

		fStart			Folder to open in the tree when the dialog is first
		                displayed.	

		itemMask		Mask used to filter items that are displayed. 	

	Returns fullname of selected item or an empty string.
*************************************/
string miniExplorer(DB     dbParent,
                         Folder fStart,
                         int    itemMask)
{
	string  pName = ""
    Project pRoot = null

	miniExplorerItemMask   = itemMask 

    if (null dbParent)
    {
	    dbMiniExplorer = create("smart Mini Explorer")
    }
    else
    {
    	dbMiniExplorer = create(dbParent, "smart Mini Explorer")
	}

    label(dbMiniExplorer, "Please select an item...")

    dbeMiniExplorerTree = treeView(dbMiniExplorer, treeViewOptionSorted, 400, 15)

    dbeMiniExplorerOkButton = apply(dbMiniExplorer, "OK", doOk)

	// create our own close and ok buttons
	close(dbMiniExplorer, false, doNothing)
	ok(dbMiniExplorer, "Cancel", doCancel)

    realize dbMiniExplorer

    set(dbeMiniExplorerTree, doSelect, doActivate)
    set(dbeMiniExplorerTree, doExpand)

    inactive(dbeMiniExplorerOkButton)
    // check status
    if (theCurrentView == DATABASE_VIEW)
    {
        // adjust accordingly
        insert(dbeMiniExplorerTree, dbDisplayRoot(), iconDatabase, iconDatabase)
    }
    else
    {
        pRoot = getRootProject_()
        setRootProject_(null)

        // process database
        for pName in database do
        {
            addItem(dbeMiniExplorerTree, item(dbSep pName))
        }

        setRootProject_(pRoot)
    }

    fnChangeToStartFolder(fStart)

    block(dbMiniExplorer)

    destroy(dbMiniExplorer)

    return(miniExplorerSelectedItem)
}

/*************************************
	miniExplorer

	Filter not specified
**************************************/
string miniExplorer(DB dbParent, Folder fStart)
{
	return miniExplorer(dbParent, fStart, MINI_EXP_SHOW_ALL)
}

/**************************************
	miniExplorer

	Parent dialog not specified
*************************************/
string miniExplorer(Folder fStart, int itemMask)
{
	return miniExplorer(null, fStart, itemMask)
}

/*************************************
	miniExplorer

	Current folder not specified
**************************************/
string miniExplorer(DB dbParent, int itemMask)
{
	return miniExplorer(dbParent, null, itemMask)
}

/************************************
	miniExplorer

	No parameters
************************************/
string miniExplorer()
{
	return miniExplorer(null, null, MINI_EXP_SHOW_ALL)
}           
Posted in Dialogs, Explorers | Comments closed

Colour Picker Example

dialogs15

This simple example shows how to build a colour picker as can be seen in the enumerated attribute editor.

DB  dbMain        = null
DBE dbeColourList = null

const int maxRealColour = 35

string realColourNames[maxRealColour + 1] = {} 

string realName = ""

int i = 0

for (i = 0; i &lt;= maxRealColour; i++)
{
    realColourNames[i] = getRealColourName(i)
}

dbMain = create(dbExplorer, "Colour Picker Example")

dbeColourList = listView(dbMain, 40, 200, 10, realColourNames)

realize dbMain

insertColumn(dbeColourList, 0, "Colour", 180, iconNone)

Icon theIcon
for (i = 0; i &lt;= maxRealColour; i++)
{

    theIcon = getRealColourIcon(i)
    set(dbeColourList, i, 0, theIcon)

}

show(dbMain)
Posted in Canvasses | Comments closed

Using Tabs on a Dialog Box

This complete script demonstrates how to implement tabs on your dialog box. Use this as a template to build your tab-based dialog box.

//	Example to show how to use tabs

/*

*/

const string tabStrings[] = {"Failure", "History", "Notification"}
DB box = centered "Example"
DBE theTab, Frame1, Frame2, Frame3 , theTextBox

Skip skipTabs = create    // tab skip list - holds the following frame skip lists

Skip skipFrame1 = create  // to hold elements associated with frame1
Skip skipFrame2 = create  // to hold elements associated with frame2
Skip skipFrame3 = create  // to hold elements associated with frame3

/***************************************
	tabsShow

	show all the DBEs in the skip list
****************************************/
void tabsShow(Skip skp)
{
	DBE element

   	for element in skp do
  	{
       	show element
   	}
}

/*************************************
	tabsHide

	hide all the DBEs in the skip list
*************************************/
void tabsHide(Skip skp)
{
	DBE element

   	for element in skp do
  	{
       	hide element
   	}
}

/*********************************
	showSelected
*********************************/
void showSelected(int selectedTab)
{
	int index

    Skip elementsSkip

    for elementsSkip in skipTabs do
    {
        index = (int key skipTabs)

        if (index == selectedTab)
        {
            tabsShow(elementsSkip)
        }
        else
        {
            tabsHide(elementsSkip)
        }
    }
}

void tabCb(DBE clicktab)
{
	int i = get clicktab
	showSelected(i)
}

theTab = tab(box, tabStrings, 800, 500, tabCb)
theTab->"left"->"form"
theTab->"right"->"form"
theTab->"top"->"form"
theTab->"bottom"->"form"

Frame1 = frame(box, "Test Case Details", 100, 100)
put(skipFrame1, Frame1, Frame1)
Frame1->"left"->"inside"->theTab
Frame1->"right"->"inside"->theTab
Frame1->"top"->"inside"->theTab
Frame1->"bottom"->"inside"->theTab

Frame2 = frame(box, "History", 100, 100)
put(skipFrame2, Frame2, Frame2)
Frame2->"left"->"inside"->theTab
Frame2->"right"->"inside"->theTab
Frame2->"top"->"inside"->theTab
Frame2->"bottom"->"inside"->theTab
put(skipTabs, 1, skipFrame2)

Frame3 = frame(box, "Notification", 100, 100)
put(skipFrame3, Frame3, Frame3)
Frame3->"left"->"inside"->theTab
Frame3->"right"->"inside"->theTab
Frame3->"top"->"inside"->theTab
Frame3->"bottom"->"inside"->theTab

theTextBox = text(box,"Test Case ID:",null,100,20,false)
put(skipFrame1, theTextBox, theTextBox)
theTextBox->"left"->"inside"->Frame1
theTextBox->"right"->"unattached"
theTextBox->"top"->"inside"->Frame1
theTextBox->"bottom"->"unattached"

put(skipTabs, 0, skipFrame1)  // key must match the tab index returned by get(theTab)
put(skipTabs, 1, skipFrame2)
put(skipTabs, 2, skipFrame3)  

realize box
set(theTab, 0)
showSelected(0)
show box
Posted in Dialogs | Comments closed

Chomsky Random Sentence Generator

This include file implements a utility function, getRandomText(), to return a random sentence. The sentence returned is a proper English sentence, but is of course complete jibberish. Such sentences are useful for creating test data or confusing managers.

//  Chomsky Random Sentence generator.

/*
    This file contains the following:

    A utility function, getRandomText(), to return a random sentence.
    The sentence returned is a proper English sentence, but is of course
    complete jibberish. Such sentences are useful for creating test data.

    A DOORS template for a requiremnets specification.
    Similar templates can be found in the standard DOORS installation.

    Tony Goodman
*/

	/***********************************************
		Introductory Phrases
	***********************************************/
	const string introPhrases[] = {
	"To characterize a linguistic level L, ",
	"On the other hand, ",
	"This suggests that ",
	"It appears that ",
	"Furthermore, ",
	"We will bring evidence in favor of the following thesis: ",
	"To provide a constituent structure for T(Z,K), ",
	"From C1, it follows that ",
	"For any transformation which is sufficiently diversified in application to be of any interest, ",
	"Analogously, ",
	"Clearly, ",
	"Note that ",
	"Of course, ",
	"Suppose, for instance, that ",
	"Thus ",
	"With this clarification, ",
	"Conversely, ",
	"We have already seen that ",
	"By combining adjunctions and certain deformations, ",
	"I suggested that these results would follow from the assumption that ",
	"If the position of the trace in (99c) were only relatively inaccessible to movement, ",
	"However, this assumption is not correct, since ",
	"Comparing these examples with their parasitic gap counterparts in (96) and (97), we see that ",
	"In the discussion of resumptive pronouns following (81), ",
	"So far, ",
	"Nevertheless, ",
	"For one thing, ",
	"Summarizing, then, we assume that ",
	"A consequence of the approach just outlined is that ",
	"Presumably, ",
	"On our assumptions, ",
	"It may be, then, that ",
	"It must be emphasized, once again, that ",
	"Let us continue to suppose that ",
	"Notice, incidentally, that "}

	/***********************************************
		Subject Phrases
	***********************************************/
	const string subjectPhrases[] = {
	"the notion of level of grammaticalness ",
	"a case of semigrammaticalness of a different sort ",
	"most of the methodological work in modern linguistics ",
	"a subset of English sentences interesting on quite independent grounds ",
	"the natural general principle that will subsume this case ",
	"an important property of these three types of EC ",
	"any associated supporting element ",
	"the appearance of parasitic gaps in domains relatively inaccessible to ordinary extraction ",
	"the speaker-hearer's linguistic intuition ",
	"the descriptive power of the base component ",
	"the earlier discussion of deviance ",
	"this analysis of a formative as a pair of sets of features ",
	"this selectionally introduced contextual feature ",
	"a descriptively adequate grammar ",
	"the fundamental error of regarding functional notions as categorial ",
	"relational information ",
	"the systematic use of complex symbols ",
	"the theory of syntactic features developed earlier " }

	/***********************************************
		Verb Phrases
	***********************************************/
	const string verbPhrases[] = {
	"can be defined in such a way as to impose ",
	"delimits ",
	"suffices to account for ",
	"cannot be arbitrary in ",
	"is not subject to ",
	"does not readily tolerate ",
	"raises serious doubts about ",
	"is not quite equivalent to ",
	"does not affect the structure of ",
	"may remedy and, at the same time, eliminate ",
	"is not to be considered in determining ",
	"is to be regarded as ",
	"is unspecified with respect to ",
	"is, apparently, determined by ",
	"is necessary to impose an interpretation on ",
	"appears to correlate rather closely with ",
	"is rather different from " }

	/***********************************************
		Object Phrases
	***********************************************/
	const string objectPhrases[] = {
	"problems of phonemic and morphological analysis.",
	"a corpus of utterance tokens upon which conformity has been defined by the paired utterance test.",
	"the traditional practice of grammarians.",
	"the levels of acceptability from fairly high (eg (99a)) to virtual gibberish (eg (98d)).",
	"a stipulation to place the constructions into these various categories.",
	"a descriptive fact.",
	"a parasitic gap construction.",
	"the extended c-command discussed in connection with (34).",
	"the ultimate standard that determines the accuracy of any proposed grammar.",
	"the system of base rules exclusive of the lexicon.",
	"irrelevant intervening contexts in selectional rules.",
	"nondistinctness in the sense of distinctive feature theory.",
	"a general convention regarding the forms of the grammar.",
	"an abstract underlying order.",
	"an important distinction in language use.",
	"the requirement that branching is not tolerated within the dominance scope of a complex symbol.",
	"the strong generative capacity of the theory." }

Template srsTemplate = template 	"SCOPE" <<
	"Identification" <>
	"System Overview" <>
	"Document Overview" <<
	"Definitions and Interpretation" <>
	"General Tolerance" <>
	"Units" <>
	"Deviation" <>
	"Precedence" >> 1 >>
	"APPLICABLE DOCUMENTS" <<
	"Government Documents" <<
	"US Military Specifications" <>
	"US Military Standards" <>
	"US Military Handbooks" <>
	"US Federal Standards" <>
	"UK Defence Standards" <>
	"Other government standards/specifications" >>
	"Non-Government Documents" <<
	"Buyer's Documents" <>
	"National (e.g. British) Standards" <>
	"European Standards" <>
	"Supplier's Documents" <>
	"Other Documents" >> 1 >>
	"CSCI REQUIREMENTS" <<
	"Required States and Modes" <>
	"CSCI Functional Requirements" <<
	"Capability X" <>
	"Capability Y (etc)" >>
	"External Interface Requirements" <<
	"Interface Identification and Diagrams" <>
	"External Interfaces" >>
	"Internal Interface Requirements" <>
	"Internal Data Requirements" <>
	"Adaptation Requirements" <>
	"Safety Requirements" <<
	"Flight Safety" <<
	"Identified Hazards" <>
	"Hazard Probabilities" <>
	"Design Standards" >> 1 >>
	"Security and Privacy Requirements" <>
	"CSCI Environmental Requirements" <>
	"Computer Resource Requirements" <<
	"Computer Hardware Requirements" <>
	"Computer Hardware Resource Utilisation Requirements" <>
	"Included Software Requirements" <>
	"Computer Communications Requirements" >>
	"Software Quality Factors" <>
	"Design and Implementation Constraints" <<
	"Required Programming Language" <>
	"Required Use of Design Standards/Methodology" <>
	"Required Use of Implementation Standards/Methodology" <>
	"Required Software Architecture" <>
	"Other Design Requirements" >>
	"Personnel Requirements" <<
	"Simultaneous Users" <>
	"Human Engineering" <>
	"Personnel Skill" <>
	"Training Requirements" <>
	"Logistics-related Requirements" <>
	"Packaging requirements" <>
	"Other Requirements" >> 1 >>
	"VALIDATION" <<
	"Responsibility for Validation" <>
	"Validation Cross-Reference" <>
	"Special Means of Validation" >>
	"REQUIREMENTS TRACEABILITY" <>
	"NOTES" <<
	"Abbreviations and Acronyms" <>
	"Glossary" >>
	"APPENDICES"

/******************************************************
	getPhrase
******************************************************/
string getPhrase(string phrases[])
{
	int c = 0

	c = random(sizeof(phrases))

	return(phrases1)
}

/******************************************************
	getRandomText
******************************************************/
string getRandomText()
{
	Buffer myLine = create
	int i = 0

		myLine = ""
		myLine += getPhrase(introPhrases)
		myLine += getPhrase(subjectPhrases)
		myLine += getPhrase(verbPhrases)
		myLine += getPhrase(objectPhrases)

	return(stringOf(myLine))
}
Posted in Miscellaneous | Comments closed

Handling Date Strings

Although DOORS prints dates correctly, there is no easy way to create a date string in a specified format within DXL. These utilities return date strings in long format DD Month YYYY and DD Month YYYY HH:MM respectively.

Usage:

string getDateString(Date d)
string getDateAndTimeString(Date d)

Example:

Date d = dateOf(intOf(today))

print d "\n"
print getDateString(d) "\n"
print getDateAndTimeString(d) "\n"

These functions are defined as follows:

//  Date Handling Utilities

/*
    Date Handling Utilities to return date strings in long format,
    optionally with time.

    smartDXL.com
*/

const string monthStrs[]    = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }

const string monthStrings[] = { "January", "February", "March",     "April",   "May",      "June",
                                "July",    "August",   "September", "October", "November", "December" }

Regexp hasDate = regexp "(([0-9]*)/([0-9]*)/([0-9]*))"

Regexp hasTime = regexp "(([0-9]*):([0-9]*):([0-9]*))"

/******************************************************
    getDateAndTimeString

    if incTime = TRUE, returns date and time in long format DD Month YYYY HH:MM	

    if incTime = FALSE, returns date in long format DD Month YYYY
******************************************************/
string getDateAndTimeString(Date d, bool incTime)
{
    string dateAndTime = null
    string sTime       = null
    int    iDay        = 0
    int    iMonth      = 0
    int    iYear       = 0

    dateAndTime = (dateOf(intOf(d))) ""

    if (hasDate dateAndTime)
    {
	    iDay   = intOf(dateAndTime[match 3])
	    iMonth = intOf(dateAndTime[match 2])
	    iYear  = intOf(dateAndTime[match 4])

	    iYear += (iYear >= 50 ? 1900 : 2000)
    }
    else
    {
		return("")
    }

    if (hasTime dateAndTime)
    {
		sTime = dateAndTime[match 2] ":" dateAndTime[match 3]
    }

    return(iDay " " monthStrings[iMonth - 1] " " iYear (incTime ? " " sTime : ""))
}    

/******************************************************
	getDateAndTimeString

	Returns date in long format DD Month YYYY HH:MM
******************************************************/
string getDateAndTimeString(Date d)
{
	return(getDateAndTimeString(d, true))
}

/******************************************************
	getDateString

	Returns date in long format DD Month YYYY
******************************************************/
string getDateString(Date d)
{
	return(getDateAndTimeString(d, false))
}
Posted in Dates, Strings | Comments closed

Display Colour Values

 View screenshot
This script displays the real and logical colours on a canvas together with their integer values.

Alongside each logical colour, the current real colour mapping is shown.

If you don’t want to run the DXL yourself, then just click on the image to the right to view the full size screenshot.

// Test Real Colours

/*
	Prints Real and Logical Colours on a canvas.

	Tony Goodman
*/

DB  dbMain    = null
DBE dbeCanvas = null

void doDrawCanvas(DBE cnv)
{
	int rColour = 0
	int lColour = 0
	string rName   = ""
	string lName   = ""
	int x       = 0
	int y       = 0
	int h       = 0

	realBackground(cnv, realColor_White)

	// real colours
	x = 50
	y = 50

	realColor(cnv, realColor_Black)
	font(cnv, 1, HeadingsFont)
	draw(cnv, x, y, "Real Colours")
	y = y + height(cnv, "X") + 20
	font(cnv, 3, TextFont)
	h = height(cnv, "X")

	for (rColour = 0; rColour <= 36; rColour++)
	{
		realColor(cnv, rColour)
		//draw(cnv, x + 100, y, rName)
		rectangle(cnv, x, y - h, 50, h)

		realColor(cnv, realColor_Black)
		draw(cnv, x + 60, y - 3, "" rColour ". " getRealColourName(rColour))

		y += (h + 5)
	}

	// logical colours
	x = 250
	y = 50

	realColor(cnv, realColor_Black)
	font(cnv, 1, HeadingsFont)
	draw(cnv, x, 50, "Logical Colours [Real colour mapping]")
	y = y + height(cnv, "X") + 20
	font(cnv, 3, TextFont)
	h = height(cnv, "X")

	for (lColour = 0; lColour < 64; lColour++)
	{
		rColour = getRealColour(lColour)
		if (rColour < 0 || rColour > 36)
		{
			//print("Illegal realColour for [" lColour "] " getLogicalColourName(lColour) "\n")
			continue
		}

		realColor(cnv, rColour)
		//draw(cnv, x + 100, y, rName)
		rectangle(cnv, x, y - h, 50, h)

		realColor(cnv, realColor_Black)
		draw(cnv, x + 60, y - 3, "" lColour ". " getLogicalColourName(lColour) "  [" getRealColourName(rColour) "]")

		if (lColour == 30)
		{
			y = height(cnv, "X") + 70
			x = 600
		}
		else
		{
			y += (h + 5)
		}
	}

}

dbMain = create("Real Colours")

dbeCanvas = canvas(dbMain,
                   900,
                   810,
                   doDrawCanvas)

realize dbMain

doDrawCanvas(dbeCanvas)

show dbMain
Posted in Canvasses | Comments closed