crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Base/CIElement.cs
changeset 0 818e61de6cd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Base/CIElement.cs	Thu Feb 11 15:50:58 2010 +0200
@@ -0,0 +1,795 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+* 
+* Description:
+*
+*/
+using System;
+using System.Text;
+using System.Reflection;
+using System.Collections.Generic;
+using SymbianUtils;
+using SymbianDebugLib.Engine;
+using CrashItemLib.Engine;
+using CrashItemLib.Crash;
+using CrashItemLib.Crash.Messages;
+using CrashItemLib.Crash.Container;
+using CrashItemLib.Crash.Base.DataBinding;
+
+namespace CrashItemLib.Crash.Base
+{
+	public abstract class CIElement : IEnumerable<CIElement>
+    {
+        #region Delegates & events
+        public delegate void CIElementEventHandler( CIElement aElement );
+        public delegate void CIMultiElementEventHandler( CIElement aSelf, CIElement aOther );
+
+        public event CIMultiElementEventHandler ChildAdded = null;
+        #endregion
+
+        #region Enumerations
+        internal enum TAutoPopulateType
+        {
+            EAutoPopulateDisabled = 0,
+            EAutoPopulateEnabled
+        }
+
+        public enum TChildSearchType
+        {
+            EDirectChildrenOnly = 0,
+            EEntireHierarchy
+        }
+        #endregion
+
+        #region Constructors
+        internal CIElement( int aId )
+            : this( aId, false )
+        {
+            // NB: to be called only by the container itself since everything else
+            // must specify a valid container object
+            System.Diagnostics.Debug.Assert( this is CIContainer );
+        }
+
+        internal CIElement( CIContainer aContainer )
+            : this( aContainer, TAutoPopulateType.EAutoPopulateDisabled )
+		{
+		}
+
+        internal CIElement( CIContainer aContainer, CIElement aParent )
+            : this( aContainer )
+        {
+            iParent = aParent;
+        }
+
+        internal CIElement( CIContainer aContainer, TAutoPopulateType aDataBindingAutoPopulate )
+            : this( aContainer.GetNextElementId(), aDataBindingAutoPopulate == TAutoPopulateType.EAutoPopulateEnabled )
+        {
+            iContainer = aContainer;
+        }
+
+        internal CIElement( CIContainer aContainer, CIElement aParent, TAutoPopulateType aDataBindingAutoPopulate )
+            : this( aContainer, aDataBindingAutoPopulate )
+        {
+            iParent = aParent;
+        }
+        
+        private CIElement( long aId, bool aDataBindingAutoPopulate )
+        {
+            iId = new CIElementId( aId );
+            iDataBindingModel = new CIDBModel( this, aDataBindingAutoPopulate );
+        }
+        #endregion
+
+        #region API - Framework Properties
+        public virtual string Name
+        {
+            get { return string.Empty; }
+            set { }
+        }
+
+        public virtual CIElementId Id
+        {
+            get { return iId; }
+            set 
+            { 
+                iId = value;
+                IsIdExplicit = true;
+            }
+        }
+        #endregion
+
+        #region API - Children
+        public virtual int Count
+        {
+            get 
+            {
+                int ret = 0;
+                //
+                lock ( iSyncLock )
+                {
+                    if ( iChildren != null )
+                    {
+                        ret = iChildren.Count;
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+
+        public bool HasChildren
+        {
+            get
+            {
+                bool ret = false;
+                //
+                lock ( iSyncLock )
+                {
+                    if ( iChildren != null )
+                    {
+                        ret = ( iChildren.Count > 0 );
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+
+        public virtual void AddChild( CIElement aChild )
+        {
+            if ( aChild != null )
+            {
+                // If we have been restricted to a specific 
+                // type of child element, then check aChild against
+                // it...
+                Type t = aChild.GetType();
+                ValidateChildType( t );
+
+                lock ( iSyncLock )
+                {
+                    if ( iChildren == null )
+                    {
+                        iChildren = new CIElementList<CIElement>( Container );
+                        iChildren.IsInContainer = this.IsInContainer;
+                    }
+
+                    if ( aChild.Parent == null )
+                    {
+                        aChild.Parent = this;
+                    }
+
+                    iChildren.Add( aChild );
+                }
+
+                OnElementAddedToSelf( aChild );
+            }
+        }
+
+        public virtual void AddChildren( CIElement[] aChildren )
+        {
+            for ( int i = aChildren.Length - 1; i >= 0; i-- )
+            {
+                AddChild( aChildren[ i ] );
+            }
+        }
+
+        public virtual void RemoveChild( CIElement aChild )
+        {
+            if ( aChild == null )
+            {
+                throw new ArgumentException( "Child is null" );
+            }
+
+            if ( HasChildren && iChildren.Count > 0 )
+            {
+                lock ( iSyncLock )
+                {
+                    iChildren.Remove( aChild );
+                }
+            }
+        }
+
+        public virtual void RemoveChildren( Type aType )
+        {
+            if ( HasChildren && iChildren.Count > 0 )
+            {
+                lock ( iSyncLock )
+                {
+                    int count = iChildren.Count;
+                    for ( int i = count - 1; i >= 0; i-- )
+                    {
+                        CIElement child = iChildren[ i ];
+                        if ( aType.IsAssignableFrom( aType ) )
+                        {
+                            iChildren.Remove( child );
+                        }
+                    }
+                }
+            }
+        }
+
+        public virtual void Clear()
+        {
+            lock ( iSyncLock )
+            {
+                if ( iChildren != null )
+                {
+                    iChildren.Clear();
+                }
+            }
+        }
+
+        public virtual bool Contains( CIElement aElement )
+        {
+            return Contains( aElement.Id );
+        }
+
+        public virtual bool Contains( CIElementId aId )
+        {
+            bool ret = false;
+            //
+            lock ( iSyncLock )
+            {
+                if ( iChildren != null )
+                {
+                    ret = iChildren.Contains( aId );
+                }
+            }
+            //
+            return ret;
+        }
+
+        public CIElement this[ CIElementId aId ]
+        {
+            get
+            {
+                CIElement ret = null;
+                //
+                lock ( iSyncLock )
+                {
+                    if ( Contains( aId ) )
+                    {
+                        System.Diagnostics.Debug.Assert( iChildren != null );
+                        ret = iChildren[ aId ];
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+
+        public CIElement this[ int aIndex ]
+        {
+            get
+            {
+                CIElement ret = null;
+                //
+                lock ( iSyncLock )
+                {
+                    if ( iChildren != null )
+                    {
+                        ret = iChildren[ aIndex ];
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+        
+        public CIElement ChildByType( Type aType )
+        {
+            CIElement ret = null;
+            //
+            lock ( iSyncLock )
+            {
+                foreach ( CIElement element in this )
+                {
+                    if ( aType.IsAssignableFrom( element.GetType() ) )
+                    {
+                        ret = element;
+                        break;
+                    }
+                }
+            }
+            //
+            return ret;
+        }
+
+        public CIElementList<T> ChildrenByType<T>() where T: CIElement
+        {
+            CIElementList<T> ret = ChildrenByType<T>( TChildSearchType.EDirectChildrenOnly );
+            return ret;
+        }
+
+        public CIElementList<T> ChildrenByType<T>( Predicate<T> aPredicate ) where T : CIElement
+        {
+            CIElementList<T> ret = ChildrenByType<T>( TChildSearchType.EDirectChildrenOnly, aPredicate );
+            return ret;
+        }
+
+        public CIElementList<T> ChildrenByType<T>( TChildSearchType aType ) where T : CIElement
+        {
+            return ChildrenByType<T>( aType, null );
+        }
+
+        public CIElementList<T> ChildrenByType<T>( TChildSearchType aType, Predicate<T> aPredicate ) where T : CIElement
+        {
+            CIElementList<T> ret = new CIElementList<T>( Container );
+            GetChildrenByType<T>( ret, aType, aPredicate );
+            return ret;
+        }
+
+        internal CIElementList<CIElement> Children
+        {
+            get
+            {
+                CIElementList<CIElement> ret = null;
+                //
+                lock ( iSyncLock )
+                {
+                    ret = iChildren;
+                    //
+                    if ( ret == null )
+                    {
+                        ret = new CIElementList<CIElement>( Container );
+                    }
+                }
+                //
+                return ret;
+            }
+        }
+        #endregion
+
+        #region API - Data Binding framework
+        public virtual void PrepareColumns()
+        {
+            DataBindingModel.ClearColumns();
+            DataBindingModel.TryAutoPopulateColumns( this );
+        }
+
+        public virtual void PrepareRows()
+        {
+            DataBindingModel.ClearRows();
+            DataBindingModel.TryAutoPopulateCells( this );
+        }
+        #endregion
+
+        #region API - Parentage
+        public bool HasParent
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return iParent != null;
+                }
+            }
+        }
+
+        public virtual CIElement Parent
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return iParent;
+                }
+            }
+            internal set 
+            {
+                lock ( iSyncLock )
+                {
+                    iParent = value;
+                }
+            }
+        }
+        #endregion
+
+        #region Properties
+        public virtual bool IsInContainer
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return ( iFlags & TFlags.EFlagsIsInContainer ) == TFlags.EFlagsIsInContainer;
+                }
+            }
+            internal set
+            {
+                // Don't allow it to change if we're locked down.
+                if ( IsFinalized == false )
+                {
+                    bool oldValue = IsInContainer;
+                    if ( oldValue != value )
+                    {
+                        // Set new flag value
+                        lock ( iSyncLock )
+                        {
+                            if ( value )
+                            {
+                                iFlags |= TFlags.EFlagsIsInContainer;
+                            }
+                            else
+                            {
+                                iFlags &= ~TFlags.EFlagsIsInContainer;
+                            }
+                        }
+
+                        // Fire internal call that reflects new state. This notifies the
+                        // container about our registration status and in turn, the container
+                        // can notify it's observers about our presence/remove within container.
+                        OnIsInContainerChanged();
+
+                        // Ensure children are also in/out of container
+                        lock ( iSyncLock )
+                        {
+                            if ( iChildren != null )
+                            {
+                                iChildren.IsInContainer = value;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        public bool IsIdExplicit
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return ( iFlags & TFlags.EFlagsIdWasExplicitlySet ) == TFlags.EFlagsIdWasExplicitlySet;
+                }
+            }
+            private set 
+            {
+                lock ( iSyncLock )
+                {
+                    if ( value )
+                    {
+                        iFlags |= TFlags.EFlagsIdWasExplicitlySet;
+                    }
+                    else
+                    {
+                        iFlags &= ~TFlags.EFlagsIdWasExplicitlySet;
+                    }
+                }
+            }
+        }
+
+        public virtual CIEngine Engine
+        {
+            get { return Container.Engine; }
+        }
+
+        public CIContainer Container
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return iContainer;
+                }
+            }
+            internal set 
+            {
+                lock ( iSyncLock )
+                {
+                    iContainer = value;
+                }
+            }
+        }
+
+        public CIDBModel DataBindingModel
+        {
+            get { return iDataBindingModel; }
+        }
+
+        protected bool IsToBeFinalizedLast
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return ( iFlags & TFlags.EFlagsIsToBeFinalizedLast ) == TFlags.EFlagsIsToBeFinalizedLast;
+                }
+            }
+            set
+            {
+                lock ( iSyncLock )
+                {
+                    if ( value )
+                    {
+                        iFlags |= TFlags.EFlagsIsToBeFinalizedLast;
+                    }
+                    else
+                    {
+                        iFlags &= ~TFlags.EFlagsIsToBeFinalizedLast;
+                    }
+                }
+            }
+        }
+
+        internal bool IsFinalized
+        {
+            get
+            {
+                lock ( iSyncLock )
+                {
+                    return ( iFlags & TFlags.EFlagsIsFinalized ) == TFlags.EFlagsIsFinalized;
+                }
+            }
+            set
+            {
+                lock ( iSyncLock )
+                {
+                    if ( value )
+                    {
+                        iFlags |= TFlags.EFlagsIsFinalized;
+                    }
+                    else
+                    {
+                        iFlags &= ~TFlags.EFlagsIsFinalized;
+                    }
+                }
+            }
+        }
+        #endregion
+
+        #region Internal methods
+        internal void Trace( string aMessage )
+        {
+            Container.Engine.Trace( aMessage );
+        }
+
+        internal void Trace( string aFormat, params object[] aParams )
+        {
+            Container.Engine.Trace( aFormat, aParams );
+        }
+
+        protected void AddSupportedChildType( Type aType )
+        {
+            lock ( iSyncLock )
+            {
+                if ( iSupportedChildTypes == null )
+                {
+                    iSupportedChildTypes = new List<Type>();
+                }
+                iSupportedChildTypes.Add( aType );
+            }
+        }
+
+        private void ValidateChildType( Type aType )
+        {
+            lock ( iSyncLock )
+            {
+                if ( iSupportedChildTypes != null )
+                {
+                    StringBuilder typeNames = new StringBuilder();
+                    //
+                    foreach ( Type t in iSupportedChildTypes )
+                    {
+                        typeNames.Append( t.ToString() + ", " );
+                        //
+                        if ( aType == t || aType.IsSubclassOf( t ) )
+                        {
+                            return;
+                        }
+                    }
+                    //
+                    string names = typeNames.ToString();
+                    if ( names.Length > 2 )
+                    {
+                        names = names.Substring( 0, names.Length - 2 );
+                    }
+                    //
+                    throw new ArgumentException( "Child is not of type: [" + names + "]" );
+                }
+            }
+        }
+
+        internal virtual void GetChildrenByType<T>( CIElementList<T> aList, TChildSearchType aType, Predicate<T> aPredicate ) where T : CIElement
+        {
+            // Get all direct children, and if recusion enabled, then fetch the
+            // entire tree.
+            Type t = typeof( T );
+            foreach ( CIElement element in Children )
+            {
+                if ( t.IsAssignableFrom( element.GetType() ) )
+                {
+                    // Get entry of correct type
+                    T objectEntry = (T) ( (object) element );
+
+                    // Check whether it is suitable for inclusion via our predicate
+                    bool addEntry = true;
+                    if ( aPredicate != null )
+                    {
+                        addEntry = aPredicate( objectEntry );
+                    }
+                    
+                    // Is it okay to take the entry?
+                    if ( addEntry )
+                    {
+                        aList.Add( objectEntry );
+                    }
+                }
+
+                // Get the element's children
+                if ( aType == TChildSearchType.EEntireHierarchy )
+                {
+                    element.GetChildrenByType<T>( aList, aType, aPredicate );
+                }
+            }
+        }
+        #endregion
+
+        #region Internal flags
+        [Flags]
+        private enum TFlags : short
+        {
+            EFlagsNone = 0,
+            EFlagsIsInContainer = 1,
+            EFlagsIdWasExplicitlySet = 2,
+            EFlagsIsReadOnly = 4,
+            EFlagsIsToBeFinalizedLast = 8,
+            EFlagsIsFinalized = 16,
+        }
+        #endregion
+
+        #region Internal framework methods
+        /// <summary>
+        /// Called when the element is to finish its construction. At this point
+        /// it is assumed that the crash container data structure is largely fully
+        /// populated. This function call should typically perform any final 
+        /// post-processing, such as looking up symbols etc.
+        /// </summary>
+        /// <param name="aParams"></param>
+        internal virtual void OnFinalize( CIElementFinalizationParameters aParams )
+        {
+        }
+
+        internal void DoFinalizeElements( CIElementFinalizationParameters aParams, Queue<CIElement> aCallBackLast, bool aForceFinalize, IEnumerable<CIElement> aElements )
+        {
+            foreach( CIElement element in aElements )
+            {
+                if ( element.IsToBeFinalizedLast )
+                {
+                    aCallBackLast.Enqueue( element );
+                }
+                //
+                element.DoFinalize( aParams, aCallBackLast, aForceFinalize );
+            }
+        }
+
+        internal virtual void DoFinalize( CIElementFinalizationParameters aParams, Queue<CIElement> aCallBackLast, bool aForceFinalize )
+        {
+            lock ( iSyncLock )
+            {
+                // Finalize children
+                if ( iChildren != null )
+                {
+                    DoFinalizeElements( aParams, aCallBackLast, aForceFinalize, iChildren );
+                }
+            }
+
+            // Finalize ourself
+            if ( ( aForceFinalize || IsToBeFinalizedLast == false ) && IsFinalized == false )
+            {
+                try
+                {
+                    OnFinalize( aParams );
+                }
+                finally
+                {
+                    IsFinalized = true;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Called by CIElement.AddChild() whenever a new element is
+        /// added as a child of this element.
+        /// 
+        /// Notify the container that a child entry was added
+        /// so that it can notify any elements that listen to
+        /// all additions to the container (direct or indirect).
+        /// </summary>
+        protected virtual void OnElementAddedToSelf( CIElement aElement )
+        {
+            // aElement inherits our container state
+            bool inContainer = IsInContainer;
+
+            // Doing this will fire an added/removed event in accordance
+            // with what our state currently is and what it has just become.
+            aElement.IsInContainer = inContainer;
+
+            // Report event
+            if ( ChildAdded != null )
+            {
+                ChildAdded( this, aElement );
+            }
+        }
+
+        protected virtual void OnIsInContainerChanged()
+        {
+            // If we're now in the container, either directly or indirectly (we don't care)
+            // then make sure we notify the container so that it can inform other elements
+            // that may be listening.
+            //
+            // Because "IsInContainer" cascades changes to our children, they will also
+            // notify the container themselves in due course.
+            //
+            // Obviously don't cascade when the container itself changes its state.
+            if ( this != Container )
+            {
+                if ( IsInContainer )
+                {
+                    Container.OnContainerElementRegistered( this );
+                }
+                else
+                {
+                    Container.OnContainerElementUnregistered( this );
+                }
+            }
+        }
+        #endregion
+
+        #region From System.Object
+        public override string ToString()
+        {
+            return Name;
+        }
+        #endregion
+
+        #region From IEnumerable<CIElement>
+        public IEnumerator<CIElement> GetEnumerator()
+        {
+            lock ( iSyncLock )
+            {
+                CIElementList<CIElement> children = iChildren;
+                if ( iChildren == null )
+                {
+                    children = new CIElementList<CIElement>( Container );
+                }
+                return children.GetEnumerator();
+            }
+        }
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            lock ( iSyncLock )
+            {
+                CIElementList<CIElement> children = iChildren;
+                if ( iChildren == null )
+                {
+                    children = new CIElementList<CIElement>( Container );
+                }
+                return children.GetEnumerator();
+            }
+        }
+        #endregion
+
+        #region Data members
+        private readonly CIDBModel iDataBindingModel;
+        private object iSyncLock = new object();
+        private CIElement iParent = null;
+        private List<Type> iSupportedChildTypes = null;
+        private CIContainer iContainer;
+        private CIElementList<CIElement> iChildren;
+        private CIElementId iId = new CIElementId();
+        private TFlags iFlags = TFlags.EFlagsNone;
+		#endregion
+    }
+}