Ejemplo n.º 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(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 tsf            = m_cache.TsStrFactory;
            var xattrSeparator = listDelimitNode.Attributes["sep"];
            var fFirst         = true;     // May actually mean first non-empty.

            for (var ihvo = 0; ihvo < chvo; ++ihvo)
            {
                if (IsExcluded(exclude, ihvo, rghvo))
                {
                    continue;
                }

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

                if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
                {
                    SetupParagraph(sParaStyle, (fFirst ? tssBefore : null), listDelimitNode);
                }

                // This needs to happen AFTER we wet up the paragraph that we want it to be part of
                // and any 'before' stuff that goes ahead of the whole sequence, but BEFORE we add any other stuff to the para.
                if (fFirst && fNumber && fSingleGramInfoFirst)
                {
                    var fAllMsaSame = SetAllMsaSameFlag(chvo, rghvo);
                    if (fAllMsaSame)
                    {
                        DisplayFirstChildPOS(rghvo[0], childFrag);
                    }

                    // Exactly if we put out the grammatical info at the start, we need to NOT put it out
                    // as part of each item. Note that we must not set this flag before we put out the one-and-only
                    // gram info, or that will be suppressed too!
                    m_viewConstructor.ShouldIgnoreGramInfo = fAllMsaSame;
                }

                if (!fShowAsParagraphsInInnerPile && !fShowAsParagraphsInDivInPara)
                {
                    AddSeparatorIfNeeded(fFirst, xattrSeparator, listDelimitNode, wsEng);
                }

                // add the numbering if needed.
                if (fNumber)
                {
                    var sTag = CalculateAndFormatSenseLabel(rghvo, ihvo, xaNum);

                    ITsStrBldr tsb = tsf.GetBldr();
                    tsb.Replace(0, 0, sTag, ttpNum);
                    ITsString tss = tsb.GetString();
                    m_numberPartRef = listDelimitNode;
                    AddNumberingNowOrDelayed(fDelayNumber, tss, out tssDelayedNumber);
                }

                // add the object.
                Debug.Assert(ihvo < rghvo.Length);
                m_vwEnv.AddObj(rghvo[ihvo], m_viewConstructor, childFrag);

                // Close Paragraph if displaying paragraphs
                if (fShowAsParagraphsInInnerPile || fShowAsParagraphsInDivInPara)
                {
                    m_vwEnv.CloseParagraph();
                }

                fFirst = false;
                if (fFirstOnly)
                {
                    break;
                }
            }             // end of sequence 'for' loop

            // 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
        }
Ejemplo n.º 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(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
        }