[GME-commit] GMESRC/SDK/Scripts GMETraversor.js, NONE, 1.1 GMETraversor.py, NONE, 1.1 GMETraversor.vbs, NONE, 1.1

Log messages of CVS commits gme-commit at list.isis.vanderbilt.edu
Tue Apr 15 14:10:52 CDT 2008


Update of /project/gme-repository/GMESRC/SDK/Scripts
In directory escher:/tmp/cvs-serv29995

Added Files:
	GMETraversor.js GMETraversor.py GMETraversor.vbs 
Log Message:
Traversing and filtering methods for JScript, VBScript.
Python has helper methods for Models, References, Sets and Connections.


CVS User: Zoltan Molnar, ISIS (zolmol)

--- NEW FILE: GMETraversor.js ---
//#################################################################################
//#
//#    This file contains JScript methods for project-wide traversal or query.
//#                  See bottom of the file for main()
//#
//#################################################################################
//#
//#  Visitation according to the following graph traversals algorithms
//#  _________________________________________________________________
//# 
//#  Breadth First method: Levelled
//#  Depth First methods: PreOrder, InOrder, PostOrder
//#  method names: traverse_levelled, traverse_preorder, traverse_inorder, traverse_postorder
//#  
//#  Children can be sorted during traversal by:
//#        NameSort, IDSort, GUIDSort, AspectHorizSort, AspectVerticSort, AspectAbsSort
//#  
//#################################################################################
//#
//#  Query for objects based on different criteria
//#  _____________________________________________
//#
//# filter() method: 
//#        Usable to do a project wide search based on Name, Kind, Role, ObjectType, Level.
//#        ObjectType is an enum as follows:
//#               Model = 1, 
//#               Atom = 2,
//#               Reference = 3,
//#               Connection = 4,
//#               Set = 5,
//#               Folder = 6
//#        Level (depth) can be a space-separated list of numbers or dash-separated number pairs: e.g: 1-2 5 7
//#
//# filterScoped() method:
//#        Usable to do a scoped search based on Name, Kind, Role, ObjectType, Level.
//#        Starts from a container, performs search down in its containment tree.
//#
//#################################################################################

var g, p;
g = gme
p = project

//#######################################################################
//# general helpers
//#######################################################################

function cout3( gme, mStr, mType)
{
    gme.ConsoleMessage( mStr, mType);
}

function cout( mStr, mType)
{
    g.ConsoleMessage( mStr, mType);
}

function fancy( mInStr)
{
    var fancy = "<head><style type=\"text/css\">" +
    "td.special{ background-color:aqua;font-size: 100%;margin-left: 20px;font-family: times, sans-serif, arial}" +
    "</style>" +
    "</head>" +
    "<table><tr><td class=\"special\">" +
    mInStr +
    "</td></tr></table>";
    return fancy;
}

function makeLink( o)
{
    return '<a href=mga:' + o.ID + '">' + o.Name + '</a>';
}

function coll2array( in_collection)
{
    var a = new Array();
    for( var j = 1; j <= in_collection.Count; ++j) {     // indices from 1 ... count
        a.push( in_collection.Item(j));
    }
    return a;
}


//#############################################################
// OBJTYPE_REFERENCE (3)
//#############################################################
function refersTo( r)
{
    var tgt = null;
    if( r.ObjType == 3)
        tgt = r.Referred;
       
    return tgt;
}

function setReferTo( r, o)
{
    if( r.ObjType == 3)
        r.Referred = o;
}

function referredBy( o)
{
    return coll2array( o.ReferencedBy);
}

//#############################################################
// OBJTYPE_SET (5)
//#############################################################

function isMemberIn( s, o)
{
    return s.ObjType == 5 && s.GetIsMemberDisp( o);
}

function members( s)
{
    var mems = null;
    if( s.ObjType == 5)
        mems = coll2array( s.Members);
        
    return mems;
}

function memberOfSets( o)
{
    return coll2array( o.MemberOfSets)
}

function addToSet( s, o)
{
    if( s.ObjType == 5)
        s.AddMember( o);
}

function remFromSet( s, o)
{
    if( s.ObjType == 5)
        s.RemoveMember( o);
}

//#############################################################
// OBJTYPE_CONNECTION
//#############################################################
function connect( m, srco, dsto, conn_mrole)
{
    if( m.ObjType == 1) // Model
    {
    	var c = m.CreateSimpleConn( conn_mrole, srco, dsto, null, null);
    	c.Name = conn_mrole.Name;
    }
}

function connectThruRefChain( m, srco, dsto, src_ref_chain, dst_ref_chain, conn_mrole)
{
    if( m.ObjType == 1) // Model
    {
    	var c = m.CreateSimpleConn( conn_mrole, srco, dsto, src_ref_chain, dst_ref_chain, conn_mrole);
    	c.Name = conn_mrole.Name;
    }
}

function partOfConns( o)
{
    var conn_points = coll2array( o.PartOfConns);

    var conns = new Array();
    for( i = 0; i < conn_points.length; ++i)
    {
    	conns.push( conn_points[i].Owner);
    }
    return conns;
}

//#############################################################
// OBJTYPE_MODEL (1)
//#############################################################

function metaRoleByName( m, kind_str)
{
    if( m.ObjType == 1) // Model
    {
    	return m.Meta.GetRoleByNameDisp( kind_str);
    }
    return null;
}

function metaRole( o)
{
    // it seems we don't have access to meta.dll
    // because it does return undefined
    return o.MetaRole;
}

function metaName( o)
{
    // it seems we don't have access to meta.dll
    // because it does return undefined
    return o.Meta.Name;
}

