/// -------------------------------------------------------------------------------- /// <summary> /// Clones the text information of this OverlapInfo object, without copying it's /// references (overlappedItemsInOther will be set to null) /// </summary> /// <returns>The cloned OverlapInfo</returns> /// -------------------------------------------------------------------------------- public OverlapInfo Clone() { OverlapInfo toReturn = new OverlapInfo(); toReturn.verseRefMin = new BCVRef(this.verseRefMin); toReturn.verseRefMax = new BCVRef(this.verseRefMax); toReturn.bookIsFromRev = this.bookIsFromRev; toReturn.indexInOwner = this.indexInOwner; toReturn.myObj = this.myObj; // don't copy the related items list, since caller's don't need it, // and it might create an infinite loop if you make a deep copy toReturn.overlappedItemsInOther = null; return toReturn; }
/// ------------------------------------------------------------------------------------ /// <summary> /// A helper method for section cluster tests- /// Verifies a given OverlapInfo item in a Cluster. /// </summary> /// <param name="objExpected">a CmObject (IScrSection or IScrTxtPara) or a ScrVerse which /// we expect the given OverlapInfo to represent</param> /// <param name="oiActual">the given OverlapInfo cluster item to be verified</param> /// ------------------------------------------------------------------------------------ private void VerifyClusterItem(object objExpected, OverlapInfo oiActual) { // We don't need to check everything in the OverlapInfo, // just the things that are essential to processing the Cluster that owns it if (objExpected is ICmObject) { ICmObject cmObjExpected = (ICmObject)objExpected; // check the index Assert.AreEqual(cmObjExpected.IndexInOwner, oiActual.indexInOwner); // check hvo too Assert.AreEqual(cmObjExpected, oiActual.myObj); // for good measure, if a section, check section refs too if (cmObjExpected is IScrSection) { Assert.AreEqual(((IScrSection)cmObjExpected).VerseRefMin, oiActual.verseRefMin); Assert.AreEqual(((IScrSection)cmObjExpected).VerseRefMax, oiActual.verseRefMax); } } else if (objExpected is ScrVerse) { Assert.AreEqual(((ScrVerse)objExpected).StartRef, oiActual.verseRefMin); Assert.AreEqual(((ScrVerse)objExpected).EndRef, oiActual.verseRefMin); } else Assert.Fail("Unhandled expected type."); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructor creates a new one-sided cluster with only one item. /// This is valid only for Missing/Added Cluster types. /// Useful for forming smaller clusters as we break down a complex cluster. /// </summary> /// ------------------------------------------------------------------------------------ public Cluster(ClusterType type, OverlapInfo sourceItem, int indexToInsertAtInDest) { Debug.Assert(type == ClusterType.AddedToCurrent || type == ClusterType.MissingInCurrent); clusterType = type; verseRefMin = sourceItem.verseRefMin; verseRefMax = sourceItem.verseRefMax; indexToInsertAtInOther = indexToInsertAtInDest; itemsCurr = new List<OverlapInfo>(6); itemsRev = new List<OverlapInfo>(6); SourceItems.Add(sourceItem); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds the given source item to this one-sided cluster. /// This is valid only for Missing/Added Cluster types. /// </summary> /// ------------------------------------------------------------------------------------ public void AddSourceItem(OverlapInfo sourceItem) { // This cluster must already have the clusterType set and the source list started. Debug.Assert(clusterType == ClusterType.AddedToCurrent || clusterType == ClusterType.MissingInCurrent); Debug.Assert(SourceItems.Count > 0); // Add the source item to the correct list SourceItems.Add(sourceItem); // Be sure to update the references as well verseRefMin = Math.Min(verseRefMin, sourceItem.verseRefMin); verseRefMax = Math.Max(verseRefMax, sourceItem.verseRefMax); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Determine if two OverlapInfos have a potential section head correlation: /// the section start refs are within two verses /// </summary> /// <param name="oi1">first OverlapInfo to check</param> /// <param name="oi2">second overlapInfo to check</param> /// <returns>true if there is potential correlation</returns> /// ------------------------------------------------------------------------------------ protected bool PotentialSectionHeadCorrelation(OverlapInfo oi1, OverlapInfo oi2) { // are section start refs are within two verses? if (Math.Abs(oi1.verseRefMin - oi2.verseRefMin) <= 2) return true; // if not they are too far apart return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds the item to cluster. /// </summary> /// <param name="cluster">The cluster.</param> /// <param name="oi">The overlap info.</param> /// ------------------------------------------------------------------------------------ private void AddItemToCluster(Cluster cluster, OverlapInfo oi) { if (oi.bookIsFromRev) cluster.itemsRev.Add(oi); else cluster.itemsCurr.Add(oi); // update the cluster reference range if (oi.verseRefMin < cluster.verseRefMin || cluster.verseRefMin == 0) cluster.verseRefMin = oi.verseRefMin; if (oi.verseRefMax > cluster.verseRefMax) cluster.verseRefMax = oi.verseRefMax; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Determines whether a given overlap info can be included in the current cluster. /// To be included in the cluster, it must meet the following criteria: /// * have a reference overlap with the specified cluster, /// * be adjacent to and within the same owning sequence (e.g. same StText), and /// </summary> /// <param name="cluster">The cluster.</param> /// <param name="oi">The overlap info.</param> /// <returns><c>true</c> if the specified OverlapInfo can be included in the cluster</returns> /// ------------------------------------------------------------------------------------ private bool CanBeIncluded(Cluster cluster, OverlapInfo oi) { // is oi completely before the cluster range? if (oi.verseRefMax < cluster.verseRefMin) return false; // is cluster range completely before oi? if (cluster.verseRefMax < oi.verseRefMin) return false; // there must be some overlap // is oi for a ScrVerse contained in the same StText? if (oi.bookIsFromRev) { if (cluster.itemsRev.Count > 0 && oi.myParaOwner != cluster.itemsRev[cluster.itemsRev.Count - 1].myParaOwner) { return false; // paragraph does not have the same owning StText } } else { if (cluster.itemsCurr.Count > 0 && oi.myParaOwner != cluster.itemsCurr[cluster.itemsCurr.Count - 1].myParaOwner) { return false; // not the next item in the owner's sequence } } return true; }
//// This version does extra work so that it never creates a zero-to-many cluster ///// ------------------------------------------------------------------------------------ ///// <summary> ///// Create basic overlap clusters from the OverlapInfo proxies for the Current and ///// Revision. ///// In this case we include only proxies that are adjacent to one another in the ///// owner's sequence in the Current or Revision. ///// The clusters will still need their types and insert Indices determined. ///// </summary> ///// ------------------------------------------------------------------------------------ //private void CreateBasicAdjacentOverlapClusters() //{ // // output list that will ultimatly contain all of the clusters we find // List<Cluster> clusterList = new List<Cluster>(); // // Create destructible copies of each master list, allowing already // // grouped items to be removed, avoiding possible infinite loops // // created when the lists are out-of-order // List<OverlapInfo> proxyListRevCopy = new List<OverlapInfo>(m_proxyListRev.ToArray()); // List<OverlapInfo> proxyListCurrCopy = new List<OverlapInfo>(m_proxyListCurr.ToArray()); // Cluster cluster = null; // the cluster under construction at any given time // // So long as there are remaining proxies, keep working through them // while (proxyListRevCopy.Count > 0 || proxyListCurrCopy.Count > 0) // { // // The proxy to process this pass- the first in either the Current or Rev processing list // OverlapInfo firstProxy; // // If both lists have remaining proxies... // if (proxyListRevCopy.Count > 0 && proxyListCurrCopy.Count > 0) // { // OverlapInfo oiRev = proxyListRevCopy[0]; // OverlapInfo oiCurr = proxyListCurrCopy[0]; // // if we are starting a new cluster... // if (cluster == null) // { // //get the next one with the earlier start reference // // (note: if refs are equal, doesn't matter which one) // if (oiRev.verseRefMin < oiCurr.verseRefMin) // firstProxy = oiRev; // else // firstProxy = oiCurr; // } // else // { // // If I have only one item in the current... // if (cluster.itemsCurr.Count == 1 && cluster.itemsRev.Count == 0) // { // // add a rev item only. // if (IsRefOverlapAndAdjacent(cluster, oiRev)) // firstProxy = oiRev; // else // { // // For now, we don't handle 0 to many clusters, so we complete // // this cluster and move on. // // save the cluster in progress, and prepare to start a new one // clusterList.Add(cluster); // cluster = null; // continue; // } // } // else if (cluster.itemsRev.Count == 1 && cluster.itemsCurr.Count == 0) // { // // If I have only one item in the revision... // if (IsRefOverlapAndAdjacent(cluster, oiCurr)) // firstProxy = oiCurr; // else // { // // For now, we don't handle 0 to many clusters, so we complete // // this cluster and move on. // // save the cluster in progress, and prepare to start a new one // clusterList.Add(cluster); // cluster = null; // continue; // } // } // // See if either side has a proxy that overlaps our cluster under construction // else if (IsRefOverlapAndAdjacent(cluster, oiRev)) // { // firstProxy = oiRev; // } // else if (IsRefOverlapAndAdjacent(cluster, oiCurr)) // firstProxy = oiCurr; // else // { // //Neither proxy overlaps with our cluster. // // save the cluster in progress, and prepare to start a new one // clusterList.Add(cluster); // cluster = null; // continue; // } // } // } // // Otherwise, use whatever remains // else if (proxyListRevCopy.Count > 0) // { // // if cluster has only one item in Rev, we need to avoid making a zero-to-many cluster // if (cluster != null && cluster.itemsRev.Count == 1 && cluster.itemsCurr.Count == 0) // { // // save the cluster in progress, and prepare to start a new one // clusterList.Add(cluster); // cluster = null; // continue; // } // else // firstProxy = proxyListRevCopy[0]; // } // else // { // // if cluster has only one item in Curr, we need to avoid making a zero-to-many cluster // if (cluster != null && cluster.itemsCurr.Count == 1 && cluster.itemsRev.Count == 0) // { // // save the cluster in progress, and prepare to start a new one // clusterList.Add(cluster); // cluster = null; // continue; // } // else // firstProxy = proxyListCurrCopy[0]; // } // // Now add this proxy to a cluster // if (cluster == null) // { // // This is the first item for this cluster // cluster = new Cluster(); // AddItemToCluster(cluster, firstProxy); // } // else if (IsRefOverlapAndAdjacent(cluster, firstProxy)) // { // // This proxy overlaps our cluster. Grab it. // AddItemToCluster(cluster, firstProxy); // } // else // { // //This proxy is NOT overlapping with our cluster. // // save the cluster in progress // clusterList.Add(cluster); // // start a new cluster for this proxy // cluster = new Cluster(); // AddItemToCluster(cluster, firstProxy); // } // // Remove the current proxy from it's corresponding list, now that it // // has been used // if (firstProxy.myBook == OverlapInfo.kRevision) // proxyListRevCopy.Remove(firstProxy); // else // proxyListCurrCopy.Remove(firstProxy); // } // // save the final cluster, if any // if (cluster != null) // { // Debug.Assert(cluster.itemsCurr.Count > 0 || cluster.itemsRev.Count > 0); // clusterList.Add(cluster); // } // // save our cluster list // m_clusterList = clusterList; //} /// ------------------------------------------------------------------------------------ /// <summary> /// Determine if two OverlapInfos have any reference overlap /// </summary> /// <param name="oi1">first OverlapInfo to check</param> /// <param name="oi2">second overlapInfo to check</param> /// <returns>true if there is any reference overlap</returns> /// ------------------------------------------------------------------------------------ protected bool IsRefOverlap(OverlapInfo oi1, OverlapInfo oi2) { // is oi1 completely before oi2? if (oi1.verseRefMax < oi2.verseRefMin) return false; // is oi2 completely before oi1? if (oi2.verseRefMax < oi1.verseRefMin) return false; // there must be some overlap return true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds the item to cluster. /// </summary> /// <param name="cluster">The cluster.</param> /// <param name="oi">The overlap info.</param> /// ------------------------------------------------------------------------------------ private void AddItemToCluster(Cluster cluster, OverlapInfo oi) { if (oi.myBook == OverlapInfo.kCurrent) cluster.itemsCurr.Add(oi); else if (oi.myBook == OverlapInfo.kRevision) cluster.itemsRev.Add(oi); // update the cluster reference range if (oi.verseRefMin < cluster.verseRefMin || cluster.verseRefMin == 0) cluster.verseRefMin = oi.verseRefMin; if (oi.verseRefMax > cluster.verseRefMax) cluster.verseRefMax = oi.verseRefMax; }