private void PreCoalesceRow(DocumentNode dn, ref bool fVMerged)
        {
            DocumentNodeArray dnaCells = dn.GetRowsCells();
            RowFormat rf = dn.FormatState.RowFormat;
            DocumentNode dnTable = dn.GetParentOfType(DocumentNodeType.dnTable);
            ColumnStateArray csa = (dnTable != null) ? dnTable.ColumnStateArray : null;

            // Normally number of cells and cell definitions are equal, but be careful.
            int nCount = dnaCells.Count < rf.CellCount ? dnaCells.Count : rf.CellCount;

            // Non-unary colspan can arise both because I have "merged" cells specified
            // as well as because I just have cells that exactly span some other cols.
            // The code in PreCoalesce enforces that the cells line up, so I can just
            // test for that here.

            int nColsSeen = 0;
            int i = 0;
            while (i < nCount)
            {
                DocumentNode dnCell = dnaCells.EntryAt(i);
                CellFormat cf = rf.NthCellFormat(i);
                long cellx = cf.CellX;

                // optimization - record if we encountered a vmerged cell
                if (cf.IsVMerge)
                {
                    fVMerged = true;
                }

                // Determine colspan based on cells we will eliminate through the merge flags
                if (cf.IsHMergeFirst)
                {
                    for (i++; i < nCount; i++)
                    {
                        cf = rf.NthCellFormat(i);
                        if (cf.IsVMerge)
                        {
                            fVMerged = true;
                        }
                        if (cf.IsHMerge)
                        {
                            dnaCells.EntryAt(i).ColSpan = 0;    // zero means omit this cell
                        }
                    }
                }
                else
                {
                    i++;
                }

                // Determine actual colspan based on cellx value
                if (csa != null)
                {
                    int nColStart = nColsSeen;

                    while (nColsSeen < csa.Count)
                    {
                        ColumnState cs = csa.EntryAt(nColsSeen);
                        nColsSeen++;

                        // This is the normal case
                        if (cs.CellX == cellx)
                        {
                            break;
                        }

                        // This is anomalous, but can occur with odd \cellx values (non-monotonically increasing).
                        if (cs.CellX > cellx)
                        {
                            break;
                        }
                    }

                    if (nColsSeen - nColStart > dnCell.ColSpan)
                    {
                        dnCell.ColSpan = nColsSeen - nColStart;
                    }
                }
            }
        }
예제 #2
0
        private void WriteStructure(DocumentNode dnThis) 
        {
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
            bool nested = dnThis.GetParentOfType(DocumentNodeType.dnCell) != null;
 
            // Prolog
            switch (dnThis.Type) 
            { 
                case DocumentNodeType.dnSection:
                    { 
                        WriteSection(dnThis);
                        return;
                    }
 
                case DocumentNodeType.dnParagraph:
                    { 
                        WriteParagraph(dnThis); 
                        return;
                    } 

                case DocumentNodeType.dnInline:
                    {
                        WriteInlineChild(dnThis); 
                        return;
                    } 
 
                case DocumentNodeType.dnInlineUIContainer:
                case DocumentNodeType.dnBlockUIContainer: 
                    {
                        WriteUIContainerChild(dnThis);
                        return;
                    } 

                case DocumentNodeType.dnList: 
                case DocumentNodeType.dnListItem: 
                    // Handled as paragraph properties
                    break; 

                case DocumentNodeType.dnTable:
                    // Make sure column format is canonicalized
                    if (dnThis.FormatState.HasRowFormat) 
                    {
                        dnThis.FormatState.RowFormat.Trleft = dnThis.FormatState.LI; 
                        dnThis.FormatState.RowFormat.CanonicalizeWidthsFromXaml(); 
                    }
                    PatchVerticallyMergedCells(dnThis); 
                    break;

                case DocumentNodeType.dnTableBody:
                    // For RTF, we only write row properties. 
                    break;
 
                case DocumentNodeType.dnRow: 
                    WriteRow(dnThis);
                    break; 

                case DocumentNodeType.dnCell:
                    break;
 
                default:
                    // Not really structure 
                    return; 
            }
 
            // Write direct children, except for row
            if (dnThis.Type != DocumentNodeType.dnRow)
            {
                int nStart = dnThis.Index + 1; 
                int nEnd = dnThis.Index + dnThis.ChildCount;
 
                for (; nStart <= nEnd; nStart++) 
                {
                    DocumentNode dnChild = dna.EntryAt(nStart); 

                    if (dnChild.Parent == dnThis)
                    {
                        WriteStructure(dnChild); 
                    }
                } 
            } 

            // Epilog 
            switch (dnThis.Type)
            {
                case DocumentNodeType.dnList:
                case DocumentNodeType.dnListItem: 
                    // Handled as paragraph properties
                    break; 
 
                case DocumentNodeType.dnTable:
                    break; 

                case DocumentNodeType.dnTableBody:
                    break;
 
                case DocumentNodeType.dnRow:
                    // Handled above 
                    break; 

                case DocumentNodeType.dnCell: 
                    if (!dnThis.IsTerminated)
                    {
                        _rtfBuilder.Append(nested ? "\\nestcell" : "\\cell");
                        _rtfBuilder.Append("\r\n"); 
                    }
                    break; 
            } 
        }