function newChild( m, kind_str)
{
    var nch = null;
    if( m.ObjType == 1)
    {
    	var mrole = metaRoleByName( m, kind_str);
    	if( null != mrole)
    	{
    	    nch = m.CreateChildObject( mrole);
    	    nch.Name = mrole.Name;
    	}
    }
    return nch;
}

function childByName( m, name_str)
{
    var ch = null;
    if( m.ObjType == 1)
    {
    	ch = m.GetChildFCODisp( name_str);
    }
    return ch;
}

function children( m)
{
    if( m.ObjType == 1)
    {
    	return coll2array( m.ChildFCOs);
    }
    return null;
}

function parent( o)
{
    if( o.ParentFolder)     return o.ParentFolder; // by checking ParentFolder first, we can use the same 
    else if( o.ParentModel) return o.ParentModel;  // implementation for folders and fcos, since folders
    else                    return null;           // have too a method named ParentFolder
}

//#######################################################################
//# transaction handlers
//#######################################################################

function begin( the_project )
{
    try {
        var terr = the_project.BeginTransactionInNewTerr(); // only on GME8
	                                                    // under GME7 please use this: g.oleit.BeginTransaction();
        return terr;
    } catch(err) {
        g.oleit.BeginTransaction();
    }
}

function commit( the_project, terr )
{
    //g.oleit.CommitTransaction();
    //if( terr != null) terr.Flush();

    the_project.CommitTransaction();

    if( terr != null) {
        cout( "Territory destroyed.", 1);
        terr.Destroy();
    }
}

function abort( the_project, terr )
{
    //g.oleit.AbortTransaction(); // from GME8 on
    //if( terr != null) terr.Flush();

    the_project.AbortTransaction();

    if( terr != null) {
        cout( "Territory destroyed.", 1);
        terr.Destroy();
    }
}


//#######################################################################
//# sorters
//#######################################################################
function sortNumber(a, b)
{
    return a - b;
}

function IDSort( x, y)
{
    if( x.ID < y.ID)       r = -1;
    else if( x.ID > y.ID)  r = 1;
    else                   r = 0;
    return r;
}

function GUIDSort( x, y)
{
    if( x.GetGUIDDisp() < y.GetGUIDDisp())       r = -1;
    else if( x.GetGUIDDisp() > y.GetGUIDDisp())  r = 1;
    else                                         r = 0;
    return r;
}

function NameSort( x, y)
{
    if( x.Name < y.Name)       r = -1;
    else if( x.Name > y.Name)  r = 1;
    else                       r = 0;
    return r;
}

//#######################################################################
//# aspect sorter helper
//#######################################################################

function getAspectPos( object, aspectname)
{
    var pos_array = object.GetRegistryValueDisp( 'PartRegs/' + aspectname + '/Position').split(',');
    var int_array = new Array( parseInt( pos_array[0]), parseInt( pos_array[1]));
    return int_array;
}

//#######################################################################
//# aspect sorters
//#######################################################################

function AspectAbsSort( a, b)
{
    /*Since objects can be placed in different aspects
    It is required for these comparators to define which
    aspect information are they going to consider.
    And since not all objects reside in a model (some sit in 
    a folder), those will throw exceptions when are asked
    about their position in a certain aspect.
    */
    var aspectname = 'SignalFlowAspect';
    try {
        var a_pos = getAspectPos( a, aspectname);
        var b_pos = getAspectPos( b, aspectname);
        var ax = a_pos[0], ay = a_pos[1];
        var bx = b_pos[0], by = b_pos[1];
    
        absa = ax * ax + ay * ay;
        absb = bx * bx + by * by;
    
        r  =  0
        if( absa < absb)         r  = -1;
        else if( absa > absb)    r  =  1;
        else                     r  = IDSort( a, b);
    
        return r;
    }
    catch(err) {
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectAbsSort, Message = ' + err.message, 1)
        return IDSort( a, b)
    }
}
    
function AspectHorizSort( a, b)
{
    var aspectname = 'SignalFlowAspect';
    try {
        // get pairs of coordinates like "86, 86"
        var a_pos = getAspectPos( a, aspectname);
        var b_pos = getAspectPos( b, aspectname);
        var ax = a_pos[0], ay = a_pos[1];
        var bx = b_pos[0], by = b_pos[1];

        r  =  0;
        if( ax < bx)        r = -1;
        else if(ax > bx)    r = 1;
        else if(ay < by)    r = -1;
        else if(ay > by)    r = 1;
        else                r = 0;

        return r;
    }
    catch(err) {
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectHorizSort, Message = ' + err.message, 1);
        return IDSort( a, b)
    }
}

function AspectVerticSort( a, b)
{
    var aspectname = 'SignalFlowAspect';
    try {
        // get pairs of coordinates like "86, 86"
        var a_pos = getAspectPos( a, aspectname);
        var b_pos = getAspectPos( b, aspectname);
        var ax = a_pos[0], ay = a_pos[1];
        var bx = b_pos[0], by = b_pos[1];

        r  =  0;
        if( ay < by)        r = -1;
        else if(ay > by)    r = 1;
        else if(ax < bx)    r = -1;
        else if(ax > bx)    r = 1;
        else                r = 0;

        return r;
    }
    catch(err) {
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectVerticSort, Message = ' + err.message, 1);
        return IDSort( a, b);
    }
}

function handle( o)
{
	cout( o.GetGUIDDisp() + " ~ " + o.ID + " ~ " + o.Name, 1);
	//cout( "Handled", 2);
}


