/// ------------------------------------------------------------------------------------ /// <summary> /// Return an FdoCollection representing all the records that need to be filtered. /// </summary> /// <param name="hvoPropOwner">ID of the object that owns the collection to be filtered /// </param> /// <returns>collection of all items (records) to be filtered</returns> /// ------------------------------------------------------------------------------------ private FdoVector <ICmObject> GetCollectionOfRecordsToFilter(int hvoPropOwner) { int flid = m_flidProvider.GetFlidForPropOwner(hvoPropOwner); if (!m_changeWatchers.ContainsKey(flid)) { m_changeWatchers.Add(flid, new VirtualPropChangeWatcher(flid, this)); } // Return a collection of all items in the vector field switch (m_cache.GetFieldType(flid)) { case FieldType.kcptReferenceCollection: return(new FdoReferenceCollection <ICmObject>(m_cache, hvoPropOwner, flid)); case FieldType.kcptReferenceSequence: return(new FdoReferenceSequence <ICmObject>(m_cache, hvoPropOwner, flid)); case FieldType.kcptOwningSequence: return(new FdoOwningSequence <ICmObject>(m_cache, hvoPropOwner, flid)); default: case FieldType.kcptOwningCollection: return(new FdoOwningCollection <ICmObject>(m_cache, hvoPropOwner, flid)); } }
/// <summary> /// Creates the appropriate string accessor to the given flid. /// </summary> /// <param name="cache"></param> /// <param name="hvoOwner"></param> /// <param name="flidOwning"></param> /// <param name="sView">Class_Field to load from database (obsolete?)</param> /// <returns></returns> static public MultiAccessor CreateMultiAccessor(FdoCache cache, int hvoOwner, int flidOwning, string sView) { FieldType flidType = cache.GetFieldType(flidOwning); switch (flidType) { case FieldType.kcptMultiUnicode: case FieldType.kcptMultiBigUnicode: return new MultiUnicodeAccessor(cache, hvoOwner, flidOwning, sView); case FieldType.kcptMultiString: case FieldType.kcptMultiBigString: return new MultiStringAccessor(cache, hvoOwner, flidOwning, sView); default: return null; } }
/// <summary> /// This is the ReferenceUi factory. /// We currently exclude ReferenceSequenceUi (see that class for reason). /// </summary> /// <param name="cache"></param> /// <param name="rootObj"></param> /// <param name="referenceFlid"></param> /// <param name="targetHvo"></param> /// <returns></returns> static public ReferenceBaseUi MakeUi(FdoCache cache, ICmObject rootObj, int referenceFlid, int targetHvo) { FieldType iType = cache.GetFieldType(referenceFlid); if (iType == FieldType.kcptReferenceSequence || iType == FieldType.kcptReferenceCollection) return new VectorReferenceUi(cache, rootObj, referenceFlid, targetHvo); else if (iType == FieldType.kcptReferenceAtom) return new ReferenceBaseUi(cache, rootObj, referenceFlid, targetHvo); return null; }
public VectorReferenceUi(FdoCache cache, ICmObject rootObj, int referenceFlid, int targetHvo) : base(cache, rootObj, referenceFlid, targetHvo) { m_iType = cache.GetFieldType(m_flid); Debug.Assert(m_iType == FieldType.kcptReferenceSequence || m_iType == FieldType.kcptReferenceCollection); }
/// <summary> /// Returns an array of string values (keys) for the objects under this layout node. /// </summary> /// <param name="fdoCache"></param> /// <param name="layout"></param> /// <param name="hvo"></param> /// <param name="layoutCache"></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"></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, 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, fdoCache); // modify the hvo if needed if (hvo != hvoTarget) { return AddStringFromOtherObj(layout, hvoTarget, fdoCache); } int flid = GetFlid(fdoCache, layout, hvo); if (wsForce != 0) { // If we are forcing a writing system, and it's a multistring, get the forced alternative. int itype = fdoCache.MetaDataCacheAccessor.GetFieldType((uint)flid); itype = itype & 0x1f; // strip virtual bit switch (itype) { case (int) FieldType.kcptMultiUnicode: case (int) FieldType.kcptMultiString: case (int) FieldType.kcptMultiBigUnicode: case (int) FieldType.kcptMultiBigString: return new string[] {fdoCache.MainCacheAccessor.get_MultiStringAlt(hvo, flid, wsForce).Text}; } } bool fFoundType; string strValue = fdoCache.GetText(hvo, flid, layout, out fFoundType); if (fFoundType) { return new string[] {strValue}; } else { throw new Exception("Bad property type (" + strValue + " for hvo " + hvo + " found for string property " + flid + " in " + layout.OuterXml); } } case "configureMlString": { int flid = GetFlid(fdoCache, layout, hvo); // The Ws info specified in the part ref node Set<int> wsIds = LangProject.GetAllWritingSystems(caller, fdoCache, null, hvo, flid); if (wsIds.Count == 1) { string strValue = fdoCache.MainCacheAccessor.get_MultiStringAlt(hvo, flid, wsIds.ToArray()[0]).Text; return new string[] {strValue}; } else return new string[] {AddMultipleAlternatives(fdoCache, wsIds, hvo, flid, caller)}; } case "multiling": return ProcessMultiLingualChildren(fdoCache, 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, 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, layout, hvo, layoutCache, caller, stringTbl, wsForce); else return AssembleChildKeys(fdoCache, layout, hvo, layoutCache, caller, stringTbl, wsForce); case "part": { string partref = XmlUtils.GetOptionalAttributeValue(layout, "ref"); if (partref == null) return ChildKeys(fdoCache, layout, hvo, layoutCache, caller, stringTbl, wsForce); // an actual part, made up of its pieces XmlNode part = XmlVc.GetNodeForPart(hvo, partref, false, fdoCache.MainCacheAccessor, 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, part, hvo, layoutCache, layout, stringTbl, wsForce); } case "div": case "innerpile": { // Concatenate keys for child nodes (as distinct strings) return ChildKeys(fdoCache, 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(fdoCache, layout, hvo); int hvoTarget = fdoCache.MainCacheAccessor.get_ObjectProp(hvo, flid); if (hvoTarget == 0) break; // return empty key string targetLayoutName = XmlUtils.GetOptionalAttributeValue(layout, "layout"); // uses 'default' if missing. XmlNode layoutTarget = GetLayoutNodeForChild(fdoCache, hvoTarget, flid, targetLayoutName, layout, layoutCache); if (layoutTarget == null) break; return ChildKeys(fdoCache, 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(fdoCache, layout, hvo); int ctarget = fdoCache.MainCacheAccessor.get_VecSize(hvo, flid); string[] result = null; string targetLayoutName = XmlVc.GetLayoutName(layout, caller); // also allows for finding "param" attr in caller, if not null //string targetLayoutName = XmlUtils.GetOptionalAttributeValue(layout, "layout"); for(int i = 0; i < ctarget; i++) { int hvoTarget = fdoCache.MainCacheAccessor.get_VecItem(hvo, flid, i); int prevResultLength = GetArrayLength(result); XmlNode layoutTarget = GetLayoutNodeForChild(fdoCache, hvoTarget, flid, targetLayoutName, layout, layoutCache); if (layoutTarget == null) continue; // should not happen, but best recovery we can make result = Concatenate(result, ChildKeys(fdoCache, 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); } } return result; } case "choice": { foreach(XmlNode whereNode in layout.ChildNodes) { if (whereNode.Name != "where") { if (whereNode.Name == "otherwise") return StringsFor(fdoCache, 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, caller)) return StringsFor(fdoCache, 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, caller)) return StringsFor(fdoCache, XmlUtils.GetFirstNonCommentChild(layout), hvo, layoutCache, caller, stringTbl, wsForce); break; } case "ifnot": { if (!XmlVc.ConditionPasses(layout, hvo, fdoCache, caller)) return StringsFor(fdoCache, 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 string[] { literal }; } case "int": { int flid = GetFlid(fdoCache, layout, hvo); int val = fdoCache.MainCacheAccessor.get_IntProp(hvo, flid); return new string[] {XmlViewsUtils.AlphaCompNumberString(val)}; } case "datetime": { int flid = GetFlid(fdoCache, layout, hvo); FieldType itype = fdoCache.GetFieldType(flid); if (itype == FieldType.kcptTime) { DateTime dt = fdoCache.GetTimeProperty(hvo, flid); return new string[] {XmlViewsUtils.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 string[] {"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. }
internal static string[] AddStringFromOtherObj(XmlNode frag, int hvoTarget, FdoCache cache) { int flid = XmlVc.GetFlid(frag, hvoTarget, cache); ITsStrFactory tsf = TsStrFactoryClass.Create(); FieldType itype = cache.GetFieldType(flid); if ((itype == FieldType.kcptUnicode) || (itype == FieldType.kcptBigUnicode)) { return new string[] {cache.GetUnicodeProperty(hvoTarget, flid)}; } else if ((itype == FieldType.kcptString) || (itype == FieldType.kcptBigString)) { return new string[] { cache.GetTsStringProperty(hvoTarget, flid).Text }; } else // multistring of some type { int wsid = 0; string sep = ""; if (s_cwsMulti > 1) { string sLabelWs = XmlUtils.GetOptionalAttributeValue(frag, "ws"); if (sLabelWs != null && sLabelWs == "current") { sep = DisplayMultiSep(frag, cache) + DisplayWsLabel(s_qwsCurrent, cache); wsid = s_qwsCurrent.WritingSystem; } } if (wsid == 0) wsid = LangProject.GetWritingSystem(frag, cache, null, LangProject.kwsAnal); if ((itype == FieldType.kcptMultiUnicode) || (itype == FieldType.kcptMultiBigUnicode)) { return new string[] {sep, cache.GetMultiUnicodeAlt(hvoTarget, flid, wsid, null) }; } else { return new string[] {sep, cache.GetMultiStringAlt(hvoTarget, flid, wsid).Text }; } } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Cycle through the applications main windows and synchronize them with database /// changes. /// </summary> /// <param name="sync">synchronization information record</param> /// <param name="cache">database cache</param> /// <returns>false if a refreshall was performed or presync failed; this suppresses /// subsequent sync messages. True to continue processing.</returns> /// ------------------------------------------------------------------------------------ public virtual bool Synchronize(SyncInfo sync, FdoCache cache) { CheckDisposed(); if (m_suppressedCaches.ContainsKey(cache)) { Queue<SyncInfo> messages = m_suppressedCaches[cache].Queue; if (!messages.Contains(sync)) messages.Enqueue(sync); return true; } cache.StoreSync(SyncGuid, sync); if (sync.msg == SyncMsg.ksyncFullRefresh || sync.msg == SyncMsg.ksyncCustomField) { RefreshAllViews(cache); return false; } foreach (IFwMainWnd wnd in MainWindows) { if (wnd.Cache == cache && !wnd.PreSynchronize(sync)) return false; } if (sync.msg == SyncMsg.ksyncWs) { // REVIEW TeTeam: AfLpInfo::Synchronize calls AfLpInfo::FullRefresh, which // clears the cache, loads the styles, loads ws and updates wsf, load project // basics, updates external link root, load overlays and refreshes possibility // lists. I don't think we need to do any of these here. RefreshAllViews(cache); return false; } else if (sync.msg == SyncMsg.ksyncPromoteEntry) { // Review: Write code here to deal with this case. Look at // AfLpInfo::Syncronize to see what's necessary. // This would be relevant to an application that uses subentries (like Data Notebook-- // if it used FwApp). } else if (sync.msg == SyncMsg.ksyncSimpleEdit) { // Use the UpdatePropIfCached method to update anything that changed that we care about. // Todo: need to get Synchronize called for each new syncinfo in DB on window activate. IVwOleDbDa odd = cache.VwOleDbDaAccessor; int hvo = sync.hvo; int flid = sync.flid; FieldType iType = cache.GetFieldType(flid); switch(iType) { case FieldType.kcptMultiString: case FieldType.kcptMultiUnicode: case FieldType.kcptMultiBigString: case FieldType.kcptMultiBigUnicode: // Try all active WS to see if cached. (Pathologically, if some wss are used for both, // they will be updated twice.) foreach (int ws in cache.LangProject.VernWssRC.HvoArray) odd.UpdatePropIfCached(hvo, flid, (int)iType, ws); foreach (int ws in cache.LangProject.AnalysisWssRC.HvoArray) odd.UpdatePropIfCached(hvo, flid, (int)iType, ws); // This will usually prevent a double-update; pathologically, one might still happen // if the user ws is in the analysis or vernacular lists but is not the first analysis one. if (cache.DefaultUserWs != cache.DefaultAnalWs) odd.UpdatePropIfCached(hvo, flid, (int)iType, cache.DefaultUserWs); break; case 0: // This is very rare but possible. Do nothing since kcptNull is not a real data // type, hence cannot have any data. break; default: odd.UpdatePropIfCached(hvo, flid, (int)iType, 0); break; } return true; } foreach (IFwMainWnd wnd in MainWindows) { if (wnd.Cache == cache && !wnd.Synchronize(sync)) { // The window itself was not able to process the message successfully; // play safe and refresh everything RefreshAllViews(cache); return false; } } return true; }