///
/// 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