//#######################################################################
//# traversal algorithms
//#######################################################################

function traverse_postorder( currento, comparator)
{
    // 1st: traverse subtrees
    if( currento.ObjType == 1 || currento.ObjType == 6)                  // children for Models and Folders
    {
        var to_visit = coll2array( currento.ChildObjects);
        to_visit.sort( comparator);                                      // sorted with comparator

        for( var oi = 0; oi < to_visit.length; ++oi) 
        {
            traverse_postorder( to_visit[oi], comparator);
        }
    }
    
    // 2nd: handle current node
    handle( currento);
}

function traverse_preorder( currento, comparator)
{
    // 1st: handle current node
    handle( currento);

    // 2nd: traverse subtrees
    if( currento.ObjType == 1 || currento.ObjType == 6)                  // children for Models and Folders
    {
        var to_visit = coll2array( currento.ChildObjects);
        //to_visit.sort( comparator);                                    // sorted with comparator

        for( var oi = 0; oi < to_visit.length; ++oi)
        {
           traverse_preorder( to_visit[oi], comparator);
        }
    }
}    

function traverse_inorder( currento, comparator)
{
    var to_visit = new Array();
    var separate_at = 0;
    var i = 0;
    
    if( currento.ObjType == 1 || currento.ObjType == 6)                // children for Models and Folders
    {
        to_visit = coll2array( currento.ChildObjects);
        to_visit.sort( comparator);                                    // sorted with comparator

        separate_at = Math.floor( (1 + to_visit.length)/2);            // element at separate_at will be in right children
                                                                       // leftchildren need visitation before the current node
                                                                       // rightchildren need visitation after the current node
                                                                       // we figure out an index (separate_at) to split the list in 2
    }

    // 1st: traverse left children
    //cout( "Left: from " + i + " to " + separate_at, 2);
    for( i = 0; i < separate_at; ++i) {
        traverse_inorder( to_visit[i], comparator);
    }

    // 2nd: handle current node
    handle( currento);
    
    // 3rd: traverse right children
    //cout( "Right: from " + separate_at + " to " + to_visit.length, 2);
    for( i = separate_at; i < to_visit.length; ++i) {
        traverse_inorder( to_visit[i], comparator);
    }
}    


function traverse_levelled( rootfolder, cmp)      //  ' aka BFT, Breadth First Traversal
{                                                        //  ' non-recursive implementation with a fifo queue
    var to_visit = new Array( rootfolder);
    var i = 0;
    while( i < to_visit.length)
    {
        var o = to_visit[i];
        handle( o);
        if( o.ObjType == 1 || o.ObjType == 6)
        {
            // convert childobjects into an array
            var to_append = coll2array( o.ChildObjects);
            
            //
            // sort children
            to_append.sort( cmp);
            
            //
            // append to the queue
            to_visit = to_visit.concat( to_append);
        }
        ++i;
    }
}

function filter( oname, okind, orole, otype, level)
{
    var flt = p.CreateFilter();
    flt.Name = oname;
    flt.Kind = okind;
    flt.Role = orole;
    flt.ObjType = otype;
    flt.Level = level;
    var res = p.AllFCOs( flt);                                                // filter used project-wide
    cout( "Results follow: ", 1);
    for( var i = 1; i <= res.Count; ++i)
       cout( res.Item(i).Name + " -> " + makeLink( res.Item(i)), 1);

    return coll2array( res);
}

function filterScoped( scopeObject, oname, okind, orole, otype, level)
{
    var flt = p.CreateFilter();
    flt.Name = oname;
    flt.Kind = okind;
    flt.Role = orole;
    flt.ObjType = otype;
    flt.Level = level;
    var res = scopeObject.GetDescendantFCOs( flt);                            // filter used only down under container object in the hierarchy tree
    cout( "Results follow: ", 1);
    for( var i = 1; i <= res.Count; ++i)
       cout( res.Item(i).Name + " -> " + makeLink( res.Item(i)), 1);

    return coll2array( res);
}

function testFilter()
{
  var r1;
  r1 = filter( "", "Model", "", "", "");                           // kind based filtering
  r1 = filterScoped( it.MgaModel, "", "Model", "", "", "");
  
  for( var k = 0; k < r1.length; ++k)
     cout( makeLink(r1[k]), 3);
}


function traverse()
{
    var algo_text = new Array();
    algo_text[traverse_preorder  ] = 'Preorder traversal';         // dictionary, will help showing to the user which traversal is used
    algo_text[traverse_postorder ] = 'Postorder traversal';
    algo_text[ traverse_inorder  ] = 'Inorder traversal';
    algo_text[ traverse_levelled ] = 'Levelled traversal (BFS)';

    var sort_text = new Array();
    sort_text[ AspectAbsSort    ] = 'Absolute Position';           // dictionary, will help showing to the user which sort is used
    sort_text[ AspectHorizSort  ] = 'Horizontal Position';
    sort_text[ AspectVerticSort ] = 'Vertical Position';
    sort_text[ NameSort         ] = 'Name';
    sort_text[ GUIDSort         ] = 'GUID';
    sort_text[ IDSort           ] = 'ID';


    //#-----------------------------------
    //# select the sort criteria here
    //#-----------------------------------
    var used_sort = AspectAbsSort;

    //#-----------------------------------
    //# select traversal algorithm here
    //#-----------------------------------
    var used_algo = traverse_levelled;

    cout( fancy('Examining project \'' + p.RootFolder.Name + '\' with ' + algo_text[used_algo] + ' method, sorting children by their ' + sort_text[ used_sort] + '.'), 1)


    cout( "Traversing " + p.RootFolder.Name, 1);
    used_algo( p.RootFolder, used_sort);
    // or simply:
    //traverse_levelled( p.RootFolder, IDSort);
    //traverse_preorder( p.RootFolder, IDSort);
    //traverse_postorder(p.RootFolder, IDSort);
    //traverse_inorder(  p.RootFolder, IDSort);
}