예제 #3
0
        /// <summary>
        /// Wirte the CellX control and value to layout the cell position on the table and
        /// return the last cell x position.
        /// There is no smart calculation for getting cell width without the specified value, 
        /// so we use DefaultCellXAsTwips(1440) magic number which is the default CellX value on Word.
        /// </summary> 
        private long WriteCellDimensions(DocumentNode dnCell, int nCol, long lastCellX) 
        {
            DocumentNode dnTable = dnCell.GetParentOfType(DocumentNodeType.dnTable); 

            if (dnTable.FormatState.HasRowFormat)
            {
                RowFormat rf = dnTable.FormatState.RowFormat; 
                CellFormat cf = rf.NthCellFormat(nCol);
 
                if (dnCell.ColSpan > 1) 
                {
                    CellFormat cfSpanned = new CellFormat(cf); 

                    for (int i = 1; i < dnCell.ColSpan; i++)
                    {
                        cf = rf.NthCellFormat(nCol + i); 
                        cfSpanned.Width.Value += cf.Width.Value;
                        cfSpanned.CellX = cf.CellX; 
                    } 

                    // Calculate the default value if CellX never set or has zero cell count 
                    if (cfSpanned.CellX == -1 || rf.CellCount == 0)
                    {
                        // Calculate the default CellX value with tables width
                        cfSpanned.CellX = lastCellX + 
                            dnCell.ColSpan * DefaultCellXAsTwips +
                            GetDefaultAllTablesWidthFromCell(dnCell); 
                    } 

                    // Write the encoded width information like as CellX control and value 
                    _rtfBuilder.Append(cfSpanned.RTFEncodingForWidth);

                    // Save the last CellX value to accumulate it with the next cell
                    lastCellX = cfSpanned.CellX; 
                }
                else 
                { 
                    if (cf.CellX == -1 || rf.CellCount == 0)
                    { 
                        // Calculate the default CellX value
                        cf.CellX = lastCellX + DefaultCellXAsTwips + GetDefaultAllTablesWidthFromCell(dnCell);
                    }
 
                    // Write the encoded width information like as CellX control and value
                    _rtfBuilder.Append(cf.RTFEncodingForWidth); 
 
                    lastCellX = cf.CellX;
                } 
            }
            else
            {
                _rtfBuilder.Append("\\clftsWidth1"); 
                _rtfBuilder.Append("\\cellx");
 
                // Set the CellX value and write the CellX control and value 
                long cellX = lastCellX + dnCell.ColSpan * DefaultCellXAsTwips;
                _rtfBuilder.Append(cellX.ToString(CultureInfo.InvariantCulture)); 

                lastCellX = cellX;
            }
 
            return lastCellX;
        } 
예제 #4
0
        private void WriteRowSettings(DocumentNode dnRow)
        {
            DocumentNode dnTable = dnRow.GetParentOfType(DocumentNodeType.dnTable);
            DirState dirHere = dnTable != null ? dnTable.XamlDir : DirState.DirLTR; 
            DirState dirPa = dnTable != null ? dnTable.ParentXamlDir : DirState.DirLTR;
 
            if (dnTable != null) 
            {
                // Note: Parent directionality determines margin interpretation. 
                long l = dirPa == DirState.DirLTR ? dnTable.FormatState.LI : dnTable.FormatState.RI;
                string s = l.ToString(CultureInfo.InvariantCulture);
                _rtfBuilder.Append("\\trleft");
                _rtfBuilder.Append(s); 
                _rtfBuilder.Append("\\trgaph-");
                _rtfBuilder.Append(s); 
            } 
            else
            { 
                _rtfBuilder.Append("\\trgaph0");
                _rtfBuilder.Append("\\trleft0");
            }
            WriteRowBorders(dnRow); 
            WriteRowDimensions(dnRow);
            WriteRowPadding(dnRow); 
            _rtfBuilder.Append("\\trql"); 
            if (dirHere == DirState.DirRTL)
            { 
                _rtfBuilder.Append("\\rtlrow");
            }
            else
            { 
                _rtfBuilder.Append("\\ltrrow");
            } 
        } 
