diff -r 000000000000 -r 818e61de6cd1 crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Base/DataBinding/CIDBModel.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crashanalysercmd/Libraries/Engine/CrashItemLib/Crash/Base/DataBinding/CIDBModel.cs Thu Feb 11 15:50:58 2010 +0200 @@ -0,0 +1,303 @@ +/* +* 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.Collections.Generic; +using System.Reflection; +using System.ComponentModel; + +namespace CrashItemLib.Crash.Base.DataBinding +{ + public class CIDBModel : IEnumerable + { + #region Constructors + public CIDBModel( CIElement aElement, bool aAutoPopulate ) + { + iElement = aElement; + iAutoPopulate = aAutoPopulate; + } + #endregion + + #region API + public void Add( CIDBColumn aColumn ) + { + aColumn.Model = this; + iColumns.Add( aColumn ); + } + + public void Add( CIDBRow aRow ) + { + aRow.Model = this; + iRows.Add( aRow ); + } + + public void Add( params CIDBCell[] aCells ) + { + CIDBRow row = new CIDBRow( aCells ); + Add( row ); + } + + public void ClearRows() + { + iRows.Clear(); + } + + public void ClearColumns() + { + iColumns.Clear(); + } + + public void TryAutoPopulateColumns( CIElement aElement ) + { + Type customAttributeType = typeof( CIDBAttributeColumn ); + Type thisObjectType = aElement.GetType(); + + object[] attribs = thisObjectType.GetCustomAttributes( customAttributeType, true ); + if ( attribs != null && attribs.Length > 0 ) + { + ExtractAttributeColumns( attribs, aElement ); + } + } + + public void TryAutoPopulateCells( CIElement aElement ) + { + if ( AutoPopulate ) + { + SortedDictionary rows = new SortedDictionary(); + + Type customAttributeType = typeof( CIDBAttributeCell ); + Type thisObjectType = aElement.GetType(); + + // Get properties featuring the CIDBAttribute + PropertyInfo[] propertyInfo = thisObjectType.GetProperties(); + foreach ( PropertyInfo p in propertyInfo ) + { + object[] attribs = p.GetCustomAttributes( customAttributeType, true ); + if ( attribs != null && attribs.Length > 0 ) + { + object propertyValue = p.GetValue( aElement, null ); + ExtractAttributeCells( p.ToString(), aElement, attribs, propertyValue, rows ); + } + } + + // Same, but get methods featuring the CIDBAttribute + MethodInfo[] methodInfo = thisObjectType.GetMethods(); + foreach ( MethodInfo m in methodInfo ) + { + object[] attribs = m.GetCustomAttributes( customAttributeType, true ); + if ( attribs != null && attribs.Length > 0 ) + { + // We only support this attribute on methods that don't contain + // any arguments + int paramCount = m.GetParameters().Length; + if ( paramCount != 0 ) + { + throw new NotSupportedException( "Method: " + m.ToString() + " has CIDBAttribute but non-empty parameter list -> Not supported" ); + } + + // Get property value + object propertyValue = m.Invoke( aElement, null ); + ExtractAttributeCells( m.ToString(), aElement, attribs, propertyValue, rows ); + } + } + + // Since the list is already sorted for us, just add the items in order + foreach ( KeyValuePair kvp in rows ) + { + this.Add( kvp.Value ); + } + } + } + #endregion + + #region Properties + public bool AutoPopulate + { + get { return iAutoPopulate; } + } + + public CIElement Element + { + get { return iElement; } + } + + public List Columns + { + get { return iColumns; } + } + + public List Rows + { + get { return iRows; } + } + #endregion + + #region Internal methods + private void ExtractAttributeColumns( object[] aColumnAttributes, CIElement aElement ) + { + bool foundColumnAttributes = false; + SortedDictionary columns = new SortedDictionary(); + + foreach ( object obj in aColumnAttributes ) + { + if ( obj is CIDBAttributeColumn ) + { + CIDBAttributeColumn attribute = (CIDBAttributeColumn) obj; + + // Make a column + CIDBColumn col = new CIDBColumn( attribute.Caption ); + col.Width = attribute.Width; + col.WidthSet = attribute.WidthSet; + col.TakesUpSlack = attribute.TakesUpSlack; + + if ( columns.ContainsKey( attribute.Order ) ) + { + throw new Exception( string.Format( "Column: [{0}] in element: [{1}] specifies order: {2} which is already in use", + attribute.Caption, aElement, attribute.Order ) ); + } + + columns.Add( attribute.Order, col ); + foundColumnAttributes = true; + } + } + + // Since the list is already sorted for us, just add the items in order + foreach ( KeyValuePair kvp in columns ) + { + this.Add( kvp.Value ); + } + + // We'll override the auto populate feature if we find a valid + // column attribute + iAutoPopulate = foundColumnAttributes; + } + + private void ExtractAttributeCells( string aEntityName, CIElement aElement, object[] aCIDBAttributeEntries, object aValue, SortedDictionary aRows ) + { + foreach ( object obj in aCIDBAttributeEntries ) + { + if ( obj is CIDBAttributeCell ) + { + CIDBAttributeCell attribute = (CIDBAttributeCell) obj; + + // If the property is an 'auto expand' entry, then don't look at this + // property, but instead look at the object itself + if ( attribute.Options == CIDBAttributeCell.TOptions.EAutoExpand ) + { + // The object must be an element + CIElement element = aValue as CIElement; + if ( element == null ) + { + throw new ArgumentException( "CIDBAttributeCell(TOptions.EAutoExpand) may only be applied to CIElement objects" ); + } + + TryAutoPopulateCells( element ); + } + else + { + // Whether or not to create a row + bool makeRow = true; + + // Convert attribute value to string. If the object is an enum, we'll check if it has + // a System.ComponentModel.Description attached to it, and use that in preference to a raw + // value. + string defaultValueString = ( attribute.DefaultValue != null ) ? attribute.DefaultValue.ToString() : null; + string propertyValueString = aValue.ToString(); + if ( aValue.GetType().BaseType == typeof( Enum ) ) + { + // Check if it supports System.ComponentModel.Description + FieldInfo fi = aValue.GetType().GetField( propertyValueString ); + if ( fi != null ) + { + DescriptionAttribute[] attributes = (DescriptionAttribute[]) fi.GetCustomAttributes( typeof( DescriptionAttribute ), false ); + if ( attributes != null && attributes.Length > 0 ) + { + propertyValueString = attributes[ 0 ].Description; + } + } + } + else if ( attribute.Format.Length > 0 && aValue is IFormattable ) + { + string formatSpec = attribute.Format; + IFormattable formattable = (IFormattable) aValue; + propertyValueString = formattable.ToString( formatSpec, null ); + + // Also get the default value if available + bool defaultIsFormattable = attribute.DefaultValue is IFormattable; + if ( attribute.DefaultValue != null && defaultIsFormattable ) + { + formattable = (IFormattable) attribute.DefaultValue; + defaultValueString = formattable.ToString( formatSpec, null ); + } + } + + // If the value of the property is the same as the default, then don't + // show it. + if ( defaultValueString != null ) + { + makeRow = ( defaultValueString.CompareTo( propertyValueString ) != 0 ); + } + + // Make a row + if ( makeRow ) + { + CIDBRow row = new CIDBRow(); + row.Add( new CIDBCell( attribute.Caption ) ); + row.Add( new CIDBCell( propertyValueString, attribute.ForeColor, attribute.BackColor, attribute.Format ) ); + + // Add the row if it doesn't exist. If it does, then that implies + // duplicate ordering, which we treat as a programming error. + if ( aRows.ContainsKey( attribute.Order ) ) + { + throw new Exception( string.Format( "Entity: [{0}] in element: [{1}] specifies order: {2} which is already in use", + aEntityName, aElement, attribute.Order ) ); + } + + aRows.Add( attribute.Order, row ); + } + } + } + } + } + #endregion + + #region From IEnumerable + public IEnumerator GetEnumerator() + { + foreach ( CIDBRow row in iRows ) + { + yield return row; + } + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + foreach ( CIDBRow row in iRows ) + { + yield return row; + } + } + #endregion + + #region Data members + private readonly CIElement iElement; + private bool iAutoPopulate = false; + private List iColumns = new List(); + private List iRows = new List(); + #endregion + } +}