//#######################################################################
//# main
                     
cout( fancy("--Greetings!--"), 1);
cout( "Hello World, this is JScript here!", 1);

var terr = begin(p);

try {
    traverse();
    //testFilter();

    commit( p, terr);
}
catch(err) {
    cout( "Exception [" + err.message + "]. Transaction will abort.", 3);
    abort( p, terr);
}

cout( "Bye, bye!", 1);

--- NEW FILE: GMETraversor.vbs ---
'//#################################################################################
'//#
'//#    This file contains VBScript methods for project-wide traversal or query.
'//#                  See bottom of the file for main()
'//#
'//#################################################################################
'//#
'//#  Visitation according to the following graph traversals algorithms
'//#  _________________________________________________________________
'//# 
'//#  Breadth First method: Levelled
'//#  Depth First methods: PreOrder, InOrder, PostOrder
'//#  method names: traverse_levelled, traverse_preorder, traverse_inorder, traverse_postorder
'//#  
'//#  Children can be sorted during traversal by:
'//#        NameSort, IDSort, GUIDSort, AspectHorizSort, AspectVerticSort, AspectAbsSort
'//#  
'//#################################################################################
'//#
'//#  Query for objects based on different criteria
'//#  _____________________________________________
'//#
'//# filter() method: 
'//#        Usable to do a project wide search based on Name, Kind, Role, ObjectType, Level.
'//#        ObjectType is an enum as follows:
'//#               Model = 1, 
'//#               Atom = 2,
'//#               Reference = 3,
'//#               Connection = 4,
'//#               Set = 5,
'//#               Folder = 6
'//#        Level (depth) can be a space-separated list of numbers or dash-separated number pairs: e.g: 1-2 5 7
'//#
'//# filterScoped() method:
'//#        Usable to do a scoped search based on Name, Kind, Role, ObjectType, Level.
'//#        Starts from a container, performs search down in its containment tree.
'//#
'//#################################################################################

Set g = gme
Set p = project

Sub cout3( gme, mStr, mType)
    gme.ConsoleMessage mStr, mType
End Sub

Sub cout( mStr, mType)
    g.ConsoleMessage mStr, mType
End Sub

Function fancy( mInStr)
    fancy = "<head><style type=""text/css"">" &_
    "td.special{ background-color:aqua;font-size: 100%;margin-left: 20px;font-family: times, sans-serif, arial}" &_
    "</style>" &_
    "</head>" &_
    "<table><tr><td class=""special"">" &_
    mInStr &_
    "</td></tr></table>"
End Function

