/// ------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="TsStringComparer"/> class. /// </summary> /// <param name="icuLocale">The icu locale that is used to create a collating engine. /// </param> /// ------------------------------------------------------------------------------------ public TsStringComparer(string icuLocale) { m_collatingEngine = LgIcuCollatorClass.Create(); m_IcuCleanupManager = IcuCleanupManagerClass.Create(); m_IcuCleanupManager.RegisterCleanupCallback(this); m_icuLocale = icuLocale; }
/// <summary> /// Get the lead character, either a single character or a composite matching something /// in the sort rules. (We need to support multi-graph letters. See LT-9244.) /// </summary> private string GetLeadChar(string sEntryNFD, string sWs) { if (string.IsNullOrEmpty(sEntryNFD)) { return(""); } string sEntry = Icu.ToLower(sEntryNFD, sWs); Dictionary <string, string> mapChars; Set <string> sortChars = GetDigraphs(sWs, out mapChars); string sEntryT = sEntry; bool fChanged = false; do { foreach (string key in mapChars.Keys) { sEntry = sEntry.Replace(key, mapChars[key]); } fChanged = sEntryT != sEntry; sEntryT = sEntry; } while (fChanged); string sFirst = sEntry.Substring(0, 1); foreach (string sChar in sortChars) { if (sEntry.StartsWith(sChar)) { if (sFirst.Length < sChar.Length) { sFirst = sChar; } } } // We don't want sFirst for an ignored first character or digraph. ILgCollatingEngine lce = LgIcuCollatorClass.Create(); lce.Open(sWs); byte[] ka = (byte[])lce.get_SortKeyVariant(sFirst, LgCollatingOptions.fcoDefault); if (ka[0] == 1) { string sT = sEntry.Substring(sFirst.Length); return(GetLeadChar(sT, sWs)); } return(sFirst); }
/// <summary> /// Creates a TreeNode tree along genres populated by the texts that claim them. /// The list of textsWithNoGenre is also populated. /// Recursively descend the genre tree and duplicate parts that have corresponding texts. /// </summary> /// <param name="parent">The parent to attach the genres to. If null, nothing is done.</param> /// <param name="genreList">The owning sequence of genres - its a tree.</param> /// <param name="allTexts">The flat list of all texts in the project.</param> private void LoadTextsFromGenres(TreeNode parent, IFdoOwningSequence <ICmPossibility> genreList, IEnumerable <FDO.IText> allTexts) { if (parent == null) { return; } var sortedGenreList = new List <ICmPossibility>(); foreach (var gen in genreList) { sortedGenreList.Add(gen); } var sorter = new CmPossibilitySorter(); sortedGenreList.Sort(sorter); foreach (var gen in sortedGenreList) { // This tree node is added to genreTreeNodes if there are texts or children var genItem = new TreeNode(gen.ChooserNameTS.Text); // LT-12179: Create a List for collecting selected tree nodes which we will later sort // before actually adding them to the tree: var sortedNodes = new List <TreeNode>(); var foundFirstText = false; // Create a collator ready for sorting: var collator = LgIcuCollatorClass.Create(); foreach (IText tex in allTexts) { // This tex may not have a genre or it may claim to be in more than one foreach (var tgen in tex.GenresRC) { if (tgen.Equals(gen)) { // The current tex is valid, so create a TreeNode with its details: var texItem = new TreeNode(tex.ChooserNameTS.Text); texItem.Tag = tex.ContentsOA; texItem.Name = "Text"; // LT-12179: Add the new TreeNode to the (not-yet-)sorted list: sortedNodes.Add(texItem); // LT-12179: If this is the first tex we've added, establish the collator's details // according to the writing system at the start of the tex: if (!foundFirstText) { foundFirstText = true; var ws1 = tex.ChooserNameTS.get_WritingSystemAt(0); var wsEngine = gen.Cache.WritingSystemFactory.get_EngineOrNull(ws1); collator.Open(wsEngine.Id); } break; } } } // LT-12179: if (foundFirstText) { // Order the TreeNodes alphabetically: sortedNodes.Sort((x, y) => collator.Compare(x.Text, y.Text, LgCollatingOptions.fcoIgnoreCase)); // Add the TreeNodes to the tree: genItem.Nodes.AddRange(sortedNodes.ToArray()); } if (gen.SubPossibilitiesOS.Count > 0) { // Descend to the child genres regardless if there were texts assigned to this genre LoadTextsFromGenres(genItem, gen.SubPossibilitiesOS, allTexts); } //Add the node even if there are no texts that point to this genre. genItem.Tag = gen; // ICmPossibility genItem.Name = "Genre"; parent.Nodes.Add(genItem); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Load texts by Genre into the texts tree view. /// </summary> /// <param name="cache">The cache.</param> /// <returns>A control tree of the Texts in the project</returns> /// ------------------------------------------------------------------------------------ public TreeNode LoadTextsByGenreAndWithoutGenre(FdoCache cache) { if (cache.LanguageProject.GenreListOA == null) { return(null); } var genreList = cache.LanguageProject.GenreListOA.PossibilitiesOS; Debug.Assert(genreList != null); var allTexts = cache.ServiceLocator.GetInstance <ITextRepository>().AllInstances(); if (allTexts == null) { return(null); } // Title node for all texts, Biblical and otherwise var textsNode = new TreeNode("All Texts in Genres and not in Genres"); textsNode.Name = "Texts"; // For each genre, find the texts that claim it LoadTextsFromGenres(textsNode, genreList, allTexts); var textsWithNoGenre = new List <TreeNode>(); // and get the ones with no genre // LT-12179: Create a List for collecting selected tree nodes which we will later sort // before actually adding them to the tree: var foundFirstText = false; // Create a collator ready for sorting: var collator = LgIcuCollatorClass.Create(); foreach (var tex in allTexts) { if (tex.GenresRC.Count == 0) { var texItem = new TreeNode(tex.ChooserNameTS.Text); texItem.Tag = tex.ContentsOA; texItem.Name = "Text"; textsWithNoGenre.Add(texItem); // LT-12179: If this is the first tex we've added, establish the collator's details // according to the writing system at the start of the tex: if (!foundFirstText) { foundFirstText = true; var ws1 = tex.ChooserNameTS.get_WritingSystemAt(0); var wsEngine = cache.WritingSystemFactory.get_EngineOrNull(ws1); collator.Open(wsEngine.Id); } } } if (textsWithNoGenre.Count > 0) { // LT-12179: Order the TreeNodes alphabetically: textsWithNoGenre.Sort((x, y) => collator.Compare(x.Text, y.Text, LgCollatingOptions.fcoIgnoreCase)); // Make a TreeNode for the texts with no known genre var woGenreTreeNode = new TreeNode("No Genre", textsWithNoGenre.ToArray()); woGenreTreeNode.Name = "TextsWoGenre"; textsNode.Nodes.Add(woGenreTreeNode); } return(textsNode); }