/// <summary> /// Executes in two distinct scenarios. /// /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing"></param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// /// If subclasses override this method, they should call the base implementation. /// </remarks> protected virtual void Dispose(bool disposing) { //Debug.WriteLineIf(!disposing, "****************** " + GetType().Name + " 'disposing' is false. ******************"); // Must not be run more than once. if (m_isDisposed) { return; } if (disposing) { // Dispose managed resources here. // does not belong to us! // if (m_layouts != null) // m_layouts.Dispose(); } // Dispose unmanaged resources here, whether disposing is true or false. m_sda = null; m_layoutName = null; m_mdc = null; m_cache = null; m_layouts = null; m_colSpec = null; m_isDisposed = true; }
/// <summary> /// Returns an array of string values (keys) for the objects under this layout node. /// </summary> /// <param name="fdoCache">The fdo cache.</param> /// <param name="sda">The sda.</param> /// <param name="layout">The layout.</param> /// <param name="hvo">The hvo.</param> /// <param name="layoutCache">The layout cache.</param> /// <param name="caller">where layout is a component of a 'part' element, caller /// is the 'part ref' that invoked it.</param> /// <param name="stringTbl">The string TBL.</param> /// <param name="wsForce">if non-zero, "string" elements are forced to use that writing system for multistrings.</param> /// <returns></returns> static public string[] StringsFor(FdoCache fdoCache, ISilDataAccess sda, XmlNode layout, int hvo, LayoutCache layoutCache, XmlNode caller, StringTable stringTbl, int wsForce) { // Some nodes are known to be uninteresting. if (XmlVc.CanSkipNode(layout)) return new string[0]; // don't know how to sort, treat as empty key. switch (layout.Name) { case "string": { int hvoTarget = hvo; XmlVc.GetActualTarget(layout, ref hvoTarget, sda); // modify the hvo if needed if (hvo != hvoTarget) { return AddStringFromOtherObj(layout, hvoTarget, fdoCache, sda); } int flid = GetFlid(sda, layout, hvo); if (wsForce != 0) { // If we are forcing a writing system, and it's a multistring, get the forced alternative. int itype = sda.MetaDataCache.GetFieldType(flid); itype = itype & (int)CellarPropertyTypeFilter.VirtualMask; switch (itype) { case (int) CellarPropertyType.MultiUnicode: case (int) CellarPropertyType.MultiString: if (wsForce < 0) { int wsActual; var tss = WritingSystemServices.GetMagicStringAlt(fdoCache, sda, wsForce, hvo, flid, true, out wsActual); return new[] {tss == null ? "" : tss.Text }; } return new[] {sda.get_MultiStringAlt(hvo, flid, wsForce).Text}; } } bool fFoundType; var strValue = fdoCache.GetText(hvo, flid, layout, out fFoundType); if (fFoundType) return new[] {strValue}; throw new Exception("Bad property type (" + strValue + " for hvo " + hvo + " found for string property " + flid + " in " + layout.OuterXml); } case "configureMlString": { int flid = GetFlid(sda, layout, hvo); // The Ws info specified in the part ref node HashSet<int> wsIds = WritingSystemServices.GetAllWritingSystems(fdoCache, caller, null, hvo, flid); if (wsIds.Count == 1) { var strValue = sda.get_MultiStringAlt(hvo, flid, wsIds.First()).Text; return new[] {strValue}; } return new[] {AddMultipleAlternatives(fdoCache, sda, wsIds, hvo, flid, caller)}; } case "multiling": return ProcessMultiLingualChildren(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); case "layout": // "layout" can occur when GetNodeToUseForColumn returns a phony 'layout' // formed by unifying a layout with child nodes. Assemble its children. // (arguably, we should treat that like div if current flow is a pile. // but we can't tell that and it rarely makes a difference.) case "para": case "span": { return AssembleChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); } case "column": // top-level node for whole column; concatenate children as for "para" // if multipara is false, otherwise as for "div" if (XmlUtils.GetOptionalBooleanAttributeValue(layout, "multipara", false)) return ChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); else return AssembleChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); case "part": { string partref = XmlUtils.GetOptionalAttributeValue(layout, "ref"); if (partref == null) return ChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); // an actual part, made up of its pieces XmlNode part = XmlVc.GetNodeForPart(hvo, partref, false, sda, layoutCache); // This is the critical place where we introduce a caller. The 'layout' is really a 'part ref' which is the // 'caller' for all embedded nodes in the called part. return StringsFor(fdoCache, sda, part, hvo, layoutCache, layout, stringTbl, wsForce); } case "div": case "innerpile": { // Concatenate keys for child nodes (as distinct strings) return ChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce); } case "obj": { // Follow the property, get the object, look up the layout to use, // invoke recursively. int flid = GetFlid(sda, layout, hvo); int hvoTarget = sda.get_ObjectProp(hvo, flid); if (hvoTarget == 0) break; // return empty key string targetLayoutName = XmlUtils.GetOptionalAttributeValue(layout, "layout"); // uses 'default' if missing. XmlNode layoutTarget = GetLayoutNodeForChild(sda, hvoTarget, flid, targetLayoutName, layout, layoutCache); if (layoutTarget == null) break; return ChildKeys(fdoCache, sda, layoutTarget, hvoTarget, layoutCache, caller, stringTbl, wsForce); } case "seq": { // Follow the property. For each object, look up the layout to use, // invoke recursively, concatenate int flid = GetFlid(sda, layout, hvo); int[] contents; int ctarget = sda.get_VecSize(hvo, flid); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative<int>(ctarget)) { int chvo; sda.VecProp(hvo, flid, ctarget, out chvo, arrayPtr); contents = MarshalEx.NativeToArray<int>(arrayPtr, chvo); } string[] result = null; string targetLayoutName = XmlVc.GetLayoutName(layout, caller); // also allows for finding "param" attr in caller, if not null int i = 0; foreach (int hvoTarget in contents) { int prevResultLength = GetArrayLength(result); XmlNode layoutTarget = GetLayoutNodeForChild(sda, hvoTarget, flid, targetLayoutName, layout, layoutCache); if (layoutTarget == null) continue; // should not happen, but best recovery we can make result = Concatenate(result, ChildKeys(fdoCache, sda, layoutTarget, hvoTarget, layoutCache, caller, stringTbl, wsForce)); // add a separator between the new childkey group and the previous childkey group if (i > 0 && prevResultLength != GetArrayLength(result) && prevResultLength > 0) { int ichIns = 0; if (result[prevResultLength - 1] != null) ichIns = result[prevResultLength - 1].Length; AddSeparator(ref result[prevResultLength - 1], ichIns, layout); } ++i; } return result; } case "choice": { foreach(XmlNode whereNode in layout.ChildNodes) { if (whereNode.Name != "where") { if (whereNode.Name == "otherwise") return StringsFor(fdoCache, sda, XmlUtils.GetFirstNonCommentChild(whereNode), hvo, layoutCache, caller, stringTbl, wsForce); continue; // ignore any other nodes,typically comments } // OK, it's a where node. if (XmlVc.ConditionPasses(whereNode, hvo, fdoCache, sda, caller)) return StringsFor(fdoCache, sda, XmlUtils.GetFirstNonCommentChild(whereNode), hvo, layoutCache, caller, stringTbl, wsForce); } break; // if no condition passes and no otherwise, return null. } case "if": { if (XmlVc.ConditionPasses(layout, hvo, fdoCache, sda, caller)) return StringsFor(fdoCache, sda, XmlUtils.GetFirstNonCommentChild(layout), hvo, layoutCache, caller, stringTbl, wsForce); break; } case "ifnot": { if (!XmlVc.ConditionPasses(layout, hvo, fdoCache, sda, caller)) return StringsFor(fdoCache, sda, XmlUtils.GetFirstNonCommentChild(layout), hvo, layoutCache, caller, stringTbl, wsForce); break; } case "lit": { string literal = layout.InnerText; if (stringTbl != null) { string sTranslate = XmlUtils.GetOptionalAttributeValue(layout, "translate", ""); if (sTranslate.Trim().ToLower() != "do not translate") literal = stringTbl.LocalizeLiteralValue(literal); } return new[] { literal }; } case "int": { int flid = GetFlid(sda, layout, hvo); int val = sda.get_IntProp(hvo, flid); return new[] {AlphaCompNumberString(val)}; } case "datetime": { int flid = GetFlid(sda, layout, hvo); CellarPropertyType itype = (CellarPropertyType)sda.MetaDataCache.GetFieldType(flid); if (itype == CellarPropertyType.Time) { DateTime dt = SilTime.GetTimeProperty(sda, hvo, flid); return new[] {DateTimeCompString(dt)}; } else { string stFieldName = XmlUtils.GetManditoryAttributeValue(layout, "field"); throw new Exception("Bad field type (" + stFieldName + " for hvo " + hvo + " found for " + layout.Name + " property " + flid + " in " + layout.OuterXml); } } case "picture": // Treat a picture as a non-empty string for purposes of deciding whether something is empty. // This string seems as good as anything for other purposes. return new[] {"a picture"}; default: // unknown or comment node, adds nothing Debug.Assert(false, "unrecognized XML node."); break; } return new string[0]; // don't know how to sort, treat as empty key. }
static private string[] AssembleChildKeys(FdoCache fdoCache, ISilDataAccess sda, XmlNode layout, int hvo, LayoutCache layoutCache, XmlNode caller, StringTable stringTbl, int wsForce) { return Assemble(ChildKeys(fdoCache, sda, layout, hvo, layoutCache, caller, stringTbl, wsForce)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Returns an array of string values (keys) for the objects under the layout child nodes. /// </summary> /// ------------------------------------------------------------------------------------ static internal string[] ChildKeys(FdoCache fdoCache, ISilDataAccess sda, XmlNode layout, int hvo, LayoutCache layoutCache, XmlNode caller, StringTable stringTbl, int wsForce) { string[] result = null; foreach (XmlNode child in layout.ChildNodes) { if (child is XmlComment) continue; result = Concatenate(result, StringsFor(fdoCache, sda, child, hvo, layoutCache, caller, stringTbl, wsForce)); } return result; }
/// ------------------------------------------------------------------------------------ /// <summary> /// The node argument is an "obj" or "seq" element, and caller (if not null) is a part /// element that invoked the node and may override its "layout" attribute. /// Apply the same logic used by XmlVc to determine the node that will be used /// to display the destination object hvoDst /// </summary> /// <param name="hvoDst">The hvo DST.</param> /// <param name="caller">The caller.</param> /// <param name="node">The node.</param> /// <param name="layouts">The layouts.</param> /// <param name="sda">The sda.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ static XmlNode GetNodeForRelatedObject(int hvoDst, XmlNode caller, XmlNode node, LayoutCache layouts, ISilDataAccess sda) { if (XmlUtils.GetOptionalAttributeValue(node, "frag") != null) return null; // old approach not handled. // (frag="true" is also used to prevent splitting entry when sorting on gloss or // allomorph in Find Entries dialog display. Part of fixing LT-10293.) string layoutName = XmlVc.GetLayoutName(node, caller); XmlNode layoutNode = XmlVc.GetNodeForPart(hvoDst, layoutName, true, sda, layouts); return XmlVc.GetDisplayNodeForChild(layoutNode, node, layouts); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Main (recursive) part of CollectBrowseItems. Given that hvo is to be displayed using node, /// figure what objects to put in the list. /// </summary> /// <param name="hvo">The hvo.</param> /// <param name="node">The node.</param> /// <param name="collector">The collector.</param> /// <param name="mdc">The MDC.</param> /// <param name="sda">The sda.</param> /// <param name="layouts">The layouts.</param> /// <param name="caller">The caller.</param> /// <param name="hvos">The hvos.</param> /// <param name="flids">The flids.</param> /// ------------------------------------------------------------------------------------ static void CollectBrowseItems(int hvo, XmlNode node, ArrayList collector, IFwMetaDataCache mdc, ISilDataAccess sda, LayoutCache layouts, XmlNode caller, int[] hvos, int[] flids) { switch(node.Name) { case "obj": { int clsid = sda.get_IntProp(hvo, CmObjectTags.kflidClass); int flid = mdc.GetFieldId2(clsid, XmlUtils.GetManditoryAttributeValue(node, "field"), true); int hvoDst = sda.get_ObjectProp(hvo, flid); if (hvoDst == 0) { // We want a row, even though it's blank for this column. collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); return; } // 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, caller, node, layouts, sda); if (dstNode == null) { // maybe an old-style "frag" element? Anyway, we can't do anything smart, // so just insert the original object. collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); return; } CollectBrowseItems(hvoDst, dstNode, collector, mdc, sda, layouts, null, AppendInt(hvos, hvo), AppendInt(flids, flid)); } break; case "seq": { // very like "obj" except for the loop. How could we capture this? int clsid = sda.get_IntProp(hvo, CmObjectTags.kflidClass); int flid = mdc.GetFieldId2(clsid, XmlUtils.GetManditoryAttributeValue(node, "field"), true); int chvo = sda.get_VecSize(hvo, flid); if (chvo == 0) { // We want a row, even though it's blank for this column. collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); return; } for (int ihvo = 0; ihvo < chvo; ihvo++) { int hvoDst = sda.get_VecItem(hvo, flid, ihvo); // 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, caller, node, layouts, sda); if (dstNode == null) { if (ihvo == 0) { // maybe an old-style "frag" element? Anyway, we can't do anything smart, // so just insert the original object. collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); return; } // if this happens and it's not the first object, we have a funny mixture of modes. // As a fall-back, skip this object. continue; } CollectBrowseItems(hvoDst, dstNode, collector, mdc, sda, layouts, null, AppendInt(hvos, hvo), AppendInt(flids, flid)); } } break; case "span": case "para": case "div": case "concpara": case "innerpile": case "column": // 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. case "part": case "layout": // These are grouping nodes. In general this terminates things. However, if there is only // one thing embedded apart from comments and properties, we can proceed. XmlNode mainChild = FindMainChild(node); if (mainChild == null) { // no single non-trivial child, keep our current object collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); return; } // Recurse with same object, but process the 'main child'. CollectBrowseItems(hvo, mainChild, collector, mdc, sda, layouts, caller, hvos, flids); break; default: collector.Add(new ManyOnePathSortItem(hvo, hvos, flids)); break; } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Given one of the original list items, and the spec of the column we want to sort by, /// add to collector whatever ManyOnePathSortItems are appropriate. /// </summary> /// <param name="hvo">The hvo.</param> /// <param name="colSpec">The col spec.</param> /// <param name="collector">The collector.</param> /// <param name="mdc">The MDC.</param> /// <param name="sda">The sda.</param> /// <param name="layouts">The layouts.</param> /// ------------------------------------------------------------------------------------ public static void CollectBrowseItems(int hvo, XmlNode colSpec, ArrayList collector, IFwMetaDataCache mdc, ISilDataAccess sda, LayoutCache layouts) { XmlNode topNode = XmlBrowseViewBaseVc.GetColumnNode(colSpec, hvo, sda, layouts); // Todo: handle various cases here, mostly drill-down to <seq> or <obj> CollectBrowseItems(hvo, topNode, collector, mdc, sda, layouts, null, null, null); }
/// ------------------------------------------------------------------------------------ /// <summary> /// We want to display the object bvi.KeyObject, or one of its pathobjects, in a /// column specified by colSpec. /// Determine the hvo and XmlNode that we should use as the root for the cell. /// By default, we display the first object in the path, using the base node /// derived from the colSpec. /// However, if the colSpec begins with a path compatible with bvi.PathFlid(0), /// we can use bvi.PathObject(1) and the appropriate derived node. /// If all flids match we can use bvi.KeyObject itself. /// If collectOuterStructParts is non-null, it accumulates containing parts /// that are structural, like para, span, div. /// </summary> /// <param name="bvi">The bvi.</param> /// <param name="colSpec">The col spec.</param> /// <param name="mdc">The MDC.</param> /// <param name="sda">The sda.</param> /// <param name="layouts">The layouts.</param> /// <param name="hvo">The hvo.</param> /// <param name="collectOuterStructParts">The collect outer struct parts.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public static XmlNode GetNodeToUseForColumn(IManyOnePathSortItem bvi, XmlNode colSpec, IFwMetaDataCache mdc, ISilDataAccess sda, LayoutCache layouts, out int hvo, List<XmlNode> collectOuterStructParts) { return GetDisplayCommandForColumn(bvi, colSpec, mdc, sda, layouts, out hvo, collectOuterStructParts).Node; }
/// <summary> /// This returns a NodeDisplayCommand containing thd node for GetNodeToUseForColumn. However, it distinguishes whether to /// display the children of this node or the node itself by returning the appropriate kind of NodeDisplayCommand. /// </summary> /// <param name="bvi"></param> /// <param name="colSpec"></param> /// <param name="mdc"></param> /// <param name="sda"></param> /// <param name="layouts"></param> /// <param name="hvo"></param> /// <param name="collectOuterStructParts"></param> /// <returns></returns> public static NodeDisplayCommand GetDisplayCommandForColumn(IManyOnePathSortItem bvi, XmlNode colSpec, IFwMetaDataCache mdc, ISilDataAccess sda, LayoutCache layouts, out int hvo, List<XmlNode> collectOuterStructParts) { XmlNode topNode = XmlBrowseViewBaseVc.GetColumnNode(colSpec, bvi.PathObject(0), sda, layouts); return GetDisplayCommandForColumn1(bvi, topNode, mdc, sda, layouts, 0, out hvo, collectOuterStructParts); }
public override void FixtureSetup() { base.FixtureSetup(); SetupTestModel(Resources.TextCacheModel_xml); m_sda = new RealDataCache(); m_sda.MetaDataCache = MetaDataCache.CreateMetaDataCache("TestModel.xml"); //m_cache.ParaContentsFlid = kflidParaContents; //m_cache.ParaPropertiesFlid = kflidParaProperties; //m_cache.TextParagraphsFlid = kflidTextParas; Debug.Assert(m_wsManager == null); m_wsManager = Cache.ServiceLocator.GetInstance<IWritingSystemManager>(); m_sda.WritingSystemFactory = m_wsManager; m_wsAnal = Cache.DefaultAnalWs; m_wsVern = Cache.DefaultVernWs; //IWritingSystem deWs; //m_wsManager.GetOrSet("de", out deWs); //m_wsDeu = deWs.Handle; //m_wsManager.UserWs = m_wsEng; //m_wsUser = m_wsManager.UserWs; m_tsf = TsStrFactoryClass.Create(); m_hvoLexDb = m_sda.MakeNewObject(kclsidLexDb, 0, -1, -1); kflidLexDb_Entries = m_sda.MetaDataCache.GetFieldId("LexDb", "Entries", false); kflidEntry_Form = m_sda.MetaDataCache.GetFieldId("Entry", "Form", false); kflidEntry_Summary = m_sda.MetaDataCache.GetFieldId("Entry", "Summary", false); m_hvoKick = m_sda.MakeNewObject(kclsidEntry, m_hvoLexDb, kflidLexDb_Entries, 0); m_sda.SetMultiStringAlt(m_hvoKick, kflidEntry_Form, m_wsVern, m_tsf.MakeString("kick", m_wsVern)); m_sda.SetString(m_hvoKick, kflidEntry_Summary, m_tsf.MakeString("strike with foot", m_wsAnal)); var keyAttrs = new Dictionary<string, string[]>(); keyAttrs["layout"] = new[] { "class", "type", "name", "choiceGuid" }; keyAttrs["group"] = new[] { "label" }; keyAttrs["part"] = new[] { "ref" }; var layoutInventory = new Inventory("*.fwlayout", "/LayoutInventory/*", keyAttrs, "test", "nowhere"); layoutInventory.LoadElements(Resources.Layouts_xml, 1); keyAttrs = new Dictionary<string, string[]>(); keyAttrs["part"] = new[] { "id" }; var partInventory = new Inventory("*Parts.xml", "/PartInventory/bin/*", keyAttrs, "test", "nowhere"); partInventory.LoadElements(Resources.Parts_xml, 1); m_layouts = new LayoutCache(m_sda.MetaDataCache, layoutInventory, partInventory); }
static private XmlNode GetLayoutNodeForChild(ISilDataAccess sda, int hvoTarget, int flid, string targetLayoutName, XmlNode layout, LayoutCache layoutCache) { XmlNode layoutTarget = XmlVc.GetNodeForPart(hvoTarget, targetLayoutName, true, sda, layoutCache); if (layoutTarget == null) layoutTarget = layout; // no layout looked up, use whatever children caller has else if (layout.ChildNodes.Count != 0) { // got both a looked-up layout and child nodes overriding. if (layoutTarget.Name == "layout") { // thing we looked up is a layout, we will unify. layoutTarget = layoutCache.LayoutInventory.GetUnified(layoutTarget, layout); } else { // thing we looked up is a part, for now (see XmlVc.Display) we just replace // with supplied parts layoutTarget = layout; } } return layoutTarget; }
public void Setup() { // Create the following: // - part and layout inventories // - metadata cache // - DataAccess cache // - collection of columns to display. // We want a MetaDataCache that knows about // - LexEntry.Senses, Msas, CitationForm, Bibliography, Etymology // - LexSense.SemanticDomains, SenseType, Status, gloss // - CmPossibility Name, abbr // - MoMorphSynAnalysis // - MoStemMsa // - MoDerivationalMsa m_mdc = FwMetaDataCacheClass.Create(); string m_sTestPath = Path.Combine(DirectoryFinder.FwSourceDirectory, @"Common\Controls\XmlViews\XmlViewsTests\SampleCm.xml"); m_mdc.InitXml(m_sTestPath, true); // We want ISilDataAccess with: // - LexEntry (1) with no senses and one MSA (2) // - LexEntry (4) with one sense (5) and no MSA // - LexEntry (6) with three senses (7, 8, 9) and two MSAs (10, 11) // - sense(5) with no semantic domains // - senses with one SD (7->30, 8->31) // - sense with three SDs, one the same as the first (9->30, 31, 32) // - MoStemMsa (2, 11) // - MoDerivationalMsa (10) m_cda = VwCacheDaClass.Create(); m_sda = m_cda as ISilDataAccess; m_wsf = LgWritingSystemFactoryClass.Create(); m_sda.WritingSystemFactory = m_wsf; SimpleDataParser parser = new SimpleDataParser(m_mdc, m_cda); parser.Parse(Path.Combine(DirectoryFinder.FwSourceDirectory, @"Common\Controls\XmlViews\XmlViewsTests\SampleData.xml")); int wsEn = m_wsf.GetWsFromStr("en"); // These are mainly to check out the parser. Assert.AreEqual(3, m_sda.get_ObjectProp(2, 23011), "part of speech of an MoStemMsa"); Assert.AreEqual(2, m_sda.get_VecItem(1, 2009, 0), "owned msa"); Assert.AreEqual("noun", m_sda.get_MultiStringAlt(3, 7003, wsEn).Text, "got ms property"); Assert.AreEqual(9, m_sda.get_VecItem(6, 2010, 2), "3rd sense"); Assert.AreEqual(31, m_sda.get_VecItem(9, 21016, 1), "2nd semantic domain"); // Columns includes // - CitationForm (string inside span) // - Bibliography (string not in span) // - Sense glosses (string in para in seq, nested in column element) // - Semantic domains (pair of strings in para in seq in seq, using layout refs) // - MSAs (simplified, but polymorphic with one having <choice> and one <obj> to CmPossibility XmlDocument docColumns = new XmlDocument(); docColumns.Load(Path.Combine(DirectoryFinder.FwSourceDirectory, @"Common\Controls\XmlViews\XmlViewsTests\TestColumns.xml")); m_columnList = docColumns.DocumentElement.ChildNodes; // Parts just has what those columns need. string partDirectory = Path.Combine(DirectoryFinder.FwSourceDirectory, @"Common\Controls\XmlViews\XmlViewsTests"); Dictionary<string, string[]> keyAttrs = new Dictionary<string, string[]>(); keyAttrs["layout"] = new string[] {"class", "type", "name" }; keyAttrs["group"] = new string[] {"label"}; keyAttrs["part"] = new string[] {"ref"}; // Currently there are no specialized layout files that match. m_layoutInventory = new Inventory(new string[] {partDirectory}, "*Layouts.xml", "/LayoutInventory/*", keyAttrs); keyAttrs = new Dictionary<string, string[]>(); keyAttrs["part"] = new string[] {"id"}; m_partInventory = new Inventory(new string[] {partDirectory}, "TestParts.xml", "/PartInventory/bin/*", keyAttrs); if (m_layouts != null) m_layouts.Dispose(); m_layouts = new LayoutCache(m_mdc, m_layoutInventory, m_partInventory); }
public void Teardown() { if (m_wsf != null && Marshal.IsComObject(m_wsf)) { m_wsf.Shutdown(); Marshal.ReleaseComObject(m_wsf); } m_wsf = null; if (Marshal.IsComObject(m_cda)) { Marshal.ReleaseComObject(m_cda); } m_cda = null; if (Marshal.IsComObject(m_mdc)) { Marshal.ReleaseComObject(m_mdc); } m_mdc = null; if (Marshal.IsComObject(m_sda)) { Marshal.ReleaseComObject(m_sda); } m_sda = null; m_layoutInventory = null; m_columnList = null; m_layouts = null; m_partInventory = null; }
/// <summary> /// Given the "column" element that describes a column of a browse view, /// come up with the XmlNode whose children will be the actual parts (or part refs) /// to use to display the contents. /// </summary> /// <param name="column"></param> /// <param name="hvo"></param> /// <param name="sda"></param> /// <param name="layouts"></param> /// <returns></returns> public static XmlNode GetColumnNode(XmlNode column, int hvo, ISilDataAccess sda, LayoutCache layouts) { XmlNode nodeToProcess = column; string layoutName = XmlUtils.GetOptionalAttributeValue(column, "layout"); if (layoutName != null) { // new approach: display the object using the specified layout. XmlNode nodeInner = GetNodeForPart(hvo, layoutName, true, sda, layouts); if (nodeInner != null) nodeToProcess = nodeInner; } return nodeToProcess; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Process a fragment's children against multiple writing systems. /// </summary> /// ------------------------------------------------------------------------------------ static private string[] ProcessMultiLingualChildren(FdoCache fdoCache, ISilDataAccess sda, XmlNode frag, int hvo, LayoutCache layoutCache, XmlNode caller, StringTable stringTbl, int wsForce) { string sWs = XmlUtils.GetOptionalAttributeValue(frag, "ws"); if (sWs == null) return null; Debug.Assert(s_qwsCurrent == null); Debug.Assert(s_cwsMulti == 0); string[] result = null; try { HashSet<int> wsIds = WritingSystemServices.GetAllWritingSystems(fdoCache, frag, s_qwsCurrent, 0, 0); s_cwsMulti = wsIds.Count; if (s_cwsMulti > 1) s_sMultiSep = XmlUtils.GetOptionalAttributeValue(frag, "sep"); s_fMultiFirst = true; foreach (int WSId in wsIds) { s_qwsCurrent = fdoCache.ServiceLocator.WritingSystemManager.Get(WSId); result = Concatenate(result, ChildKeys(fdoCache, sda, frag, hvo, layoutCache, caller, stringTbl, wsForce)); } } finally { // Make sure these are reset, no matter what. s_qwsCurrent = null; s_cwsMulti = 0; s_sMultiSep = null; s_fMultiFirst = false; } return result; }
/// <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(IManyOnePathSortItem 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), CmObjectTags.kflidClass); int flid = mdc.GetFieldId2(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, CmObjectTags.kflidClass) == 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); } }
/// <summary> /// Executes in two distinct scenarios. /// /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing"></param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// /// If subclasses override this method, they should call the base implementation. /// </remarks> protected virtual void Dispose(bool disposing) { //Debug.WriteLineIf(!disposing, "****************** " + GetType().Name + " 'disposing' is false. ******************"); // Must not be run more than once. if (m_isDisposed) return; if (disposing) { // Dispose managed resources here. // does not belong to us! // if (m_layouts != null) // m_layouts.Dispose(); } // Dispose unmanaged resources here, whether disposing is true or false. m_sda = null; m_layoutName = null; m_mdc = null; m_cache = null; m_layouts = null; m_colSpec = null; m_isDisposed = true; }
public void Teardown() { if (Marshal.IsComObject(m_cda)) { Marshal.ReleaseComObject(m_cda); } m_cda = null; if (Marshal.IsComObject(m_mdc)) { Marshal.ReleaseComObject(m_mdc); } m_mdc = null; if (Marshal.IsComObject(m_sda)) { Marshal.ReleaseComObject(m_sda); } m_sda = null; m_layoutInventory = null; m_columnList = null; m_layouts = null; m_partInventory = null; m_wsManager = null; }