예제 #5
0
        private bool WriteParagraphListInfo(DocumentNode dnThis, FormatState fsThis)
        { 
            bool bOutControl = false;

            bool bNewStyle = GenerateListTables;
            if (dnThis.ListLabel != null) 
            {
                DocumentNode dnList = dnThis.GetParentOfType(DocumentNodeType.dnList); 
                if (dnList != null) 
                {
                    // Old style list info for RichEdit and other non-Word client compat if I can. 
                    // Only do this for simple, non multi-level lists.
                    if (bNewStyle && dnList.FormatState.PNLVL == 1)
                    {
                        bNewStyle = false; 
                    }
 
                    if (bNewStyle) 
                    {
                        _rtfBuilder.Append("{\\listtext "); 
                        _rtfBuilder.Append(dnThis.ListLabel);
                        if (dnList.FormatState.Marker != MarkerStyle.MarkerBullet
                            && dnList.FormatState.Marker != MarkerStyle.MarkerNone)
                        { 
                            _rtfBuilder.Append(".");
                        } 
                        _rtfBuilder.Append("\\tab}"); 

                        // NB: RichEdit requires \ls keyword to occur immediately after \listtext 
                        if (fsThis.ILS > 0)
                        {
                            _rtfBuilder.Append("\\ls");
                            _rtfBuilder.Append(fsThis.ILS.ToString(CultureInfo.InvariantCulture)); 
                            bOutControl = true;
                        } 
                        if (fsThis.ILVL > 0) 
                        {
                            _rtfBuilder.Append("\\ilvl"); 
                            _rtfBuilder.Append(fsThis.ILVL.ToString(CultureInfo.InvariantCulture));
                            bOutControl = true;
                        }
                    } 
                    else
                    { 
                        _rtfBuilder.Append("{\\pntext "); 
                        _rtfBuilder.Append(dnThis.ListLabel);
                        if (dnList.FormatState.Marker != MarkerStyle.MarkerBullet 
                            && dnList.FormatState.Marker != MarkerStyle.MarkerNone)
                        {
                            _rtfBuilder.Append(".");
                        } 
                        _rtfBuilder.Append("\\tab}{\\*\\pn");
                        _rtfBuilder.Append(Converters.MarkerStyleToOldRTFString(dnList.FormatState.Marker)); 
                        if (fsThis.ListLevel > 0 && dnList.FormatState.PNLVL > 1) 
                        {
                            _rtfBuilder.Append("\\pnlvl"); 
                            _rtfBuilder.Append(fsThis.ListLevel.ToString(CultureInfo.InvariantCulture));
                        }
                        if (fsThis.FI > 0)
                        { 
                            _rtfBuilder.Append("\\pnhang");
                        } 
                        if (fsThis.StartIndex >= 0) 
                        {
                            _rtfBuilder.Append("\\pnstart"); 
                            _rtfBuilder.Append(fsThis.StartIndex.ToString(CultureInfo.InvariantCulture));
                        }
                        if (dnList.FormatState.Marker == MarkerStyle.MarkerBullet)
                        { 
                            _rtfBuilder.Append("{\\pntxtb\\'B7}}");
                        } 
                        else if (dnList.FormatState.Marker == MarkerStyle.MarkerNone) 
                        {
                            _rtfBuilder.Append("{\\pntxta }{\\pntxtb }}"); 
                        }
                        else
                        {
                            _rtfBuilder.Append("{\\pntxta .}}"); 
                        }
 
                        // Already terminated with curly, no need for extra space. 
                        bOutControl = false;
                    } 
                }
            }

            return bOutControl; 
        }
