示例#1
0
        /// <summary>
        /// The main entry point to do the work of the original method.
        /// </summary>
        internal void Display(ref ITsString tssDelayedNumber)
        {
            MainCallerDisplayCommand dispInfo;

            if (!m_viewConstructor.CanGetMainCallerDisplayCommand(m_frag, out dispInfo))
            {
                // Shouldn't be possible, but just in case...
                Debug.Assert(true, "No MainCallerDisplayCommand!");
                return;
            }

            XmlNode listDelimitNode;             // has the list seps attrs like 'sep'
            XmlNode specialAttrsNode;            // has the more exotic ones like 'excludeHvo'

            listDelimitNode = specialAttrsNode = dispInfo.MainNode;
            // 'inheritSeps' attr means to use the 'caller' (the part ref node)
            // to get the separator information.
            if (XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "inheritSeps", false))
            {
                listDelimitNode = dispInfo.Caller;
            }

            //
            // 1. get number of items in vector
            //
            var chvo = m_sda.get_VecSize(m_hvo, m_flid);

            if (chvo == 0)
            {
                // We may want to do something special for empty vectors.  See LT-9687.
                ProcessEmptyVector(m_vwEnv, m_hvo, m_flid);
                return;
            }
            //
            // 2. for each item in the vector,
            //		a) print leading number if desired.
            //		b) call AddObj
            //		c) print separator if desired and needed
            //
            int[] rghvo = GetVector(m_sda, m_hvo, m_flid);
            Debug.Assert(chvo == rghvo.Length);
            //
            // Define some special boolean flags.
            //
            // Note that we deliberately don't use the listDelimitNode here.
            // These three props are not currently configurable, and they belong on the 'seq' element,
            // not the part ref.
            var fCheckForEmptyItems = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode,
                                                                                "checkForEmptyItems", false);
            string exclude    = XmlUtils.GetOptionalAttributeValue(specialAttrsNode, "excludeHvo", null);
            var    fFirstOnly = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode, "firstOnly", false);

            XmlAttribute xaNum;
            var          fNumber = SetNumberFlagIncludingSingleOption(listDelimitNode, chvo, out xaNum);

            ApplySortingIfSpecified(rghvo, specialAttrsNode);

            // Determine if sequence should be filtered by a stored list of Guids.
            // Note that if we filter, we replace rghvo with the filtered list.
            if (m_viewConstructor.ShouldFilterByGuid)
            {              // order by vector item type guids
                // Don't reorder LexEntry VisibleComplexFormBackRefs vector if the user overrode it manually.
                var obj = m_cache.ServiceLocator.GetObject(m_hvo);
                if (obj is ILexEntry)
                {
                    var lexEntry = obj as ILexEntry;
                    if (m_flid == m_cache.MetaDataCacheAccessor.GetFieldId("LexEntry", "VisibleComplexFormBackRefs", false))
                    {
                        if (!VirtualOrderingServices.HasVirtualOrdering(lexEntry, "VisibleComplexFormBackRefs"))
                        {
                            chvo = ApplyFilterToSequence(ref rghvo);
                        }
                    }
                    else
                    {
                        chvo = ApplyFilterToSequence(ref rghvo);
                    }
                }
                else
                {
                    chvo = ApplyFilterToSequence(ref rghvo);
                }
            }

            // Check whether the user wants the grammatical information to appear only once, preceding any
            // sense numbers, if there is only one set of grammatical information, and all senses refer to
            // it.  See LT-9663.
            var childFrag            = m_frag;
            var fSingleGramInfoFirst = false;

            if (m_flid == LexEntryTags.kflidSenses)
            {
                fSingleGramInfoFirst = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "singlegraminfofirst", false);
            }

            // This groups senses by placing graminfo before the number, and omitting it if the same as the
            // previous sense in the entry.  This isn't yet supported by the UI, but may well be requested in
            // the future.  (See LT-9663.)
            //bool fGramInfoBeforeNumber = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "graminfobeforenumber", false);

            // Setup text properties for any numbering
            int          wsEng        = m_cache.WritingSystemFactory.GetWsFromStr(strEng);
            ITsTextProps ttpNum       = null;
            var          fDelayNumber = false;

            if (fNumber)
            {
                ttpNum       = SetNumberTextProperties(wsEng, listDelimitNode);
                fDelayNumber = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode, "numdelay", false);
            }

            // A vector may be conditionally configured to display its objects as separate paragraphs
            // in dictionary (document) configuration.  See LT-9667.
            var fShowAsParagraphsInInnerPile = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode,
                                                                                         "showasindentedpara", false);
            // We have (this is probably bad) two ways to do this. The better one is setting the flowType to divInPara.
            // When we do this for a vector, and configure properties that require us to insert numbering and so forth,
            // we currently force a paragraph for each item. It's too hard otherwise to get the numbers etc. into the paragraph.
            // This means that the X_AsPara layout which the configure dialog causes to be invoked when setting up sense-as-para
            // has to be configured NOT to make a paragraph. It also means we can't readily configure a view that has more than one
            // paragraph, except when doing another layer of inserting paragraphs into what is usually a single one. I don't like
            // this much but it does what we need for now and making it better looks very messy.
            var       fShowAsParagraphsInDivInPara = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "flowType", null) == "divInPara";
            ITsString tssBefore  = null;
            string    sParaStyle = null;

            if (fShowAsParagraphsInInnerPile && chvo > 0)
            {
                sParaStyle = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "style");
                tssBefore  = SetBeforeString(specialAttrsNode, listDelimitNode);
                // We need a line break here to force the inner pile of paragraphs to begin at
                // the margin, rather than somewhere in the middle of the line.
                m_vwEnv.AddString(TsStringUtils.MakeString(StringUtils.kChHardLB.ToString(),
                                                           m_cache.ServiceLocator.WritingSystems.DefaultAnalysisWritingSystem.Handle));
                m_vwEnv.OpenInnerPile();
            }
            else if (fShowAsParagraphsInDivInPara)
            {
                sParaStyle = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "parastyle", "");
            }

            // Setup and run actual internal vector loop
            var xattrSeparator = listDelimitNode.Attributes["sep"];
            var fFirst         = true;     // May actually mean first non-empty.
            WrapParagraphDisplayCommand tempCommand = null;
            int tempId = 0;

            if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
            {
                // We make a temporary command object, whose purpose is to wrap the paragraphs we want to create
                // here for each item and any embellishments we add INSIDE the display of each individual item.
                // This ensures that if we break those paragraphs (e.g., for subentries of a sense), all the
                // paragraphs for the outer object are still correctly nested inside the item.
                // This is especially important for XML export, where if the paragraph and object elements are
                // not correctly nested, we don't even have valid XML.
                // The command object's lifetime is only as long as this XmlVcDisplayVec,
                // because it references this XmlVcDisplayVec object and even updates some of its member variables.
                // I'm not sure it really has to do that, but I was trying to make a minimal change to the code
                // that had to be wrapped in the command object so it could be invoked by the AddObj call.
                // It is possible we could make a more permanent and reusable command object, but it would
                // require extensive analysis of at least how the member variables it modifies are used to make
                // sure it is safe. At this point I'm going for the safest change I can. This whole area of the
                // system is likely to be rewritten sometime.
                tempCommand = new WrapParagraphDisplayCommand(childFrag, this, sParaStyle, tssBefore,
                                                              listDelimitNode, fNumber, fDelayNumber, xaNum, ttpNum);
                tempId = m_viewConstructor.GetId(tempCommand);
                tempCommand.DelayedNumber = tssDelayedNumber;
            }
            for (var ihvo = 0; ihvo < chvo; ++ihvo)
            {
                if (IsExcluded(exclude, ihvo, rghvo))
                {
                    continue;
                }

                if (fCheckForEmptyItems && IsItemEmpty(rghvo[ihvo], childFrag))
                {
                    continue;
                }

                Debug.Assert(ihvo < rghvo.Length);
                if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
                {
                    // Passing tempId causes it to use the tempCommand we made above, which does
                    // much the same as the code in the else branch, except for wrapping the content
                    // of the object in a paragraph (and not inserting separators). In general we want to keep
                    // them the same, which is why the common code is wrapped in the AddItemEmbellishments
                    // method. The critical thing is that the paragraph must be part of the object,
                    // even though it is caused by the listDelimitNode attributes rather than by those
                    // of the XML that directly controls the display of the object.
                    m_vwEnv.AddObj(rghvo[ihvo], m_viewConstructor, tempId);
                }
                else
                {
                    // not part of add embellishments because never used with either showAsParagraphs option
                    AddSeparatorIfNeeded(fFirst, xattrSeparator, listDelimitNode, wsEng);
                    AddItemEmbellishments(listDelimitNode, fNumber, rghvo[ihvo], ihvo, xaNum, ttpNum, fDelayNumber, ref tssDelayedNumber);
                    m_vwEnv.AddObj(rghvo[ihvo], m_viewConstructor, childFrag);
                    fFirst = false;
                }

                if (fFirstOnly)
                {
                    break;
                }
            }             // end of sequence 'for' loop
            if (tempCommand != null)
            {
                tssDelayedNumber = tempCommand.DelayedNumber;                 // recover the end result of how it was modified.
                m_viewConstructor.RemoveCommand(tempCommand, tempId);
            }

            // Close Inner Pile if displaying paragraphs
            if (fShowAsParagraphsInInnerPile && chvo > 0)
            {
                m_vwEnv.CloseInnerPile();
            }

            // Reset the flag for ignoring grammatical information after the first if it was set
            // earlier in this method.
            if (fSingleGramInfoFirst)
            {
                m_viewConstructor.ShouldIgnoreGramInfo = false;
            }

            // Reset the flag for delaying displaying a number.
            if (m_viewConstructor.DelayNumFlag && m_hvo == m_hvoDelayedNumber)
            {
                m_viewConstructor.DelayNumFlag = false;
                tssDelayedNumber = null;
            }

            // end of Display method
        }
