/// ------------------------------------------------------------------------------------ /// <summary> /// Retrieve properties for all data types and verify that we only get the expected /// values, i.e. the expected data type that we put in the cache. /// </summary> /// <param name="hvo">HVO part of the key</param> /// <param name="tag">tag part of the key</param> /// <param name="expValues">Expected values</param> /// ------------------------------------------------------------------------------------ private void VerifyCache(int hvo, int tag, object[] expValues) { int hvoVal = m_ISilDataAccess.get_ObjectProp(hvo, tag); Assert.AreEqual(expValues[0], hvoVal); int chvo = 99; using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative(10, typeof(int))) { m_ISilDataAccess.VecProp(hvo, tag, 10, out chvo, arrayPtr); if (expValues[1] is int[]) { Assert.AreEqual(((int[])expValues[1]).Length, chvo); } else { Assert.AreEqual(expValues[1], chvo); } m_ISilDataAccess.BinaryPropRgb(hvo, tag, arrayPtr, 10, out chvo); if (expValues[2] is byte[]) { Assert.AreEqual(((byte[])expValues[2]).Length, chvo); } else { Assert.AreEqual(expValues[2], chvo); } Guid guidNew = m_ISilDataAccess.get_GuidProp(hvo, tag); Assert.AreEqual(expValues[3], guidNew); long valLong = m_ISilDataAccess.get_Int64Prop(hvo, tag); Assert.AreEqual(expValues[4], valLong); // Int64 and TimeProp use the same cache valLong = m_ISilDataAccess.get_TimeProp(hvo, tag); Assert.AreEqual(expValues[4], valLong); int valInt = m_ISilDataAccess.get_IntProp(hvo, tag); Assert.AreEqual(expValues[5], valInt); ITsString tsStringNew = m_ISilDataAccess.get_MultiStringAlt(hvo, tag, 12345); Assert.AreEqual(expValues[6], tsStringNew.Text); tsStringNew = m_ISilDataAccess.get_StringProp(hvo, tag); Assert.AreEqual(expValues[7], tsStringNew.Text); string strNew = m_ISilDataAccess.get_UnicodeProp(hvo, tag); Assert.AreEqual(expValues[8], strNew); object obj = m_ISilDataAccess.get_UnknownProp(hvo, tag); Assert.AreEqual(expValues[9], obj); CheckIsPropInCache(hvo, tag, expValues); } }
/// <summary> /// Get the items from a vector property. /// </summary> private static int[] GetVector(ISilDataAccess sda, int hvo, int tag) { var chvo = sda.get_VecSize(hvo, tag); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative <int>(chvo)) { sda.VecProp(hvo, tag, chvo, out chvo, arrayPtr); return(MarshalEx.NativeToArray <int>(arrayPtr, chvo)); } }
public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { ISilDataAccess sda = cda as ISilDataAccess; int cobj = sda.get_VecSize(hvo, m_tagReal); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative(cobj + 1, typeof(int))) // one longer to leave room for dummy { sda.VecProp(hvo, m_tagReal, cobj, out cobj, arrayPtr); int [] rgHvo = (int[])MarshalEx.NativeToArray(arrayPtr, cobj, typeof(int)); rgHvo[cobj] = TypeAheadSupportVc.kBaseFakeObj; cda.CacheVecProp(hvo, tag, rgHvo, cobj + 1); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Print method /// </summary> /// ------------------------------------------------------------------------------------ public override void Print(PrintDocument pd) { CheckDisposed(); bool fPrintSelection = (pd.PrinterSettings.PrintRange == PrintRange.Selection); int[] originalObjects = null; if (fPrintSelection) { IVwSelection sel = RootBox.Selection; int clev = sel.CLevels(true); int hvoObj, tag, ihvoEnd, ihvoAnchor, cpropPrevious; IVwPropertyStore vps; sel.PropInfo(true, clev - 1, out hvoObj, out tag, out ihvoEnd, out cpropPrevious, out vps); clev = sel.CLevels(false); sel.PropInfo(false, clev - 1, out hvoObj, out tag, out ihvoAnchor, out cpropPrevious, out vps); ISilDataAccess sda = m_fdoCache.MainCacheAccessor; int chvoReal = sda.get_VecSize(m_hvoRoot, m_mainFlid); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative(chvoReal, typeof(int))) { sda.VecProp(m_hvoRoot, m_mainFlid, chvoReal, out chvoReal, arrayPtr); originalObjects = (int[])MarshalEx.NativeToArray(arrayPtr, chvoReal, typeof(int)); } int ihvoMin = Math.Min(ihvoEnd, ihvoAnchor); int ihvoLim = Math.Max(ihvoEnd, ihvoAnchor) + 1; int[] selectedObjects = new int[ihvoLim - ihvoMin]; for (int i = 0; i < selectedObjects.Length; i++) { selectedObjects[i] = originalObjects[i + ihvoMin]; } m_fdoCache.VwCacheDaAccessor.CacheVecProp(m_hvoRoot, m_mainFlid, selectedObjects, selectedObjects.Length); } try { base.Print(pd); } finally { if (fPrintSelection) { m_fdoCache.VwCacheDaAccessor.CacheVecProp(m_hvoRoot, m_mainFlid, originalObjects, originalObjects.Length); } } }
public void AutoLoad() { // Get the language project as an FDO object ILangProject lp = m_fdoCache.LangProject; // Use it to get the HVO of the data notebook, but without making an FDO object // and thus loading data. Assert.IsTrue(m_sda.get_IsPropInCache(lp.Hvo, (int)LangProject.LangProjectTags.kflidResearchNotebook, (int)CellarModuleDefns.kcptOwningAtom, 0), "LP notebook loaded by FDO"); int hvoNotebook = m_fdoCache.GetObjProperty(lp.Hvo, (int)LangProject.LangProjectTags.kflidResearchNotebook); // Owning atomic Assert.IsFalse(m_sda.get_IsPropInCache(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidEventTypes, (int)CellarModuleDefns.kcptOwningAtom, 0), "Notebook event types not preloaded"); int hvoEventTypes = m_sda.get_ObjectProp(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidEventTypes); Assert.IsTrue(m_sda.get_IsPropInCache(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidEventTypes, (int)CellarModuleDefns.kcptOwningAtom, 0), "Notebook event types autoloaded"); Assert.IsTrue(hvoEventTypes != 0, "got real event types"); int flidET = m_sda.get_IntProp(hvoEventTypes, (int)CmObjectFields.kflidCmObject_OwnFlid); Assert.AreEqual((int)RnResearchNbk.RnResearchNbkTags.kflidEventTypes, flidET, "owning flid loaded correctly"); int clsidET = m_sda.get_IntProp(hvoEventTypes, (int)CmObjectFields.kflidCmObject_Class); Assert.AreEqual((int)CmPossibilityList.kClassId, clsidET, "class autoloaded"); int ownerET = m_sda.get_ObjectProp(hvoEventTypes, (int)CmObjectFields.kflidCmObject_Owner); Assert.AreEqual(hvoNotebook, ownerET, "owner auto-loaded"); // Todo: test ref atomic. // Owning collection. Assert.IsFalse(m_sda.get_IsPropInCache(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords, (int)CellarModuleDefns.kcptOwningCollection, 0), "Nb records not preloaded"); // Forces a load int chvoRecs = m_sda.get_VecSize(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords); Assert.IsTrue(m_sda.get_IsPropInCache(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords, (int)CellarModuleDefns.kcptOwningCollection, 0), "Nb records autoloaded"); // Be careful what we assert...don't want it too dependent on the exact data. // Should be OK to assume at least a few records. Assert.IsTrue(chvoRecs > 4, "at least 4 recs"); int hvoRec3 = m_sda.get_VecItem(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords, 3); int clsIDR3 = m_sda.get_IntProp(hvoRec3, (int)CmObjectFields.kflidCmObject_Class); Assert.IsTrue((int)RnEvent.kClassId == clsIDR3 || (int)RnAnalysis.kClassId == clsIDR3, "class of rec 3 valid"); Assert.IsFalse(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidResearchers, (int)CellarModuleDefns.kcptReferenceCollection, 0), "R3 researchers not preloaded"); int chvoR3Researchers = m_sda.get_VecSize(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidResearchers); Assert.IsTrue(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidResearchers, (int)CellarModuleDefns.kcptReferenceCollection, 0), "R3 researchers autoloaded"); // We can't assume anything about any one record, but we should be able to find // at least one where researchers is non-empty. Along the way we do at least // some testing of VecProp and also make sure we can load a string that is a // BigString bool fGotEmpty = false; bool fGotNonEmpty = false; bool fGotEvent = false; int hvoEvent = 0; // some record will be an event... int hvoText = 0; // that has a non-empty structured text... int hvoPara = 0; // that has a non-empty paragraph with a label. for (int ihvo = 0; ihvo < chvoRecs && ((!fGotEmpty) || (!fGotNonEmpty) || (!fGotEvent) || hvoText == 0); ihvo++) { int hvoRec = m_sda.get_VecItem(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords, ihvo); int chvoResearchers = m_sda.get_VecSize(hvoRec, (int)RnGenericRec.RnGenericRecTags.kflidResearchers); if (chvoResearchers > 0) { if (!fGotNonEmpty) { fGotNonEmpty = true; // Try this on the first non-empty list. int hvoResearcher = m_sda.get_VecItem(hvoRec, (int)RnGenericRec.RnGenericRecTags.kflidResearchers, 0); int clsidResearcher = m_sda.get_IntProp(hvoResearcher, (int)CmObjectFields.kflidCmObject_Class); Assert.AreEqual(CmPerson.kClassId, clsidResearcher, "class of researcher"); } } else { fGotEmpty = true; // should now be considered cached anyway. Assert.IsTrue(m_sda.get_IsPropInCache(hvoRec, (int)RnGenericRec.RnGenericRecTags.kflidResearchers, (int)CellarModuleDefns.kcptReferenceCollection, 0), "empty researchers autoloaded"); } int clsIDRec = m_sda.get_IntProp(hvoRec, (int)CmObjectFields.kflidCmObject_Class); if (clsIDRec == (int)RnEvent.kClassId && !fGotEvent) { hvoEvent = hvoRec; hvoText = m_sda.get_ObjectProp(hvoEvent, (int)RnEvent.RnEventTags.kflidDescription); if (hvoText != 0) { int chvo; using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative(1000, typeof(int))) { // if there's a description with more than 1000 paragraphs this will break and // we'll fix it then. m_sda.VecProp(hvoText, (int)StText.StTextTags.kflidParagraphs, 1000, out chvo, arrayPtr); int[] rgHvo = (int[])MarshalEx.NativeToArray(arrayPtr, chvo, typeof(int)); // search for the paragraph that has non-empty label (there are a couple). for (int ihvoPara = 0; ihvoPara < chvo; ++ihvoPara) { hvoPara = rgHvo[ihvoPara]; // BigString ITsString tssPara = m_sda.get_StringProp(hvoPara, (int)StTxtPara.StTxtParaTags.kflidContents); if (tssPara.Length > 0) { string sname = m_sda.get_UnicodeProp(hvoPara, (int)StPara.StParaTags.kflidStyleName); if (sname != null && sname.Length > 0) { fGotEvent = true; } // Todo: it would be nice to test UnicodePropRgch, but we can't test // on the same prop because it's already loaded. Also, the modification // for data loading is shared code. We could make another cache instance // to test from, maybe? Or keep searching till we find another instance? // Could also look for a kcptBigUnicode, but implementation is identical. } } } } } } Assert.IsTrue(fGotEmpty && fGotNonEmpty, "found both empty and non-empty researcher lists"); Assert.IsTrue(hvoEvent != 0, "got at least one event"); // todo: test sequence (somehow verify order). // todo: test ref seq/collection (verify it does NOT set the owner to the referring obj). // Ref atomic Assert.IsFalse(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidConfidence, (int)CellarModuleDefns.kcptReferenceAtom, 0), "R3 confidence not preloaded"); int hvoConfidence = m_sda.get_ObjectProp(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidConfidence); Assert.IsTrue(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidConfidence, (int)CellarModuleDefns.kcptReferenceAtom, 0), "R3 confidence autoloaded"); if (hvoConfidence != 0) { int clsidConfidence = m_sda.get_IntProp(hvoConfidence, (int)CmObjectFields.kflidCmObject_Class); Assert.AreEqual(CmPossibility.kClassId, clsidConfidence, "class of confidence"); } // TsString. Assert.IsFalse(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidTitle, (int)CellarModuleDefns.kcptString, 0), "title of rec 3 not preloaded"); ITsString qtssRec3Title = m_sda.get_StringProp(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidTitle); Assert.IsTrue(m_sda.get_IsPropInCache(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidTitle, (int)CellarModuleDefns.kcptString, 0), "autoloaded title of rec 3"); // Int (e.g., gendate) Assert.IsFalse(m_sda.get_IsPropInCache(hvoEvent, (int)RnEvent.RnEventTags.kflidDateOfEvent, (int)CellarModuleDefns.kcptInteger, 0), "date of event not preloaded"); int nDateEvent = m_sda.get_IntProp(hvoEvent, (int)RnEvent.RnEventTags.kflidDateOfEvent); Assert.IsTrue(m_sda.get_IsPropInCache(hvoEvent, (int)RnEvent.RnEventTags.kflidDateOfEvent, (int)CellarModuleDefns.kcptInteger, 0), "autoloaded date of event"); // Todo: find example of int64 prop and test. // Test loading of binary data (into a TsTextProps). object obj = m_sda.get_UnknownProp(hvoPara, (int)StPara.StParaTags.kflidStyleRules); Assert.IsNotNull(obj as ITsTextProps); // Also loading of raw binary data, using the same prop. using (ArrayPtr rgbData = MarshalEx.ArrayToNative(10000, typeof(byte))) { int cb = -1; m_sda.BinaryPropRgb(hvoPara, (int)StPara.StParaTags.kflidStyleRules, rgbData, 10000, out cb); Assert.IsTrue(cb > 0, "got some bytes using BinaryPropRgb"); // Enhance JohnT: wish I could figure what they ought to be and test... // Get a UserView object (they have no owner, so go direct) SqlConnection con = new SqlConnection(string.Format("Server={0}; Database={1}; User ID = fwdeveloper;" + "Password=careful; Pooling=false;", m_fdoCache.ServerName, m_fdoCache.DatabaseName)); con.Open(); SqlCommand cmd = con.CreateCommand(); cmd.CommandText = "select top 2 id from UserView"; SqlDataReader reader = cmd.ExecuteReader(); reader.Read(); int hvoUv = reader.GetInt32(0); reader.Close(); con.Close(); // Guid prop Guid guidUv = m_sda.get_GuidProp(hvoUv, (int)UserView.UserViewTags.kflidApp); Assert.IsFalse(guidUv == Guid.Empty, "got non-empty guid"); // Time prop long lEventTime = m_sda.get_TimeProp(hvoEvent, (int)RnGenericRec.RnGenericRecTags.kflidDateCreated); Assert.IsFalse(lEventTime == 0, "got meaningful time"); // Enhance JohnT: really verify. // Int prop int viewSubtype = m_sda.get_IntProp(hvoUv, (int)UserView.UserViewTags.kflidSubType); // Enhance JohnT: think of a way to verify... // get_Prop: Time object objMod = m_sda.get_Prop(hvoRec3, (int)RnGenericRec.RnGenericRecTags.kflidDateModified); Assert.IsTrue(objMod is long); // get_Prop: String int hvoRec0 = m_sda.get_VecItem(hvoNotebook, (int)RnResearchNbk.RnResearchNbkTags.kflidRecords, 0); object objTitle = m_sda.get_Prop(hvoRec0, (int)RnGenericRec.RnGenericRecTags.kflidTitle); Assert.IsTrue(objTitle is ITsString, "get_Prop title is string"); // get_Prop: Int object objType = m_sda.get_Prop(hvoUv, (int)UserView.UserViewTags.kflidType); Assert.IsTrue(objType is int, "get_Prop type is integer"); // Confirm some more results by loading through FDO ICmObject objRec3 = CmObject.CreateFromDBObject(m_fdoCache, hvoRec3); Assert.IsTrue(objRec3 is IRnGenericRec, "object of correct type"); IRnGenericRec grRec3 = (IRnGenericRec)objRec3; // I'd prefer to use full ITsString equality test, but not sure how to get // a regular ITsString from FDO obj. Assert.AreEqual(qtssRec3Title.Text, grRec3.Title.Text, "two ways to retrieve R3 title match"); // Can't try this yet because FDO GenDate not yet implemented. The data type might not // be right anyway. // CmObject objEvent = CmObject.CreateFromDBObject(m_fdoCache, hvoEvent); // Assert.IsTrue(objEvent is RnEvent, "type of event"); // RnEvent ev1 = (RnEvent) objEvent; // Assert.AreEqual(ev1.DateOfEvent, nDateEvent, "date of event matches"); } }
/// <summary> /// /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="chvoMax"></param> /// <param name="_chvo"></param> /// <param name="_rghvo"></param> public void VecProp(int hvo, int tag, int chvoMax, out int _chvo, ArrayPtr _rghvo) { m_sda.VecProp(hvo, tag, chvoMax, out _chvo, _rghvo); }
public void VecProp() { // test VecProp using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative <int>(10)) { int chvo = 99; m_ISilDataAccess.VecProp(1001, 2001, 10, out chvo, arrayPtr); Assert.AreEqual(0, chvo); chvo = m_ISilDataAccess.get_VecSize(1001, 2001); Assert.AreEqual(0, chvo); int[] rgHvo = new int[] { 33, 44, 55 }; m_IVwCacheDa.CacheVecProp(1001, 2001, rgHvo, rgHvo.Length); m_ISilDataAccess.VecProp(1001, 2001, 10, out chvo, arrayPtr); int[] rgHvoNew = MarshalEx.NativeToArray <int>(arrayPtr, chvo); Assert.AreEqual(rgHvo.Length, rgHvoNew.Length); for (int i = 0; i < rgHvoNew.Length; i++) { Assert.AreEqual(rgHvo[i], rgHvoNew[i]); } int[] rgHvo2 = new int[] { 66, 77, 88, 99 }; m_IVwCacheDa.CacheVecProp(1001, 2001, rgHvo2, rgHvo2.Length); m_ISilDataAccess.VecProp(1001, 2001, 10, out chvo, arrayPtr); rgHvoNew = MarshalEx.NativeToArray <int>(arrayPtr, chvo); Assert.AreEqual(rgHvo2.Length, rgHvoNew.Length); for (int i = 0; i < rgHvoNew.Length; i++) { Assert.AreEqual(rgHvo2[i], rgHvoNew[i]); } Exception ex = null; try { m_ISilDataAccess.VecProp(1001, 2001, 2, out chvo, arrayPtr); } catch (Exception e) { ex = e; } Assert.IsNotNull(ex); Assert.AreEqual(typeof(ArgumentException), ex.GetType()); // test VecItem int hvo = m_ISilDataAccess.get_VecItem(1001, 2001, 2); Assert.AreEqual(88, hvo); ex = null; try { hvo = m_ISilDataAccess.get_VecItem(1001, 2001, 10); } catch (Exception e) { ex = e; } Assert.IsNotNull(ex); Assert.AreEqual(typeof(ArgumentException), ex.GetType()); // test Vector size chvo = m_ISilDataAccess.get_VecSize(1001, 2001); Assert.AreEqual(rgHvo2.Length, chvo); } }
/// <summary> /// Export the lexicon entries filtered into the list given by flid with relation to /// the LexDb object. /// </summary> public void ExportLift(TextWriter w, string folderPath, ISilDataAccess sda, int flid) { var hvoObject = m_cache.LangProject.LexDbOA.Hvo; var chvo = sda.get_VecSize(hvoObject, flid); int[] contents; using (var arrayPtr = MarshalEx.ArrayToNative<int>(chvo)) { sda.VecProp(hvoObject, flid, chvo, out chvo, arrayPtr); contents = MarshalEx.NativeToArray<int>(arrayPtr, chvo); } var entries = FilterVirtualFlidVector(contents); ExportLift(w, folderPath, entries, entries.Count); }
/// <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. }
/// <summary> /// Get the items from a vector property. /// </summary> private static int[] GetVector(ISilDataAccess sda, int hvo, int tag) { var chvo = sda.get_VecSize(hvo, tag); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative<int>(chvo)) { sda.VecProp(hvo, tag, chvo, out chvo, arrayPtr); return MarshalEx.NativeToArray<int>(arrayPtr, chvo); } }
/// <summary> Get the full contents of the specified sequence in one go.</summary> /// <param name='hvo'> </param> /// <param name='tag'> </param> /// <param name='chvoMax'> </param> /// <param name='_chvo'> </param> /// <param name='_rghvo'> </param> public virtual void VecProp(int hvo, int tag, int chvoMax, out int _chvo, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ArrayPtrMarshaler), SizeParamIndex = 2)] ArrayPtr /*long[]*/ _rghvo) { m_baseSda.VecProp(hvo, tag, chvoMax, out _chvo, _rghvo); }