예제 #6
0
        private void WriteParagraph(DocumentNode dnThis) 
        {
            int nStart = dnThis.Index + 1; 
            int nEnd = dnThis.Index + dnThis.ChildCount; 
            int nAt;
 
            FormatState fsThis = dnThis.FormatState;
            FormatState fsParent = dnThis.Parent != null ? dnThis.Parent.FormatState : FormatState.EmptyFormatState;
            DocumentNodeArray dna = _converterState.DocumentNodeArray;
 
            _rtfBuilder.Append("{");
 
            bool bOutControl = WriteParagraphFontInfo(dnThis, fsThis, fsParent); 

            // Structure properties 
            // NB: RE 4.01 seems to require \intbl keyword to come before inline content
            if (fsThis.IsInTable)
            {
                _rtfBuilder.Append("\\intbl"); 
                bOutControl = true;
            } 
            if (bOutControl) 
            {
                _rtfBuilder.Append(" "); 
            }

            bOutControl = WriteParagraphListInfo(dnThis, fsThis);
            if (bOutControl) 
            {
                _rtfBuilder.Append(" "); 
            } 

            // FlowDirection control - state it before writing nested inline node. 
            // MsWord expect "rtlpar" control before writing inline, but Wordpad
            // doesn't matter state it before or after of inline writing.
            if (fsThis.DirPara == DirState.DirRTL)
            { 
                _rtfBuilder.Append("\\rtlpar");
            } 
 
            // OK, now write out the inline children.
            for (nAt = nStart; nAt <= nEnd; nAt++) 
            {
                DocumentNode dnChild = dna.EntryAt(nAt);

                // Ignore non-direct children - they get written out by their parent 
                if (dnChild.Parent == dnThis)
                { 
                    WriteInlineChild(dnChild); 
                }
            } 

            // Structure properties
            if (fsThis.ITAP > 1)
            { 
                _rtfBuilder.Append("\\itap");
                _rtfBuilder.Append(fsThis.ITAP.ToString(CultureInfo.InvariantCulture)); 
            } 

            // Margins 
            _rtfBuilder.Append("\\li");
            _rtfBuilder.Append(fsThis.LI.ToString(CultureInfo.InvariantCulture));
            _rtfBuilder.Append("\\ri");
            _rtfBuilder.Append(fsThis.RI.ToString(CultureInfo.InvariantCulture)); 
            _rtfBuilder.Append("\\sa");
            _rtfBuilder.Append(fsThis.SA.ToString(CultureInfo.InvariantCulture)); 
            _rtfBuilder.Append("\\sb"); 
            _rtfBuilder.Append(fsThis.SB.ToString(CultureInfo.InvariantCulture));
 
            // Borders
            if (fsThis.HasParaBorder)
            {
                _rtfBuilder.Append(fsThis.ParaBorder.RTFEncoding); 
            }
 
            // TextIndent 
            if (dnThis.ListLabel != null)
            { 
                _rtfBuilder.Append("\\jclisttab\\tx");
                _rtfBuilder.Append(fsThis.LI.ToString(CultureInfo.InvariantCulture));
                _rtfBuilder.Append("\\fi-360");
            } 
            else
            { 
                _rtfBuilder.Append("\\fi"); 
                _rtfBuilder.Append(fsThis.FI.ToString(CultureInfo.InvariantCulture));
            } 

            // Alignment
            switch (fsThis.HAlign)
            { 
                case HAlign.AlignLeft:
                    if (fsThis.DirPara != DirState.DirRTL) 
                    { 
                        _rtfBuilder.Append("\\ql");
                    } 
                    else
                    {
                        _rtfBuilder.Append("\\qr");
                    } 
                    break;
                case HAlign.AlignRight: 
                    if (fsThis.DirPara != DirState.DirRTL) 
                    {
                        _rtfBuilder.Append("\\qr"); 
                    }
                    else
                    {
                        _rtfBuilder.Append("\\ql"); 
                    }
                    break; 
                case HAlign.AlignCenter: 
                    _rtfBuilder.Append("\\qc");
                    break; 
                case HAlign.AlignJustify:
                    _rtfBuilder.Append("\\qj");
                    break;
            } 

            // Background color 
            if (fsThis.CBPara >= 0) 
            {
                _rtfBuilder.Append("\\cbpat"); 
                _rtfBuilder.Append(fsThis.CBPara.ToString(CultureInfo.InvariantCulture));
            }

            // LineHeight 
            if (fsThis.SL != 0)
            { 
                _rtfBuilder.Append("\\sl"); 
                _rtfBuilder.Append(fsThis.SL.ToString(CultureInfo.InvariantCulture));
                _rtfBuilder.Append("\\slmult0"); 
            }

            // omit \par if last paragraph in cell
            if (dnThis.IsLastParagraphInCell()) 
            {
                DocumentNode dnCell = dnThis.GetParentOfType(DocumentNodeType.dnCell); 
                dnCell.IsTerminated = true; 
                if (fsThis.ITAP > 1)
                { 
                    _rtfBuilder.Append("\\nestcell");
                    _rtfBuilder.Append("{\\nonesttables\\par}");

                } 
                else
                { 
                    _rtfBuilder.Append("\\cell"); 
                }
                _rtfBuilder.Append("\r\n"); 
            }
            else
            {
                _rtfBuilder.Append("\\par"); 
            }
            _rtfBuilder.Append("}"); 
            _rtfBuilder.Append("\r\n"); 
        }