示例#2
0
		/// <summary>
		/// The main entry point to do the work of the original method.
		/// </summary>
		internal void Display(ref ITsString tssDelayedNumber)
		{
			MainCallerDisplayCommand dispInfo;
			if (!m_viewConstructor.CanGetMainCallerDisplayCommand(m_frag, out dispInfo))
			{
				// Shouldn't be possible, but just in case...
				Debug.Assert(true, "No MainCallerDisplayCommand!");
				return;
			}

			XmlNode listDelimitNode; // has the list seps attrs like 'sep'
			XmlNode specialAttrsNode;  // has the more exotic ones like 'excludeHvo'
			listDelimitNode = specialAttrsNode = dispInfo.MainNode;
			// 'inheritSeps' attr means to use the 'caller' (the part ref node)
			// to get the separator information.
			if (XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "inheritSeps", false))
				listDelimitNode = dispInfo.Caller;

			//
			// 1. get number of items in vector
			//
			var chvo = m_sda.get_VecSize(m_hvo, m_flid);
			if (chvo == 0)
			{
				// We may want to do something special for empty vectors.  See LT-9687.
				ProcessEmptyVector(m_vwEnv, m_hvo, m_flid);
				return;
			}
			//
			// 2. for each item in the vector,
			//		a) print leading number if desired.
			//		b) call AddObj
			//		c) print separator if desired and needed
			//
			int[] rghvo = GetVector(m_sda, m_hvo, m_flid);
			Debug.Assert(chvo == rghvo.Length);
			//
			// Define some special boolean flags.
			//
			// Note that we deliberately don't use the listDelimitNode here.
			// These three props are not currently configurable, and they belong on the 'seq' element,
			// not the part ref.
			var fCheckForEmptyItems = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode,
				"checkForEmptyItems", false);
			string exclude = XmlUtils.GetOptionalAttributeValue(specialAttrsNode, "excludeHvo", null);
			var fFirstOnly = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode, "firstOnly", false);

			XmlAttribute xaNum;
			var fNumber = SetNumberFlagIncludingSingleOption(listDelimitNode, chvo, out xaNum);

			ApplySortingIfSpecified(rghvo, specialAttrsNode);

			// Determine if sequence should be filtered by a stored list of Guids.
			// Note that if we filter, we replace rghvo with the filtered list.
			if (m_viewConstructor.ShouldFilterByGuid)
			{  // order by vector item type guids
				// Don't reorder LexEntry VisibleComplexFormBackRefs vector if the user overrode it manually.
				var obj = m_cache.ServiceLocator.GetObject(m_hvo);
				if (obj is ILexEntry)
				{
					var lexEntry = obj as ILexEntry;
					if (m_flid == m_cache.MetaDataCacheAccessor.GetFieldId("LexEntry", "VisibleComplexFormBackRefs", false))
					{
						if (!VirtualOrderingServices.HasVirtualOrdering(lexEntry, "VisibleComplexFormBackRefs"))
							chvo = ApplyFilterToSequence(ref rghvo);
					}
					else
					{
						chvo = ApplyFilterToSequence(ref rghvo);
					}
				}
				else
				{
					chvo = ApplyFilterToSequence(ref rghvo);
				}
			}

			// Check whether the user wants the grammatical information to appear only once, preceding any
			// sense numbers, if there is only one set of grammatical information, and all senses refer to
			// it.  See LT-9663.
			var childFrag = m_frag;
			var fSingleGramInfoFirst = false;
			if (m_flid == LexEntryTags.kflidSenses)
				fSingleGramInfoFirst = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "singlegraminfofirst", false);

			// This groups senses by placing graminfo before the number, and omitting it if the same as the
			// previous sense in the entry.  This isn't yet supported by the UI, but may well be requested in
			// the future.  (See LT-9663.)
			//bool fGramInfoBeforeNumber = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode, "graminfobeforenumber", false);

			// Setup text properties for any numbering
			int wsEng = m_cache.WritingSystemFactory.GetWsFromStr(strEng);
			ITsTextProps ttpNum = null;
			var fDelayNumber = false;
			if (fNumber)
			{
				ttpNum = SetNumberTextProperties(wsEng, listDelimitNode);
				fDelayNumber = XmlUtils.GetOptionalBooleanAttributeValue(specialAttrsNode, "numdelay", false);
			}

			// A vector may be conditionally configured to display its objects as separate paragraphs
			// in dictionary (document) configuration.  See LT-9667.
			var fShowAsParagraphsInInnerPile = XmlUtils.GetOptionalBooleanAttributeValue(listDelimitNode,
				"showasindentedpara", false);
			// We have (this is probably bad) two ways to do this. The better one is setting the flowType to divInPara.
			// When we do this for a vector, and configure properties that require us to insert numbering and so forth,
			// we currently force a paragraph for each item. It's too hard otherwise to get the numbers etc. into the paragraph.
			// This means that the X_AsPara layout which the configure dialog causes to be invoked when setting up sense-as-para
			// has to be configured NOT to make a paragraph. It also means we can't readily configure a view that has more than one
			// paragraph, except when doing another layer of inserting paragraphs into what is usually a single one. I don't like
			// this much but it does what we need for now and making it better looks very messy.
			var fShowAsParagraphsInDivInPara = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "flowType", null) == "divInPara";
			ITsString tssBefore = null;
			string sParaStyle = null;
			if (fShowAsParagraphsInInnerPile && chvo > 0)
			{
				sParaStyle = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "style");
				tssBefore = SetBeforeString(specialAttrsNode, listDelimitNode);
				// We need a line break here to force the inner pile of paragraphs to begin at
				// the margin, rather than somewhere in the middle of the line.
				m_vwEnv.AddString(m_cache.TsStrFactory.MakeString(StringUtils.kChHardLB.ToString(),
					m_cache.ServiceLocator.WritingSystems.DefaultAnalysisWritingSystem.Handle));
				m_vwEnv.OpenInnerPile();
			}
			else if (fShowAsParagraphsInDivInPara)
			{
				sParaStyle = XmlUtils.GetOptionalAttributeValue(listDelimitNode, "parastyle", "");
			}

			// Setup and run actual internal vector loop
			var xattrSeparator = listDelimitNode.Attributes["sep"];
			var fFirst = true; // May actually mean first non-empty.
			WrapParagraphDisplayCommand tempCommand = null;
			int tempId = 0;
			if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
			{
				// We make a temporary command object, whose purpose is to wrap the paragraphs we want to create
				// here for each item and any embellishments we add INSIDE the display of each individual item.
				// This ensures that if we break those paragraphs (e.g., for subentries of a sense), all the
				// paragraphs for the outer object are still correctly nested inside the item.
				// This is especially important for XML export, where if the paragraph and object elements are
				// not correctly nested, we don't even have valid XML.
				// The command object's lifetime is only as long as this XmlVcDisplayVec,
				// because it references this XmlVcDisplayVec object and even updates some of its member variables.
				// I'm not sure it really has to do that, but I was trying to make a minimal change to the code
				// that had to be wrapped in the command object so it could be invoked by the AddObj call.
				// It is possible we could make a more permanent and reusable command object, but it would
				// require extensive analysis of at least how the member variables it modifies are used to make
				// sure it is safe. At this point I'm going for the safest change I can. This whole area of the
				// system is likely to be rewritten sometime.
				tempCommand = new WrapParagraphDisplayCommand(childFrag, this, sParaStyle, tssBefore,
					listDelimitNode, fNumber, fDelayNumber, xaNum, ttpNum);
				tempId = m_viewConstructor.GetId(tempCommand);
				tempCommand.DelayedNumber = tssDelayedNumber;
			}
			for (var ihvo = 0; ihvo < chvo; ++ihvo)
			{
				if (IsExcluded(exclude, ihvo, rghvo))
					continue;

				if (fCheckForEmptyItems && IsItemEmpty(rghvo[ihvo], childFrag))
					continue;

				Debug.Assert(ihvo < rghvo.Length);
				if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
				{
					// Passing tempId causes it to use the tempCommand we made above, which does
					// much the same as the code in the else branch, except for wrapping the content
					// of the object in a paragraph (and not inserting separators). In general we want to keep
					// them the same, which is why the common code is wrapped in the AddItemEmbellishments
					// method. The critical thing is that the paragraph must be part of the object,
					// even though it is caused by the listDelimitNode attributes rather than by those
					// of the XML that directly controls the display of the object.
					m_vwEnv.AddObj(rghvo[ihvo], m_viewConstructor, tempId);
				}
				else
				{
					// not part of add embellishments because never used with either showAsParagraphs option
					AddSeparatorIfNeeded(fFirst, xattrSeparator, listDelimitNode, wsEng);
					AddItemEmbellishments(listDelimitNode, fNumber, rghvo[ihvo], ihvo, xaNum, ttpNum, fDelayNumber, ref tssDelayedNumber);
					m_vwEnv.AddObj(rghvo[ihvo], m_viewConstructor, childFrag);
					fFirst = false;
				}

				if (fFirstOnly)
					break;
			} // end of sequence 'for' loop
			if (tempCommand != null)
			{
				tssDelayedNumber = tempCommand.DelayedNumber; // recover the end result of how it was modified.
				m_viewConstructor.RemoveCommand(tempCommand, tempId);
			}

			// Close Inner Pile if displaying paragraphs
			if (fShowAsParagraphsInInnerPile && chvo > 0)
				m_vwEnv.CloseInnerPile();

			// Reset the flag for ignoring grammatical information after the first if it was set
			// earlier in this method.
			if (fSingleGramInfoFirst)
				m_viewConstructor.ShouldIgnoreGramInfo = false;

			// Reset the flag for delaying displaying a number.
			if (m_viewConstructor.DelayNumFlag && m_hvo == m_hvoDelayedNumber)
			{
				m_viewConstructor.DelayNumFlag = false;
				tssDelayedNumber = null;
			}

			// end of Display method
		}