/// <summary> /// Overwrite all alternatives. /// </summary> /// <param name="source"></param> public void CopyAlternatives(MultiStringAccessor source) { if (source == null) return; // Nothing to do. foreach (LgWritingSystem lws in m_cache.LanguageEncodings) { int ws = lws.Hvo; ITsString srcAlt = source.GetAlternativeTss(ws); if ((srcAlt != null && srcAlt.Length != 0)) { SetAlternative(srcAlt, ws); } } }
private void MergeVernacularString (MultiStringAccessor fwString, string wsString) { if (wsString.Length > 0) fwString.VernacularDefaultWritingSystem.Text = wsString; }
/// <summary> /// Default inserts space. /// </summary> public void MergeAlternatives(MultiStringAccessor source, bool fConcatenateIfBoth) { MergeAlternatives(source, fConcatenateIfBoth, " "); }
/// <summary> /// Merge two MultiStringAccessor objects. /// These cases are handled: /// 1. If the main object (this) is missing an alternative, and the 'source' has it, then add it to 'this'. /// 2. If the main object has an alternative, and the source has none, then do nothing. /// 3. If both alternatives are non-empty, then /// 3.1 if fConcatenateIfBoth is false, keep the current value (do nothing) /// 3.2 if fConcatenateIfBoth is true, and the values are equal, keep the current value (do nothing); /// 3.3 if fConcatenateIfBoth is true, and the values are not equal, append the source to the current value. /// </summary> /// <param name="source"></param> /// <param name="fConcatenateIfBoth"></param> /// <param name="sep">insert between alterantives when merging.</param> public void MergeAlternatives(MultiStringAccessor source, bool fConcatenateIfBoth, string sep) { if (source == null) return; // Nothing to do. foreach (LgWritingSystem lws in m_cache.LanguageEncodings) { int ws = lws.Hvo; string myAlt = GetAlternative(ws).Text; string srcAlt = source.GetAlternative(ws).Text; if ((myAlt == null || myAlt == String.Empty) && (srcAlt != null && srcAlt != String.Empty)) { SetAlternative(source.GetAlternative(ws).UnderlyingTsString, ws); } else if (!fConcatenateIfBoth) { continue; } else if (myAlt != null && myAlt != String.Empty && srcAlt != null && srcAlt != String.Empty && !GetAlternative(ws).UnderlyingTsString.Equals(source.GetAlternative(ws).UnderlyingTsString)) { // concatenate ITsStrBldr tsb = GetAlternative(ws).UnderlyingTsString.GetBldr(); tsb.Replace(tsb.Length, tsb.Length, sep, null); tsb.ReplaceTsString(tsb.Length, tsb.Length, source.GetAlternative(ws).UnderlyingTsString); SetAlternative(tsb.GetString(), ws); } } }
/// <summary> /// Merge two MultiStringAccessor objects. /// These cases are handled: /// 1. If an alternative exists in both objects, nothing is merged. /// 2. If the main object (this) is missing an alternative, and the 'source' has it, then add it to 'this'. /// 3. If the main object has an alternative, then do nothing. /// </summary> /// <param name="source"></param> public void MergeAlternatives(MultiStringAccessor source) { MergeAlternatives(source, false); }
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(); }
private bool TryMultiStringAlt(ISilDataAccess sda, int hvo, int flid, out int wsActual) { MultiStringAccessor accessor = new MultiStringAccessor(m_cache, hvo, flid, ""); return accessor.TryWs(m_ws, out wsActual); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Export the back translation of a picture caption /// </summary> /// <param name="caption">caption to export</param> /// ------------------------------------------------------------------------------------ private void ExportPictureBT(MultiStringAccessor caption) { string pictureMarker = GetMarkerForStyle(ScrStyleNames.Figure, @"\figcap"); string marker = kBackTransMarkerPrefix + pictureMarker.Substring(1); for (int i = 0; i < m_requestedAnalWS.Length; i++) { int ws = m_requestedAnalWS[i]; string captionText = caption.GetAlternative(ws).Text; if (captionText != null && captionText != string.Empty) { // make sure the pic starts on a new line m_file.WriteLine(); m_file.WriteLine(marker + GetIcuSuffix(i) + " " + captionText); } } }