/// <summary> /// Get the items to be compared against the filter. /// </summary> /// <param name="item"></param> /// <returns></returns> protected override int[] GetItems(ManyOnePathSortItem item) { ISilDataAccess sda = m_cache.MainCacheAccessor; List<int> results = new List<int>(); if (item.PathLength > 0 && item.PathFlid(0) == kflidMsas) { // sorted by MSA, match just the one MSA. // I don't think this path can occur with the current XML spec where this is used. int hvoMsa; if (item.PathLength > 1) hvoMsa = item.PathObject(1); else hvoMsa = item.KeyObject; GetItemsForMsaType(sda, ref results, hvoMsa); } else if (item.PathLength >= 1 && item.PathFlid(0) == kflidEntrySenses) { // sorted in a way that shows one sense per row, test that sense's MSA. int hvoSense; if (item.PathLength > 1) hvoSense = item.PathObject(1); else hvoSense = item.KeyObject; int hvoMsa = sda.get_ObjectProp(hvoSense, (int)LexSense.LexSenseTags.kflidMorphoSyntaxAnalysis); GetItemsForMsaType(sda, ref results, hvoMsa); } else { int hvoEntry = item.RootObject.Hvo; int cmsa = sda.get_VecSize(hvoEntry, kflidMsas); for (int imsa = 0; imsa < cmsa; imsa++) { int hvoMsa = sda.get_VecItem(hvoEntry, kflidMsas, imsa); GetItemsForMsaType(sda, ref results, hvoMsa); } } return results.ToArray(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Checks if we are sorted by column of the given flid, and if so returns the hvo for that item. /// </summary> /// <param name="flid">The flid.</param> /// <param name="iPathFlid">The i path flid.</param> /// <param name="item">The item.</param> /// <param name="hvo">The hvo.</param> /// <returns> /// <c>true</c> if [is sorted by field] [the specified flid]; otherwise, <c>false</c>. /// </returns> /// ------------------------------------------------------------------------------------ static internal bool IsSortedByField(int flid, int iPathFlid, ManyOnePathSortItem item, out int hvo) { hvo = 0; if (item.PathLength > iPathFlid && item.PathFlid(iPathFlid) == flid) { if ((item.PathLength > 1) && (item.PathLength != (iPathFlid + 1))) hvo = item.PathObject(1); else hvo = item.KeyObject; return true; } return false; }
/// <summary> /// Gets the sort key by traversing the part tree, calling the sort method at the leaves. /// </summary> /// <param name="layout">The layout.</param> /// <param name="cmo">The object.</param> /// <param name="item">The item.</param> /// <param name="pathIndex">Index of the path.</param> /// <param name="sortedFromEnd">if set to <c>true</c> [sorted from end].</param> /// <returns></returns> private string GetKey(XmlNode layout, ICmObject cmo, ManyOnePathSortItem item, int pathIndex, bool sortedFromEnd) { if (layout == null) return null; switch (layout.Name) { case "obj": { int flid = GetFlid(layout, cmo.Hvo); if (pathIndex != -1 && (pathIndex == item.PathLength || flid != item.PathFlid(pathIndex))) // we are now off of the path pathIndex = -1; int objHvo = m_cache.GetObjProperty(cmo.Hvo, flid); if (objHvo != 0) { if (pathIndex != -1 && (pathIndex < item.PathLength - 1 && objHvo == item.PathObject(pathIndex + 1)) || (pathIndex == item.PathLength - 1 && objHvo == item.KeyObject)) { return GetChildObjKey(layout, objHvo, item, pathIndex + 1, sortedFromEnd); } // we are off of the path return GetChildObjKey(layout, objHvo, item, -1, sortedFromEnd); } } break; case "seq": { int flid = GetFlid(layout, cmo.Hvo); if (pathIndex != -1 && (pathIndex == item.PathLength || flid != item.PathFlid(pathIndex))) // we are now off of the path pathIndex = -1; int size = m_cache.GetVectorSize(cmo.Hvo, flid); StringBuilder sb = null; for (int i = 0; i < size; i++) { int objHvo = m_cache.GetVectorItem(cmo.Hvo, flid, i); if (pathIndex != -1 && (pathIndex < item.PathLength - 1 && objHvo == item.PathObject(pathIndex + 1)) || (pathIndex == item.PathLength - 1 && objHvo == item.KeyObject)) { return GetChildObjKey(layout, objHvo, item, pathIndex + 1, sortedFromEnd); } // if we are off of the path, we concatenate all vector keys to create an // aggregate key string childObjKey = GetChildObjKey(layout, objHvo, item, -1, sortedFromEnd); if (childObjKey != null) { if (sb == null) sb = new StringBuilder(); sb.Append(childObjKey); } } if (sb != null) return sb.ToString(); } break; case "layout": case "part": { string partref = XmlUtils.GetOptionalAttributeValue(layout, "ref"); if (partref != null) { XmlNode part = XmlVc.GetNodeForPart(cmo.Hvo, partref, true, m_sda, m_layouts); return GetKey(part, cmo, item, pathIndex, sortedFromEnd); } foreach (XmlNode child in layout.ChildNodes) { if (child is XmlComment) continue; string key = GetKey(child, cmo, item, pathIndex, sortedFromEnd); if (key != null) return key; } } break; } return null; }
/// <summary> /// Recursive implementation method for GetDisplayCommandForColumn. /// </summary> /// <param name="bvi"></param> /// <param name="node"></param> /// <param name="mdc"></param> /// <param name="sda"></param> /// <param name="layouts"></param> /// <param name="depth"></param> /// <param name="hvo"></param> /// <param name="collectOuterStructParts"></param> /// <returns></returns> static NodeDisplayCommand GetDisplayCommandForColumn1(ManyOnePathSortItem bvi, XmlNode node, IFwMetaDataCache mdc, ISilDataAccess sda, LayoutCache layouts, int depth, out int hvo, List<XmlNode> collectOuterStructParts) { hvo = bvi.PathObject(depth); // default switch(node.Name) { case "obj": case "seq": { // These two cases are the same here, because if the field matches, the object // that determines the next step comes from the bvi, not from one or many items // in the property. if (bvi.PathLength == depth) { // No more path, we display the final object using the node we've deduced is // appropriate for it. // (We could put this test outside the switch. But then we don't dig into // layout, para, span, etc elements at the end of the chain. It's more // consistent if we always dig as deep as we can. hvo = bvi.KeyObject; return new NodeDisplayCommand(node); } int clsid = sda.get_IntProp(bvi.PathObject(depth), (int)CmObjectFields.kflidCmObject_Class); int flid = (int)mdc.GetFieldId2((uint)clsid, XmlUtils.GetManditoryAttributeValue(node, "field"), true); if (flid != bvi.PathFlid(depth)) return new NodeDisplayCommand(node); // different field, can't dig deeper. int hvoDst = bvi.PathObject(depth + 1); // If the path object has been deleted, fall back to displaying whatever the property currently holds. if (sda.get_IntProp(hvoDst, (int)CmObjectFields.kflidCmObject_Class) == 0) return new NodeDisplayCommand(node); // different field, can't dig deeper. // At this point we have to mimic the process that XmlVc uses to come up with the // node that will be used to process the destination item. XmlNode dstNode = GetNodeForRelatedObject(hvoDst, null, node, layouts, sda); return GetDisplayCommandForColumn1(bvi, dstNode, mdc, sda, layouts, depth + 1, out hvo, collectOuterStructParts); } case "para": case "span": case "div": case "concpara": case "innerpile": { XmlNode mainChild = FindMainChild(node); if (mainChild == null) return new NodeDisplayCommand(node); // can't usefully go further. if (collectOuterStructParts != null) collectOuterStructParts.Add(node); return GetDisplayCommandForColumn1(bvi, mainChild, mdc, sda, layouts, depth, out hvo, collectOuterStructParts); } // Review JohnT: In XmlVc, "part" is the one thing that calls ProcessChildren with non-null caller. // this should make some difference here, but I can't figure what yet, or come up with a test that fails. // We may need a "caller" argument to pass this down so it can be used in GetNodeForRelatedObject. case "part": { string layoutName = XmlUtils.GetOptionalAttributeValue(node, "ref"); if (layoutName != null) { // It's actually a part ref, in a layout, not a part looked up by one! // Get the node it refers to, and make a command to process its children. XmlNode part = XmlVc.GetNodeForPart(hvo, layoutName, false, sda, layouts); if (part != null) return new NodeChildrenDisplayCommand(part); // display this object using the children of the part referenced. else return new NodeDisplayCommand(node); // no matching part, do default. } // These are almost the same, but are never added to collectOuterStructParts. // Also, expecially in the case of 'layout', they may result from unification, and be meaningless // except for their children; in any case, the children are all we want to process. // This is the main reason we return a command, not just a node: this case has to return the subclass. XmlNode mainChild = FindMainChild(node); if (mainChild == null) return new NodeChildrenDisplayCommand(node); // can't usefully go further. return GetDisplayCommandForColumn1(bvi, mainChild, mdc, sda, layouts, depth, out hvo, collectOuterStructParts); } case "column": case "layout": { // These are almost the same as para, span, etc, but are never added to collectOuterStructParts. // Also, expecially in the case of 'layout', they may result from unification, and be meaningless // except for their children; in any case, the children are all we want to process. // This is the main reason we return a command, not just a node: this case has to return the subclass. XmlNode mainChild = FindMainChild(node); if (mainChild == null) return new NodeChildrenDisplayCommand(node); // can't usefully go further. return GetDisplayCommandForColumn1(bvi, mainChild, mdc, sda, layouts, depth, out hvo, collectOuterStructParts); } default: // If we can't find anything clever to do, we display the object at the // current level using the current node. return new NodeDisplayCommand(node); } }