Function makeLink( o)
    makeLink = "<a href=mga:" & o.ID & """>" & o.Name & "</a>" 
End Function

'********************************************************************


Sub begin( the_project )
	the_project.BeginTransaction Nothing
End Sub

Sub commit( the_project )
	the_project.CommitTransaction
End Sub

Sub abort( the_project )
	the_project.AbortTransaction
End Sub

'********************************************************************

Sub handle( o)
	msg = o.ID & " ~ " & o.GetGUIDDisp() & " ~ " & o.Name
	cout msg, 1
End Sub

'********************************************************************

Sub traverse_preorder( currento)
    ' 1st: handle current node
    Call handle( currento)
    
    ' 2nd: traverse subtrees
    If  currento.ObjType = 1 or currento.ObjType = 6 Then              ' children for Models and Folders
	Set to_visit = currento.ChildObjects
	'Call sortMyArray( to_visit)                                      ' sorted with comparator

        For k = 1 to to_visit.Count
		traverse_preorder( to_visit(k))
	Next
    End If
End Sub

Sub traverse_postorder( currento)
    ' 1st: traverse subtrees
    If  currento.ObjType = 1 or currento.ObjType = 6 Then              ' children for Models and Folders
	Set to_visit = currento.ChildObjects
	'Call sortMyArray( to_visit)                                      ' sorted with comparator

        For k = 1 to to_visit.Count
		traverse_postorder( to_visit(k))
	Next
    End If
    
    ' 2nd: handle current node
    Call handle( currento)
End Sub

Sub traverse_inorder( currento)

    current_len = 0
    Dim to_visit()

    If  currento.ObjType = 1 or currento.ObjType = 6 Then              ' children for Models and Folders
	Set children = currento.ChildObjects
	ReDim Preserve to_visit( children.Count)
	
	' append the children to the to_visit list
	For k = 1 to children.Count
		Set to_visit(current_len) = children(k)
		current_len = current_len + 1
	Next

	'Call sortMyArray( to_visit)                                      ' sorted with comparator
    End If

    separate_at = current_len\2                                        ' trunc logic: [0..2], current len = 3, separate at = 1
                                                                       ' elem at index separate_at is in right children

    ' 1st: traverse left children
    k = 0
    While k < separate_at
	traverse_inorder( to_visit(k))
	k = k + 1
    Wend
    
    ' 2nd: handle current node
    Call handle( currento)

    ' 3rd: traverse right children
    While k < current_len
	traverse_inorder( to_visit(k))
	k = k + 1
    Wend
End Sub

Sub traverse_levelled( rootfolder)                ' aka BFT, Breadth First Traversal, with a FIFO queue logic
	Dim to_visit()

	current_len = 1
	ReDim to_visit( current_len)
	Set to_visit(0) = rootfolder

	i = LBound(to_visit)
	While i < current_len
		Set o = to_visit(i)
		Call handle( o)                   ' handle the currently selected object
		                                  '
		If o.ObjType = 1 or o.ObjType = 6 Then
			Set children = o.ChildObjects
			' cout "Combined size will be : " & current_len + children.Count, 1
			ReDim Preserve to_visit( current_len + children.Count)
			
			' append the children to the to_visit list
			For k = 1 to children.Count
				Set to_visit(current_len) = children(k)
				current_len = current_len + 1
			Next
		End If
		i = i + 1
	Wend
End Sub

'********************************************************************

Function filter( fname, fkind, frole, otype, level)
    Set flt = p.CreateFilter()
    cout flt.Project.RootFolder.Name, 3
    flt.Name = fname
    flt.Kind = fkind
    flt.Role = frole
    flt.ObjType = otype
    flt.Level = level
    Set res = p.AllFCOs( flt)                                                ' filter used project-wide
    cout "Results follow: ", 1
    For i = 1 to res.Count
       cout res.Item(i).Name & " -> " & makeLink( res.Item(i)), 1
    Next
    Set filter = res
End Function

Function filterScoped( object, fname, fkind, frole, otype, level)
    Set flt = p.CreateFilter()
    flt.Name = fname
    flt.Kind = fkind
    flt.Role = frole
    flt.ObjType = otype
    flt.Level = level
    Set res = object.GetDescendantFCOs( flt)                                 ' filter used only down below container object in the hierarchy tree
    cout "Results follow: ", 1
    For i = 1 to res.Count
       cout res.Item(i).Name & " -> " & makeLink( res.Item(i)), 1
    Next
    Set filterScoped = res
End Function

'********************************************************************

Sub test1( m)
     'Call filter( "", "ModelProxy", "", "", "")
     'Call filterScoped( it.MgaModel, "", "ModelProxy", "", "", "")
     Set fres1 = filter( "", "Model", "", "", "")
     Set fres2 = filterScoped( it.MgaModel, "", "Model", "", "", "")
     cout "Filtered results follow", 2
     For i = 1 to fres2.Count
        cout makeLink( fres2.Item(i)), 2
     Next
     
    
End Sub

'********************************************************************
'* main


On Error Resume Next ' turn off default error handler but only on this level (not in subs)
                     ' On Error GoTo 0 ' turn on default error handler
                     ' The saying is, that it works like SEH (Structured Exception Handling)
                     ' Errors are propagated up in the stack, until somebody handles it
                     ' in our case, somebody has a 'Resume Next' cmd and handles it
                     


cout fancy("--Greetings!--"), 1
cout "Hello World, this is VBScript here!", 1

Call begin( p)

cout p.RootFolder.Name, 1
'Call traverse_levelled( p.RootFolder)
'Call traverse_postorder( p.RootFolder)
'Call traverse_preorder( p.RootFolder)
'Call traverse_inorder( p.RootFolder)
test1 it.mgamodel
Call commit( p)

If Err.Number <> 0 Then   ' "Exception handling"
	Call abort( p)
End If

--- NEW FILE: GMETraversor.py ---
#################################################################################
#
#     This file contains Python methods for project-wide traversal or query.
#     In addition it has helper methods for Model, Set, Reference objects.
#                   See bottom of the file for main()
#
#################################################################################
#
#  Visitation according to the following graph traversals algorithms
#  _________________________________________________________________
#
#  Breath First method: Levelled
#  Depth First methods: PreOrder, InOrder, PostOrder
#  method names: traverse_levelled, traverse_preorder, traverse_inorder, traverse_postorder
#
#  Children can be sorted during each traversal by:
#        NameSort, IDSort, GUIDSort, AspectHorizSort, AspectVerticSort, AspectAbsSort
#
#
#################################################################################
#
#  Query for objects based on different criteria
#  _____________________________________________
#
#
# filter() method: 
#        Usable to do a project wide search based on Name, Kind, Role, ObjectType, Level.
#        ObjectType is an enum as follows:
#               Model = 1, 
#               Atom = 2,
#               Reference = 3,
#               Connection = 4,
#               Set = 5,
#               Folder = 6
#        Level (depth) can be a space-separated list of numbers or dash-separated number pairs: e.g: 1-2 5 7
#
# filterScoped() method:
#        Usable to do a scoped search based on Name, Kind, Role, ObjectType, Level.
#        Starts from a container, performs search down in its containment tree.
#
#################################################################################
#
# Helper methods for different object types useable as follows
# ____________________________________________________________
#
# Models:
#        MetaRoleObject = metaRoleByName( Model, KindString)
#        MetaRoleObject = metaRole( Object)
#        MetaNameString = metaName( Object)
#        NewChild = newChild( Model, KindString)
#        ClonedObject = clone( WhereModel, WhichObject)
#        delObj( Object)
#        ChildObject = childByName( Model, Name)
#        ListOfChildren = childrenByKind( Model, KindString)
#        ListOfChildren = children( Model)
#        Parent = parent( Object)
# Connections:
#        NewConn = connect( Model, Source, Destination, ConnectionMetaRole)
#        NewConn = connectThruRefChain( Model, Source, Destination, SourceReferenceChain, DestinationReferenceChain, ConnectionMetaRole)
#        ListOfConns = partOfConns( Object)
# References:
#        Tgt = getReferred( Ref)
#        setReferred( Ref, Tgt)
#        clearReference( Ref)
#        ListOfRefs = referredBy( Tgt)
# Sets:
#        T/F = isMemberIn( Set, Member)
#        ListOfMembers = members( Set)
#        ListOfSets = memberOfSets( Member)
#        addToSet( Set, Member)
#        remFromSet( Set, Member)
#
#################################################################################

import win32com.client

p = project                                                 # pre-existing variable defined, implements IMgaProject interface (see Interfaces/Mga.idl)
g = gme                                                     # pre-existing variable defined, implements IGMEOLEApp interface  (see Interfaces/GME.idl)



#############################################################
## OBJTYPE_REFERENCE (3)
#############################################################
def getReferred( r):
    if( r and r.ObjType == 3):
        return r.Referred
    return

def setReferred( r, o):
    if( r and r.ObjType == 3):
        r.Referred = o
    return

def clearReference( r):
    """ Clears a reference's Referred property.
        r.Referred = 0 does not work unfortunately
    """
    if r.ObjType == 3:
        try:
            r.ClearRef()                 # from GME8 on
        except:
            cout( "Exception while clearing reference: " + r.Name + "!", 3)
            raise
    return
    
def referredBy( o):
    return list( o.ReferencedBy)

#############################################################
## OBJTYPE_SET (5)
#############################################################

def isMemberIn( s, o):
    # GetIsMemberDisp is not giving back correct results:
    #return s.ObjType == 5 and s.GetIsMemberDisp( o)
    # that's why an alternative implementation is used:
    #s.GetIsMemberDisp( o)
    return o in members(s)

def members( s):
    if( s and s.ObjType == 5):
        return list( s.Members)
    return

def memberOfSets( o):
    return list(o.MemberOfSets)

def addToSet( s, o):
    if( s and s.ObjType == 5):
        s.AddMember( o)


def remFromSet( s, o):
    if( s and s.ObjType == 5):
        s.RemoveMember( o)

#############################################################
## OBJTYPE_CONNECTION
#############################################################

def connect( m, srco, dsto, conn_mrole):
    if( m.ObjType == 1):        # Model
    	c = m.CreateSimpleConn( conn_mrole, srco, dsto, None, None)
    	c.Name = conn_mrole.Name
    	return c
    return

def connectThruRefChain( m, srco, dsto, src_ref_chain, dst_ref_chain, conn_mrole):
    if( m.ObjType == 1):        # Model
    	c = m.CreateSimpleConn( conn_mrole, srco, dsto, src_ref_chain, dst_ref_chain)
    	c.Name = conn_mrole.Name
    	return c
    return

def partOfConns( o):
    conn_points = list( o.PartOfConns)
    conns = []
    for i in range(0, len(conn_points)):
    	conns.append( conn_points[i].Owner)
    return conns

#############################################################
## OBJTYPE_MODEL (1)
#############################################################

def metaRoleByName( m, kind_str):
    if m.ObjType == 1:             # Model
    	return m.Meta.GetRoleByNameDisp( kind_str)
    #return null

def metaRole( o):
    return o.MetaRole

def metaName( o):
    return o.Meta.Name

def newChild( m, kind_str):
    if m.ObjType == 1:
    	mrole = metaRoleByName( m, kind_str)
    	if mrole:
    	    nch = m.CreateChildObject( mrole)
    	    nch.Name = mrole.Name
    	    return nch
    return

def clone( m, orig):
    """ Clones orig object into m (model or folder).
        If orig is a folder, m needs to a folder too.
    """
    if m.ObjType not in (1, 6): return
    if not orig:                return
    
    if m.ObjType == 6:                                            # Target is a Folder
        if orig.ObjType == 6: cloned = m.CopyFolderDisp( orig)    # Orig is Folder too
        else:                 cloned = m.CopyFCODisp( orig)       # Orig is FCO
    elif m.ObjType == 1:
        cloned = m.CopyFCODisp( orig, metaRole( orig))            # Target is Model, Orig is FCO
    
    if cloned:
    	cloned.Name = "Cloned" + orig.Name
    return cloned
    
def delObj( o):
    """ Deletes an object o from its parent
    """
    if not o: return
    try:
        o.DestroyObject()
    except:
        cout( "Could not remove object '" + o.Name + "'!")
        raise                                                            # raise again the same exception
    return

def childByName( m, name_str):
    if m.ObjType == 1:
    	return m.GetChildFCODisp( name_str)
    return

def childrenByKind( m, kind_str):
    if m.ObjType == 1:
        return list(m.GetChildrenOfKind( kind_str))
    return

def children( m):
    if m.ObjType == 1:
    	return list(m.ChildFCOs)
    return

def parent( o):
    if   o.ParentFolder                   :    return o.ParentFolder     # by checking ParentFolder first, we can use the same 
    elif o.ObjType != 6 and o.ParentModel :    return o.ParentModel      # implementation for folders and fcos, since folders
                                                                         # have too a method named ParentFolder
    return

#######################################################################
# filter on project
#######################################################################

def filter( name = "", kind = "", role = "", otype = "", level = ""):
    flt = p.CreateFilter()
    flt.Name = name
    flt.Kind = kind
    flt.Role = role
    flt.ObjType = otype
    flt.Level = level
    res = p.AllFCOs( flt)                                                # filter used project-wide
    cout( "Results follow: ", 1)
    for i in range(1, res.Count + 1):
       cout( res.Item(i).Name + " -> " + makeLink( res.Item(i)), 1)

    return list(res)

def filterScoped( object, name = "", kind = "", role = "", otype = "", level = ""):
    flt = p.CreateFilter()
    flt.Name = name
    flt.Kind = kind
    flt.Role = role
    flt.ObjType = otype
    flt.Level = level
    res = object.GetDescendantFCOs( flt)                                 # filter used only down below container object in the hierarchy tree
    cout( "Results follow: ", 1)
    for i in range(1, res.Count + 1):
       cout( res.Item(i).Name, 1)

    return list(res)

#######################################################################
# transaction handlers
#######################################################################

def begin( p_project ):
    # alt1: return project.BeginTransactionInNewTerr()   # only in GME8
    # alt2: project.BeginTransaction( project.CreateTerritory( None, None, None))
    #   or more verbosely:
    terr = p_project.CreateTerritory( None, None, None)
    p_project.BeginTransaction( terr)
    return terr

def commit( p_project, p_terr ):
    p_project.CommitTransaction()

    if p_terr:
       p_terr.Destroy()

def abort( p_project, p_terr ):
    p_project.AbortTransaction()

    if p_terr:
       p_terr.Destroy()


#######################################################################
# general helpers
#######################################################################

def cout3( _gme, _msg, _type = 1):
    _gme.ConsoleMessage( _msg, _type)

def cout( _msg, _type = 1):
    gme.ConsoleMessage( _msg, _type)

def fancy( _inStr):
    """ Encloses incoming string into a html table cell, so 
        that it will be shown with custom fgcolor and bgcolor
    """
    return '<head><style type="text/css">td.special{ background-color:aqua;font-size: 100%;margin-left: 20px;font-family: times, sans-serif, arial}</style></head><table><tr><td class="special">' + _inStr + '</td></tr></table>'

def fancy2( _inStr):
    return '<p style="background-color: yellow">' + _inStr + '</p>'

def makeLink( o):
    return '<a href=mga:' + o.ID + '">' + o.Name + '</a>' 

#######################################################################
# sorters
#######################################################################

def IDSort( x, y):
    if( x.ID < y.ID):   r = -1
    elif( x.ID > y.ID): r = 1
    else:               r = 0
    return r

def GUIDSort( x, y):
    if( x.GetGUIDDisp() < y.GetGUIDDisp()):   r = -1
    elif( x.GetGUIDDisp() > y.GetGUIDDisp()): r = 1
    else:                                     r = 0
    return r

def NameSort( x, y):
    if( x.Name < y.Name):   r = -1
    elif( x.Name > y.Name): r = 1
    else:                   r = 0
    return r

#######################################################################
# aspect sorter helper
#######################################################################

def getAspectPos( object, aspectname):
    str_ax,str_ay = object.GetRegistryValueDisp( 'PartRegs/' + aspectname + '/Position').split(',')
    return int(str_ax), int(str_ay)

#######################################################################
# aspect sorters
#######################################################################

def AspectAbsSort( a, b):
    """ Since objects can be placed in different aspects
    It is required for these comparators to define which
    aspect information are they going to consider.
    And since not all objects reside in a model (some sit in 
    a folder), those will throw exceptions when are asked
    about their position in a certain aspect.
    """
    aspectname = 'SignalFlowAspect'
    try:
        ax, ay = getAspectPos( a, aspectname)
        bx, by = getAspectPos( b, aspectname)
    
        absa = ax * ax + ay * ay;
        absb = bx * bx + by * by;
    
        r  =  0
        if( absa < absb)   :  r  = -1
        elif( absa > absb) :  r  =  1
        else               :  r  = IDSort( a, b)
    
        return r
    except:
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectAbsSort', 1)
        return IDSort( a, b)
    
def AspectHorizSort( a, b):
    aspectname = 'SignalFlowAspect'
    try:
        # get pairs of coordinates like "86, 86"
        ax, ay = getAspectPos( a, aspectname)
        bx, by = getAspectPos( b, aspectname)

        r  =  0
        if( ax < bx)   : r = -1
        elif(ax > bx)  : r = 1
        elif(ay < by)  : r = -1
        elif(ay > by)  : r = 1
        else           : r = 0

        return r
    except:
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectHorizSort', 1)
        return IDSort( a, b)

def AspectVerticSort( a, b, aspectname = 'SignalFlowAspect'):
    try:
        # get pairs of coordinates like "86, 86"
        ax, ay = getAspectPos( a, aspectname)
        bx, by = getAspectPos( b, aspectname)

        r  =  0
        if( ay < by)   : r = -1
        elif(ay > by)  : r = 1
        elif(ax < bx)  : r = -1
        elif(ax > bx)  : r = 1
        else           : r = 0

        return r
    except:
        cout( 'Exc during comparing ' + a.Name + ' with ' + b.Name + ' in AspectVerticSort', 1)
        return IDSort( a, b)

        
#######################################################################
# a generic handler for a visited object (fco or folder)
#######################################################################

def handle( _gme, _obj):
    try: 
        cout( _obj.ID + ' ~ ' + _obj.GetGUIDDisp() + ' ~ ' + _obj.Name)
    finally:
        pass
    # 
    # or dump data to a file:
    #
    #f = open( 'c:\\visitation.txt', 'a')
    #try: 
    #    f.write( _obj.ID + '~' + _obj.GetGUIDDisp() + '~' + _obj.Name + '\n')
    #finally:
    #    f.close()

    return    

#######################################################################
# traversal algorithms
#######################################################################

def traverse_postorder( _gme, _current, _comparator):
    to_visit = []                                   # a list (!tuple)

    if _current.ObjType in (1, 6):                  # children for Models and Folders
        to_visit.extend( _current.ChildObjects)     # remains a list
        to_visit.sort( cmp = _comparator)           # which can sort

    # 1st: traverse subtrees
    for o in to_visit:
        traverse_postorder( _gme, o, _comparator)
    
    # 2nd: handle current node
    handle( _gme, _current)

    return

def traverse_preorder( _gme, _current, _comparator):
    to_visit = []                                   # a list (!tuple)

    if _current.ObjType in (1, 6):                  # children for Models and Folders
        to_visit.extend( _current.ChildObjects)     # remains a list
        to_visit.sort( cmp = _comparator)           # which can sort

    # 1st: handle current node
    handle( _gme, _current)

    # 2nd: traverse subtrees
    for o in to_visit:
        traverse_preorder( _gme, o, _comparator)

    return

def traverse_inorder( _gme, _current, _comparator):
    to_visit = []                                   # a list (!tuple)

    if _current.ObjType in (1, 6):                  # children for Models and Folders
        to_visit.extend( _current.ChildObjects)     # remains a list
        to_visit.sort( cmp = _comparator)           # which can sort
    
    separate_at = (1 + len(to_visit))/2             # element at separate_at will be in right children
                                                    # leftchildren need visitation before the current node
                                                    # rightchildren need visitation after the current node
                                                    # we figure out an index (separate_at) to split the list in 2

    # 1st: traverse left children
    for i in range( 0, separate_at):
        traverse_inorder( _gme, to_visit[i], _comparator)

    # 2nd: handle current node
    handle( _gme, _current)
    
    # 3rd: traverse right children
    for i in range( separate_at, len(to_visit)):
        traverse_inorder( _gme, to_visit[i], _comparator)

    return
    
def traverse_levelled( _gme, _rootfolder, _comparator):            # aka BFT, Breadth First Traversal with a fifo queue
    to_visit = []                                   # a list (!tuple)
    to_visit.append( _rootfolder)
    
    while len( to_visit) > 0:
        o = to_visit.pop(0)                         # pops the first element from the queue
        handle( _gme, o)                            # handle current node
        
        if o.ObjType in (1, 6):                     # children for Models and Folders
            children = list( o.ChildObjects)        # only a list
            children.sort( cmp = _comparator)       # can be sorted
            to_visit.extend( children)              # append children to the fifo queue
    
    return

def traverse_invoker( _methodFunc, _gme, _rootFolder, _comparatorFunc):
    _methodFunc( _gme, _rootFolder, _comparatorFunc)               # simple call the _methodFunc with the provided parameters
    return

#######################################################################
#
#  Visitation according to the following graph traversals algorithms
#
#
#  Depth First methods: PreOrder, InOrder, PostOrder
#  Breath First method: Levelled
#
#  Children can be sorted during each traversal by:
#  Name                                               : NameSort
#  ObjectID (as strings)                              : IDSort
#  GUID (as strings, as in the displayed format)      : GUIDSort
#  Horizontal Position (in a certain aspect)          : AspectHorizSort
#  Vertical   Position (in a certain aspect)          : AspectVerticSort
#  Absolute Distance from (0,0) (in a certain aspect) : AspectAbsSort
#

def traverse():
    algo_text={ traverse_preorder  : 'Preorder traversal'          # dictionary, will help showing to the user which traversal is used
              , traverse_postorder : 'Postorder traversal'
              , traverse_inorder   : 'Inorder traversal'
              , traverse_levelled  : 'Levelled traversal (BFS)'}

    sort_text={ AspectAbsSort      : 'Absolute Position'           # dictionary, will help showing to the user which sort is used
              , AspectHorizSort    : 'Horizontal Position'
              , AspectVerticSort   : 'Vertical Position'
              , NameSort           : 'Name'
              , GUIDSort           : 'GUID'
              , IDSort             : 'ID'}

    #-----------------------------------
    # select the sort criteria here
    #-----------------------------------
    used_sort = NameSort
    
    #-----------------------------------
    # select traversal algorithm here
    #-----------------------------------
    used_algo = traverse_levelled

    cout( fancy('Examining project \'' + p.RootFolder.Name + '\' with ' + algo_text[used_algo] + ' method, sorting children by their ' + sort_text[ used_sort] + '.'), 1)

    #-----------------------------------
    traverse_invoker( used_algo, g, p.RootFolder, used_sort)       # use this generic invoker or ...

    #-----------------------------------
    #traverse_preorder ( g, p.RootFolder, used_sort)               # or any of these direct invokations
    #traverse_postorder( g, p.RootFolder, used_sort)
    #traverse_inorder  ( g, p.RootFolder, used_sort)
    #traverse_levelled ( g, p.RootFolder, used_sort)


##############################################################################################
#
#   Variables existing when the script is executed are
#   -----------------------------------------------------
#
#   project : the project variable (see Interfaces/Mga.idl)
#   gme     : the main application window (see Interfaces/GME.idl for IGMEOLEApp)
#   it      : the actively shown model (view) (see Interfaces/GME.idl for IGMEOLEIt)
#
###############################################################################################
# main() begins
#

cout( 'Hello World, this is Python here!', 1)

terr = begin( p)                              # begin transaction (strictly needed to perform r/w operations on a IMgaProject)
try:
    traverse()                                # do a traversal
    commit(p, terr)                           # commit transaction (strictly needed to return the project in a consistent mode)
except:
    cout( 'Need to abort', 2)                 # 2 means WARNING (yellow)
    abort(p, terr)                            # abort transaction if something went wrong

cout( 'End of Script', 1)



More information about the GME-commit mailing list