internal static ITsString ExtractNonLIFTResidue(TsStringAccessor tsa) { if (tsa.Length < 29) return tsa.UnderlyingTsString; ITsStrBldr tsb = tsa.UnderlyingTsString.GetBldr(); int idx = tsb.Text.IndexOf("<lift-residue"); if (idx >= 0) { int idxEnd = tsb.Text.IndexOf("</lift-residue>", idx + 14); if (idxEnd >= 0) tsb.Replace(idx, idxEnd + 15, null, null); } return tsb.GetString(); }
/// <summary> /// Scan ImportResidue for XML looking string inserted by LIFT import. If any is found, /// move it from ImportResidue to LiftResidue. /// </summary> /// <returns>string containing any LIFT import residue found in ImportResidue</returns> public static string ExtractLIFTResidue(FdoCache cache, int hvo, int flidImportResidue, int flidLiftResidue) { TsStringAccessor tsa = new TsStringAccessor(cache, hvo, flidImportResidue); if (tsa.UnderlyingTsString == null || tsa.Length < 13) return null; int idx = tsa.Text.IndexOf("<lift-residue"); if (idx >= 0) { string sLiftResidue = tsa.Text.Substring(idx); int idx2 = sLiftResidue.IndexOf("</lift-residue>"); if (idx2 >= 0) { idx2 += 15; if (sLiftResidue.Length > idx2) sLiftResidue = sLiftResidue.Substring(0, idx2); } if (flidLiftResidue != 0) { int cch = sLiftResidue.Length; ITsStrBldr tsb = tsa.UnderlyingTsString.GetBldr(); tsb.Replace(idx, idx + cch, null, null); tsa.UnderlyingTsString = tsb.GetString(); // remove from ImportResidue cache.SetUnicodeProperty(hvo, flidLiftResidue, sLiftResidue); } return sLiftResidue; } else { return null; } }
/// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="fConcatenateIfBoth">If true, and if source and dest both have values that are not /// equal, concatenate source on end of dest. Otherwise ignore source if dest has a value.</param> public void MergeString(TsStringAccessor source, bool fConcatenateIfBoth) { if (source == null) return; string text = null; if (UnderlyingTsString != null) text = UnderlyingTsString.Text; string sourceText = null; if (source.UnderlyingTsString != null) sourceText = source.UnderlyingTsString.Text; if ((text == null || text == string.Empty) && (sourceText != null && sourceText != string.Empty)) { UnderlyingTsString = source.UnderlyingTsString; } else if (!fConcatenateIfBoth) { return; } else if ((text != null && text != string.Empty) && sourceText != null && sourceText != string.Empty && !UnderlyingTsString.Equals(source.UnderlyingTsString)) { // concatenate ITsStrBldr tsb = UnderlyingTsString.GetBldr(); tsb.Replace(tsb.Length, tsb.Length, " ", null); tsb.ReplaceTsString(tsb.Length, tsb.Length, source.UnderlyingTsString); UnderlyingTsString = tsb.GetString(); } }
/// <summary> /// /// </summary> /// <param name="source"></param> public void MergeString(TsStringAccessor source) { MergeString(source, false); }
/// <summary> /// Calculate the WritingSystemHvo for a CmBaseAnnotation. /// </summary> /// <param name="cache"></param> /// <param name="hvoObject"></param> /// <param name="beginOffset"></param> /// <param name="flid"></param> /// <returns></returns> public static int GetAnnotationWritingSystem(FdoCache cache, int hvoObject, int beginOffset, int flid) { if (flid == (int)StTxtPara.StTxtParaTags.kflidContents) { TsStringAccessor tsa = new TsStringAccessor(cache, hvoObject, flid); ITsString tss = tsa.UnderlyingTsString; if (beginOffset >= 0 && beginOffset < tss.Length) { ITsTextProps ttp = tss.get_PropertiesAt(beginOffset); int nVar; int ws = ttp.GetIntPropValues((int)FwTextPropType.ktptWs, out nVar); if (ws > 0) return ws; } } return cache.DefaultVernWs; }
private object GetCustomFieldValue(CmObject target, string property) { try { string sClass = m_cache.MetaDataCacheAccessor.GetClassName((uint)target.ClassID); uint flid = m_cache.MetaDataCacheAccessor.GetFieldId(sClass, property, true); if (flid == 0) return null; int type = m_cache.MetaDataCacheAccessor.GetFieldType(flid); string sView; switch (type) { case (int)CellarModuleDefns.kcptString: case (int)CellarModuleDefns.kcptBigString: TsStringAccessor tsa = new TsStringAccessor(m_cache, target.Hvo, (int)flid); return tsa; case (int)CellarModuleDefns.kcptMultiUnicode: case (int)CellarModuleDefns.kcptMultiBigUnicode: sView = sClass + '_' + property; MultiUnicodeAccessor mua = new MultiUnicodeAccessor(m_cache, target.Hvo, (int)flid, sView); return mua; case (int)CellarModuleDefns.kcptMultiString: case (int)CellarModuleDefns.kcptMultiBigString: sView = sClass + '_' + property; MultiStringAccessor msa = new MultiStringAccessor(m_cache, target.Hvo, (int)flid, sView); return msa; } } catch { } return null; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Merges object into this object. /// if fLoseNoStringData is false: /// For atomic properties, if this object has something in the property, the source /// property is ignored. For sequence properties, the objects in the source will be /// moved and appended to the properties in this object. Any references to the /// source object will be transferred to this object. The source object is deleted /// at the end of this method (objSrc.DeleteUnderlyingObject() call). /// String properties are copied from the source if the destination (this) has no value /// and the source has a value. /// /// if fLoseNoStringData is true, the above is modified as follows: /// 1. If a string property has a value in both source and destination, and the values /// are different, append the source onto the destination. /// 2. If an atomic object property has a value in both source and destination, /// recursively merge the value in the source with the value in the destination. /// </summary> /// <param name="objSrc">Object whose properties will be merged into this object's properties</param> /// <remarks> /// NB: The given object will be deleted in this method, so don't expect it to be valid, afterwards. /// </remarks> /// <param name="fLoseNoStringData"></param> /// ------------------------------------------------------------------------------------ public virtual void MergeObject(ICmObject objSrc, bool fLoseNoStringData) { Debug.Assert(m_cache != null); // We don't allow merging items of different classes. Debug.Assert(ClassID == objSrc.ClassID); if (ClassID != objSrc.ClassID) return; IFwMetaDataCache mdc = m_cache.MetaDataCacheAccessor; PropertyInfo[] myProperties = GetType().GetProperties(); PropertyInfo[] srcProperties = objSrc.GetType().GetProperties(); string fieldname; // Process all the fields in the source. foreach(uint flid in DbOps.GetFieldsInClassOfType(mdc, ClassID, FieldType.kgrfcptAll)) { /* These values will also be returned because they are for most of CmObject's flids. * I think it will do this for each superclass, so there could be some repeats on them. * * pvuFields->Push(101); // kflidCmObject_Guid * pvuFields->Push(102); // kflidCmObject_Class * pvuFields->Push(103); // kflidCmObject_Owner * pvuFields->Push(104); // kflidCmObject_OwnFlid * pvuFields->Push(105); // kflidCmObject_OwnOrd * //pvuFields->Push(106); // kflidCmObject_UpdStmp * //pvuFields->Push(107); // kflidCmObject_UpdDttm * */ if (flid < 1000) continue; // Do nothing for the CmObject flids. if (flid >= (int)SpecialTagValues.ktagMinVp) continue; // Do nothing for virtual properties. int nType = mdc.GetFieldType(flid); fieldname = mdc.GetFieldName(flid); //|| fieldname == "DateModified" //|| nType == (int)FieldType.kcptTime // This is handled by a separate connection, so it can time out, if another transaction is open. if (fieldname == "DateCreated" || nType == (int)FieldType.kcptImage // FDO does not support this one. || nType == (int)FieldType.kcptGenDate) // FDO does not support setter for gendate. continue; // Don't mess with this one. // Set suffixes on some of the types. switch (nType) { case (int)FieldType.kcptOwningAtom: // 23 { fieldname += "OA"; break; } case (int)FieldType.kcptReferenceAtom: // 24 { fieldname += "RA"; break; } case (int)FieldType.kcptOwningCollection: // 25 { fieldname += "OC"; break; } case (int)FieldType.kcptReferenceCollection: // 26 { fieldname += "RC"; break; } case (int)FieldType.kcptOwningSequence: // 27 { fieldname += "OS"; break; } case (int)FieldType.kcptReferenceSequence: // 28 { fieldname += "RS"; break; } } Object myCurrentValue = null; MethodInfo mySetMethod = null; Object srcCurrentValue = null; PropertyInfo pi = this.GetType().GetProperty(fieldname); if (pi != null) { myCurrentValue = pi.GetGetMethod().Invoke(this, null); mySetMethod = pi.GetSetMethod(); srcCurrentValue = objSrc.GetType().GetProperty(fieldname).GetGetMethod().Invoke(objSrc, null); } else { // We must have a custom field, and it needs special treatment. Debug.Assert(m_cache.GetIsCustomField(flid)); mySetMethod = null; string classname = mdc.GetOwnClsName(flid); string sView = classname + "_" + fieldname; switch (nType) { case (int)FieldType.kcptString: case (int)FieldType.kcptBigString: myCurrentValue = new TsStringAccessor(m_cache, m_hvo, (int)flid); srcCurrentValue = new TsStringAccessor(objSrc.Cache, objSrc.Hvo, (int)flid); break; case (int)FieldType.kcptMultiString: case (int)FieldType.kcptMultiBigString: myCurrentValue = new MultiStringAccessor(m_cache, m_hvo, (int)flid, sView); srcCurrentValue = new MultiStringAccessor(objSrc.Cache, objSrc.Hvo, (int)flid, sView); break; case (int)FieldType.kcptMultiUnicode: case (int)FieldType.kcptMultiBigUnicode: myCurrentValue = new MultiUnicodeAccessor(m_cache, m_hvo, (int)flid, sView); srcCurrentValue = new MultiUnicodeAccessor(objSrc.Cache, objSrc.Hvo, (int)flid, sView); break; } } if (srcCurrentValue == null) continue; // Nothing to merge. Debug.Assert(srcCurrentValue != null); /* * NOTE: Each of the cases (except the exception, which can't be tested) * is tested in the MergeObjectsTests class in the unit tests. * If any additions are made, or if some currently unused cases are enabled, * be sure to add them (or enable them) to that class, as well. */ switch (nType) { default: throw new ApplicationException("Unrecognized data type for merging: " + nType.ToString()); /* 0 -> 9 */ case (int)FieldType.kcptBoolean: // 1 { // Can't be null, so we have to live with default of 0 (false). // 0 gets replaced with source data, if 1 (true). bool myBool = (bool)myCurrentValue; bool srcBool = (bool)srcCurrentValue; if (!myBool && srcBool) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcCurrentValue}); } break; } // case (int)FieldType.kcptInteger: // 2 Fall through // Setter not implemented in FDO. case (int)FieldType.kcptGenDate: // 8 { // Can't be null, so we have to live with default of 0. // Zero gets replaced with source data, if greater than 0. int myInt = (int)myCurrentValue; int srcInt = (int)srcCurrentValue; if (myInt == 0 && srcInt > 0) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcCurrentValue}); } break; } case (int)FieldType.kcptTime: // 5 { // If it is DateCreated, we won't even be here, // since we will have already skipped it. bool resetTime = false; DateTime srcTime = DateTime.Now; // If it is DateModified, always set it to 'now'. if (fieldname == "DateModified") { // Already using 'Now'. resetTime = true; } else { // Otherwise, a later source will replace an older target. DateTime myTime = (DateTime)myCurrentValue; srcTime = (DateTime)srcCurrentValue; resetTime = (myTime < srcTime); if (myTime < srcTime) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcTime}); } } if (resetTime) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcTime}); } break; } case (int)FieldType.kcptGuid: // 6 { // May be null. Guid myGuidValue = (Guid)myCurrentValue; Guid srcGuidValue = (Guid)srcCurrentValue; if (myGuidValue == Guid.Empty && srcGuidValue != Guid.Empty) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcGuidValue}); mySetMethod.Invoke(objSrc, new object[] {Guid.Empty}); } break; } //case (int)FieldType.kcptImage: // 7 Fall through. case (int)FieldType.kcptBinary: // 8 { if (myCurrentValue == null) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcCurrentValue}); } break; } /* 13 -> 20 */ case (int)FieldType.kcptString: // 13 Fall through case (int)FieldType.kcptBigString: // 17 { if (MergeStringProp((int)flid, nType, objSrc, fLoseNoStringData, myCurrentValue, srcCurrentValue)) break; TsStringAccessor myTsa = myCurrentValue as TsStringAccessor; myTsa.MergeString(srcCurrentValue as TsStringAccessor, fLoseNoStringData); break; } case (int)FieldType.kcptMultiString: // 14 Fall through. case (int)FieldType.kcptMultiBigString: // 18 { if (MergeStringProp((int)flid, nType, objSrc, fLoseNoStringData, myCurrentValue, srcCurrentValue)) break; MultiStringAccessor myMsa = myCurrentValue as MultiStringAccessor; myMsa.MergeAlternatives(srcCurrentValue as MultiStringAccessor, fLoseNoStringData); break; } case (int)FieldType.kcptUnicode: // 15 Fall through. case (int)FieldType.kcptBigUnicode: // 19 { if (MergeStringProp((int)flid, nType, objSrc, fLoseNoStringData, myCurrentValue, srcCurrentValue)) break; string myUCurrent = myCurrentValue as string; string srcUValue = srcCurrentValue as string; if ((myUCurrent == null || myUCurrent == String.Empty) && srcUValue != String.Empty) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcUValue}); } else if (fLoseNoStringData && myUCurrent != null && myUCurrent != String.Empty && srcUValue != null && srcUValue != String.Empty && srcUValue != myUCurrent) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {myUCurrent + ' ' + srcUValue}); } break; } case (int)FieldType.kcptMultiUnicode: // 16 Fall through case (int)FieldType.kcptMultiBigUnicode: // 20 This one isn't actually used yet, but I hope it is the same as the small MultiUnicode { if (MergeStringProp((int)flid, nType, objSrc, fLoseNoStringData, myCurrentValue, srcCurrentValue)) break; MultiUnicodeAccessor myMua = myCurrentValue as MultiUnicodeAccessor; myMua.MergeAlternatives(srcCurrentValue as MultiUnicodeAccessor, fLoseNoStringData); break; } /* 23 -> 28 */ case (int)FieldType.kcptOwningAtom: case (int)FieldType.kcptReferenceAtom: // 24 { ICmObject srcObj = srcCurrentValue as ICmObject; ICmObject currentObj = myCurrentValue as ICmObject; if (myCurrentValue == null) { Debug.Assert(mySetMethod != null); mySetMethod.Invoke(this, new object[] {srcObj}); break; } else if (fLoseNoStringData && nType == (int)FieldType.kcptOwningAtom && srcObj != null && currentObj.GetType() == srcObj.GetType()) { // merge the child objects. currentObj.MergeObject(srcObj, true); } break; } case (int)FieldType.kcptOwningCollection: // 25 Fall through, since the collection class knows how to merge itself properly. case (int)FieldType.kcptReferenceCollection: // 26 { PropertyInfo piCol = FdoVector<ICmObject>.HvoArrayPropertyInfo(srcCurrentValue); MethodInfo myAddMethod = FdoCollection<ICmObject>.AddIntMethodInfo(myCurrentValue); foreach (int hvo in (int[])piCol.GetGetMethod().Invoke(srcCurrentValue, null)) { myAddMethod.Invoke(myCurrentValue, new object[] { hvo }); } break; } case (int)FieldType.kcptOwningSequence: // 27 Fall through, since the collection class knows how to merge itself properly. case (int)FieldType.kcptReferenceSequence: // 28 { PropertyInfo piCol = FdoVector<ICmObject>.HvoArrayPropertyInfo(srcCurrentValue); MethodInfo myAppendMethod = FdoSequence<ICmObject>.AppendIntMethodInfo(myCurrentValue); foreach (int hvo in (int[])piCol.GetGetMethod().Invoke(srcCurrentValue, null)) { myAppendMethod.Invoke(myCurrentValue, new object[] { hvo }); } break; } } } // Now move all incoming references. CmObject.ReplaceReferences(m_cache, objSrc, this); objSrc.DeleteUnderlyingObject(); }