/// /// Copyright © 2003-2008 JetBrains s.r.o. /// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder). /// using System; using System.Collections; using System.Drawing; using System.Globalization; using System.Windows.Forms; using JetBrains.JetListViewLibrary; using JetBrains.Omea.Base; using JetBrains.Omea.Containers; using JetBrains.Omea.GUIControls; using JetBrains.Omea.OpenAPI; using JetBrains.DataStructures; namespace JetBrains.Omea { /** * Manages the columns displayed in the ResourceBrowser. */ internal class DisplayColumnManager: IDisplayColumnManager, IDisplayColumnManagerEx { internal class DisplayColumn { private int _index; private ColumnDescriptor _descriptor; public DisplayColumn( int index, ColumnDescriptor descriptor ) { _index = index; _descriptor = descriptor; } internal DisplayColumn MergePropNames( DisplayColumn other ) { ArrayList myPropNames = new ArrayList( _descriptor.PropNames ); string[] otherPropNames = other._descriptor.PropNames; ArrayList mergedPropNames = null; foreach( string propName in otherPropNames ) { if ( !myPropNames.Contains( propName ) ) { if ( mergedPropNames == null ) { mergedPropNames = (ArrayList) myPropNames.Clone(); } mergedPropNames.Add( propName ); } } if ( mergedPropNames == null ) { return this; } return new DisplayColumn( _index, new ColumnDescriptor( (string[]) mergedPropNames.ToArray( typeof(String) ), _descriptor.Width ) ); } public int Index { get { return _index; } } public string[] PropNames { get { return _descriptor.PropNames; } } public ColumnDescriptor Descriptor { get { return _descriptor; } } } internal class ResourceColumnScheme { private readonly int[] _propIds; private readonly int _startRow; private readonly int _endRow; private readonly int _startX; private readonly int _width; private readonly MultiLineColumnFlags _flags; private readonly Color _textColor; private readonly HorizontalAlignment _textAlign; public ResourceColumnScheme( int[] propIds, int startRow, int endRow, int startX, int width, MultiLineColumnFlags flags, Color textColor, HorizontalAlignment textAlign ) { _propIds = propIds; _startRow = startRow; _endRow = endRow; _startX = startX; _width = width; _flags = flags; _textColor = textColor; _textAlign = textAlign; } public int[] PropIds { get { return _propIds; } } public int StartRow { get { return _startRow; } } public int EndRow { get { return _endRow; } } public int StartX { get { return _startX; } } public int Width { get { return _width; } } public MultiLineColumnFlags Flags { get { return _flags; } } public Color TextColor { get { return _textColor; } } public HorizontalAlignment TextAlign { get { return _textAlign; } } } private HashMap _displayColumns = new HashMap(); private HashMap _availableColumns = new HashMap(); private HashMap _columnState = new HashMap(); // string[] -> ResourceListState private ArrayList _allTypeColumns = new ArrayList(); private IntHashTable _customColumns = new IntHashTable(); private IntHashTable _propToTextConverters = new IntHashTable(); // int -> PropertyToTextConverter private DisplayColumnProps _props; private Hashtable _columnSchemeMap = new Hashtable(); // resource type -> ArrayList private HashSet _alignTopLevelItemsTypes = new HashSet(); // public DisplayColumnManager() { if ( Core.ResourceStore.IsOwnerThread() ) { RegisterProps(); } else { Core.ResourceAP.RunJob( new MethodInvoker( RegisterProps ) ); } RegisterAllTypesMultiLineColumn( ResourceProps.Type, 0, 0, 0, 24, MultiLineColumnFlags.AnchorLeft, SystemColors.ControlText, HorizontalAlignment.Left ); RegisterDefaultMultiLineColumn( ResourceProps.DisplayName, 0, 0, 0, 120, MultiLineColumnFlags.AnchorLeft | MultiLineColumnFlags.AnchorRight, SystemColors.ControlText, HorizontalAlignment.Left ); RegisterDefaultMultiLineColumn( Core.Props.Date, 0, 0, 120, 80, MultiLineColumnFlags.AnchorRight, SystemColors.ControlText, HorizontalAlignment.Right ); } private void RegisterProps() { _props = new DisplayColumnProps( Core.ResourceStore ); } public DisplayColumnProps Props { get { return _props; } } /** * Registers a column which is used for displaying the resources of * the specified type. */ public void RegisterDisplayColumn( string resourceType, int index, ColumnDescriptor descriptor ) { if ( resourceType != null && !Core.ResourceStore.ResourceTypes.Exist( resourceType ) ) { throw new ArgumentException( "Invalid resource type " + resourceType, "resourceType" ); } PropNamesToIDs( descriptor.PropNames, false ); // validates the column descriptor DisplayColumn col = new DisplayColumn( index, descriptor ); if ( resourceType == null ) { _allTypeColumns.Add( col ); } else { AddColumnToList( _displayColumns, resourceType, col ); } } /** * Registers a column that is not by default included in the list of * visible columns for the specified resource type, but can always be * added to the list (even if none of the resources in the list have that * property). */ public void RegisterAvailableColumn( string resourceType, ColumnDescriptor descriptor ) { if ( resourceType != null && !Core.ResourceStore.ResourceTypes.Exist( resourceType ) ) { throw new ArgumentException( "Invalid resource type " + resourceType, "resourceType" ); } PropNamesToIDs( descriptor.PropNames, false ); // validates the column descriptor DisplayColumn col = new DisplayColumn( -1, descriptor ); if ( resourceType == null ) { AddColumnToList( _availableColumns, "", col ); } else { AddColumnToList( _availableColumns, resourceType, col ); } } public void RemoveAvailableColumn( string resourceType, string propNames ) { string key = (resourceType == null) ? "" : resourceType; ArrayList columns = (ArrayList) _availableColumns [key]; if ( columns != null ) { for( int i=0; i= 0 ) { allColumns[ foundIndex ] = ((DisplayColumn) allColumns [ foundIndex ]).MergePropNames( col ); } else { int pos = 0; while ( pos < allColumns.Count && ((DisplayColumn) allColumns [ pos ]).Index < col.Index ) pos++; allColumns.Insert( pos, col ); } } private static bool PropNamesMatch( DisplayColumn col1, DisplayColumn col2 ) { ArrayList props2 = new ArrayList( col2.PropNames ); foreach( string propName in col1.PropNames ) { if ( props2.Contains( propName ) ) return true; } return false; } private static bool PropNamesMatchStrictly( DisplayColumn col1, DisplayColumn col2 ) { if( col2.PropNames.Length == col1.PropNames.Length ) { ArrayList props2 = new ArrayList( col2.PropNames ); foreach( string propName in col1.PropNames ) { if ( !props2.Contains( propName ) ) return false; } return true; } return false; } private static bool IsDisplayNameColumn( DisplayColumn col ) { foreach( string propName in col.PropNames ) { if( propName == "DisplayName" ) return true; } return false; } private static ColumnDescriptor[] DisplayColumnsToDescriptors( ArrayList columns ) { ColumnDescriptor[] result = new ColumnDescriptor[columns.Count]; for( int i = 0; i < columns.Count; i++ ) { result [i] = ((DisplayColumn) columns [i]).Descriptor; } return result; } /** * Returns the column descriptor of any registered column which shows * the specified property. */ internal bool FindColumnDescriptor( string propName, ref ColumnDescriptor descriptor ) { if ( FindDescriptorInList( propName, _allTypeColumns, ref descriptor ) ) return true; foreach( HashMap.Entry entry in _displayColumns ) { if ( FindDescriptorInList( propName, (ArrayList) entry.Value, ref descriptor ) ) return true; } foreach( HashMap.Entry entry in _availableColumns ) { if ( FindDescriptorInList( propName, (ArrayList) entry.Value, ref descriptor ) ) return true; } return false; } private static bool FindDescriptorInList( string propName, ArrayList columnList, ref ColumnDescriptor descriptor ) { foreach( DisplayColumn col in columnList ) { if ( Array.IndexOf( col.Descriptor.PropNames, propName ) >= 0 ) { descriptor = col.Descriptor; return true; } } return false; } /** * Saves the state of the list view (column widths) under the key that is * specified as a sequence of columns. */ internal void SaveListViewState( ResourceListView2 listView, ResourceListDataProvider dataProvider, ResourceListState state, bool async ) { ColumnDescriptor[] columns = ColumnDescriptorsFromList( listView ); columns = UpdateColumnsFromState( columns, state ); state.SaveState( columns, dataProvider.SortSettings, async ); } /// /// Returns an array of ColumnDescriptors describing the current column configuration /// of the ListView. /// /// The list view for which the column configuration is returned. /// An array of column descriptors. internal ColumnDescriptor[] ColumnDescriptorsFromList( ResourceListView2 listView ) { ArrayList columnDescriptors = new ArrayList(); foreach( JetListViewColumn col in listView.Columns ) { ResourcePropsColumn propsCol = col as ResourcePropsColumn; if ( propsCol != null ) { string[] propNames = new string[ propsCol.PropIds.Length ]; for( int i=0; i /// Locates and, if necessary, creates a resource list state which applies to all views /// with resources of types matching the contents of the resource list. /// internal ResourceListState StateFromList( IResourceList resList, ColumnDescriptor[] defaultColumns, bool defaultGroupItems ) { string[] keyTypes = resList.GetAllTypes(); keyTypes = CollapseFileTypes( keyTypes ); ComparableArrayList keyTypeList = new ComparableArrayList( keyTypes ); ResourceListState state = (ResourceListState) _columnState [keyTypeList]; if ( state == null ) { IResource stateResource = Core.ResourceStore.FindUniqueResource( "ColumnScheme", _props.ColumnKeyTypes, String.Join( ";", keyTypes ) ); if ( stateResource != null ) { state = ResourceListState.FromResource( stateResource ); // filter out invalid data if ( state.Columns.Length == 0 ) { state.Columns = defaultColumns; } } else { state = new ResourceListState( defaultColumns, null, defaultGroupItems ); state.KeyTypes = keyTypes; } _columnState [keyTypeList] = state; } return state; } /// /// Replaces all FileFormat resource types in the specified array of resource types /// with one pseudo-resource type "File". /// internal string[] CollapseFileTypes( string[] keyTypes ) { for( int i=0; i /// Adds a Type column to the specified column list if it is not present there. /// internal ColumnDescriptor[] CreateTypeColumn(ColumnDescriptor[] columns) { if ( columns.Length > 0 ) { foreach( ColumnDescriptor desc in columns ) { if ( desc.PropNames.Length > 0 && desc.PropNames [0] == "Type" ) { return columns; } } ColumnDescriptor[] newColumns = new ColumnDescriptor[ columns.Length+1 ]; int destIndex = 0; while( (columns [destIndex].Flags & ColumnDescriptorFlags.FixedSize) != 0 ) { newColumns [destIndex] = columns [destIndex]; destIndex++; } newColumns [destIndex] = new ColumnDescriptor( "Type", 20, ColumnDescriptorFlags.FixedSize ); Array.Copy( columns, destIndex, newColumns, destIndex+1, columns.Length-destIndex ); return newColumns; } return columns; } /** * For columns in the keyColumns array which have custom comparers, assign these * comparers to the columns with the same property IDs in the second array. */ internal void RestoreCustomComparers( ColumnDescriptor[] keyColumns, ref ColumnDescriptor[] columns ) { foreach( ColumnDescriptor keyColDesc in keyColumns ) { if ( keyColDesc.CustomComparer != null ) { for( int i=0; i 0 ) { int propId = propIds [0]; if ( propId == ResourceProps.Type ) { return new ResourceTypeGroupProvider(); } if ( propId == ResourceProps.DisplayName ) { return new DisplayNameGroupProvider(); } PropDataType propType = Core.ResourceStore.PropTypes [propId].DataType; if ( propType == PropDataType.Date ) { return new DateGroupProvider( propId ); } if ( propType == PropDataType.String || propType == PropDataType.LongString || propType == PropDataType.Link ) { return new PropTextGroupProvider( propId ); } } return null; } /** * Returns the default alignment for the specified column names. */ private static HorizontalAlignment GetDefaultAlignment( int[] propIDs ) { for( int i=0; i 1 ) { continue; } string propDisplayName = Core.ResourceStore.PropTypes.GetPropDisplayName( propIds [i] ); if ( !propNames.Contains( propDisplayName ) ) { propNames.Add( propDisplayName ); } } } return String.Join( ", ", (string[]) propNames.ToArray( typeof (string) ) ); } internal ColumnDescriptor[] UpdateColumnsFromState( ColumnDescriptor[] descriptors, ResourceListState state ) { bool[] usedColumns = new bool [state.Columns.Length]; ArrayList result = new ArrayList(); for( int i=0; i