/// /// 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.Globalization; using JetBrains.DataStructures; using JetBrains.Omea.OpenAPI; namespace JetBrains.Omea.ResourceTools { /// /// Comparer for the values of "Subject" column which ignores prefixes like /// "Re" and "Fw". User has the option to configure its own (localized) mail /// prefixes like "SV" in Swedish. /// public class SubjectComparer: IResourceComparer, IResourceGroupProvider { public const String csIniSection = "General"; public const String csIniKey = "SubjectPrefixes"; public const String csDefaultPrefixes = "re; fw;"; public const String csNoSubjectGroup = ""; private static HashSet _prefixes = new HashSet(); public int CompareResources( IResource r1, IResource r2 ) { bool hasPrefix1, hasPrefix2; string normSubj1 = NormalizeSubject( r1, out hasPrefix1 ); string normSubj2 = NormalizeSubject( r2, out hasPrefix2 ); int rc = String.Compare( normSubj1, normSubj2, true ); if ( rc == 0 ) { if ( !hasPrefix1 && hasPrefix2 ) return -1; if ( hasPrefix1 && !hasPrefix2 ) return 1; } return rc; } public string GetGroupName( IResource res ) { bool hasPrefix; string groupName = NormalizeSubject( res, out hasPrefix ); return String.IsNullOrEmpty( groupName ) ? csNoSubjectGroup : groupName; } private static string NormalizeSubject( IResource resource, out bool hasPrefix ) { CheckSubjectPrefixes(); hasPrefix = false; string subj = resource.GetStringProp( Core.Props.Subject ); if( subj != null ) { string prefix = FindPrefix( subj ); if( prefix != null ) { // Skip prefixes with enumeration like "Re[3]" int pos = prefix.Length; while( pos < subj.Length && IsDelimiter( subj, pos ) ) { pos++; } hasPrefix = true; subj = subj.Substring( pos ); } } return subj; } //--------------------------------------------------------------------- // If the hash is empty then we did not initialize the prefixes yet. // Perform lazy initialization of the has with the string values stored // in the ini file. //--------------------------------------------------------------------- private static void CheckSubjectPrefixes() { if( _prefixes.Count == 0 ) { SubjectPrefixes = Core.SettingStore.ReadString(csIniSection, csIniKey, csDefaultPrefixes); } } public static String SubjectPrefixes { set { _prefixes.Clear(); string[] prefixes = value.Split( ';' ); foreach( string prefix in prefixes ) { string pref = prefix.Trim(); if( !String.IsNullOrEmpty( pref ) ) { _prefixes.Add( pref ); } } } } private static bool IsDelimiter( string subj, int pos ) { return Char.IsWhiteSpace( subj, pos ) || Char.IsPunctuation( subj, pos ) || Char.IsDigit( subj, pos ); } private static string FindPrefix( string str ) { CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo; foreach( HashSet.Entry e in _prefixes ) { string prefix = (string)e.Key; if (ci.IsPrefix(str, prefix, CompareOptions.IgnoreCase)) return prefix; } return null; } } }