tdf#147067 Jump to clicked spot if left mouse click with Option key
[LibreOffice.git] / sw / source / filter / ww8 / WW8TableInfo.cxx
blobc148285e0ec0fe41d48ae8ed1f9cf9655cf265fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <iostream>
21 #include <stdio.h>
22 #include "WW8TableInfo.hxx"
23 #include <fmtfsize.hxx>
24 #include "attributeoutputbase.hxx"
25 #include <swtable.hxx>
26 #include <frmfmt.hxx>
27 #include <pam.hxx>
28 #include <dbgoutsw.hxx>
29 #include <sal/log.hxx>
30 #include <osl/diagnose.h>
31 #include <rtl/string.hxx>
33 namespace ww8
36 WW8TableNodeInfoInner::WW8TableNodeInfoInner(WW8TableNodeInfo * pParent)
37 : mpParent(pParent)
38 , mnDepth(0)
39 , mnCell(0)
40 , mnRow(0)
41 , mnShadowsBefore(0)
42 , mnShadowsAfter(0)
43 , mbEndOfLine(false)
44 , mbFinalEndOfLine(false)
45 , mbEndOfCell(false)
46 , mbFirstInTable(false)
47 , mbVertMerge(false)
48 , mpTableBox(nullptr)
49 , mpTable(nullptr)
53 void WW8TableNodeInfoInner::setDepth(sal_uInt32 nDepth)
55 mnDepth = nDepth;
58 void WW8TableNodeInfoInner::setCell(sal_uInt32 nCell)
60 mnCell = nCell;
63 void WW8TableNodeInfoInner::setRow(sal_uInt32 nRow)
65 mnRow = nRow;
68 void WW8TableNodeInfoInner::setShadowsBefore(sal_uInt32 nShadowsBefore)
70 mnShadowsBefore = nShadowsBefore;
73 void WW8TableNodeInfoInner::setShadowsAfter(sal_uInt32 nShadowsAfter)
75 mnShadowsAfter = nShadowsAfter;
78 void WW8TableNodeInfoInner::setEndOfLine(bool bEndOfLine)
80 mbEndOfLine = bEndOfLine;
83 void WW8TableNodeInfoInner::setFinalEndOfLine(bool bFinalEndOfLine)
85 mbFinalEndOfLine = bFinalEndOfLine;
88 void WW8TableNodeInfoInner::setEndOfCell(bool bEndOfCell)
90 mbEndOfCell = bEndOfCell;
93 void WW8TableNodeInfoInner::setFirstInTable(bool bFirstInTable)
95 mbFirstInTable = bFirstInTable;
98 void WW8TableNodeInfoInner::setVertMerge(bool bVertMerge)
101 mbVertMerge = bVertMerge;
104 void WW8TableNodeInfoInner::setTableBox(const SwTableBox * pTableBox)
106 mpTableBox = pTableBox;
109 void WW8TableNodeInfoInner::setTable(const SwTable * pTable)
111 mpTable = pTable;
114 void WW8TableNodeInfoInner::setRect(const SwRect & rRect)
116 maRect = rRect;
119 const SwNode * WW8TableNodeInfoInner::getNode() const
121 const SwNode * pResult = nullptr;
123 if (mpParent != nullptr)
124 pResult = mpParent->getNode();
126 return pResult;
129 TableBoxVectorPtr WW8TableNodeInfoInner::getTableBoxesOfRow() const
131 TableBoxVectorPtr pResult = std::make_shared<TableBoxVector>();
133 WW8TableCellGrid::Pointer_t pCellGrid =
134 mpParent->getParent()->getCellGridForTable(getTable(), false);
136 if (!pCellGrid)
138 const SwTableLine * pTabLine = getTableBox()->GetUpper();
139 const SwTableBoxes & rTableBoxes = pTabLine->GetTabBoxes();
141 sal_uInt8 nBoxes = rTableBoxes.size();
142 if (nBoxes > MAXTABLECELLS)
143 nBoxes = MAXTABLECELLS;
144 for ( sal_uInt8 n = 0; n < nBoxes; n++ )
146 pResult->push_back(rTableBoxes[n]);
149 else
150 pResult = pCellGrid->getTableBoxesOfRow(this);
152 return pResult;
155 GridColsPtr WW8TableNodeInfoInner::getGridColsOfRow(AttributeOutputBase & rBase, bool calculateColumnsFromAllRows)
157 GridColsPtr pResult = std::make_shared<GridCols>();
158 WidthsPtr pWidths;
160 // Check which columns should be checked - only the current row,
161 // or all the rows together
162 if (calculateColumnsFromAllRows)
164 // Calculate the width of all the columns based on ALL the rows.
165 // The difference is that this kind of draws vertical lines,
166 // so that if the rows look like this:
168 // ------------------------
169 // | | |
170 // ------------------------
171 // | | |
172 // ------------------------
173 // | | |
174 // ------------------------
176 // then the actual column widths will be broken down like this:
178 // ------------------------
179 // | | | | |
180 // ------------------------
182 // See the example at
183 // http://officeopenxml.com/WPtableGrid.php
184 // Under "Word 2007 Example"
185 pWidths = getColumnWidthsBasedOnAllRows();
187 else
189 // Calculate the width of all the columns based on the current row
190 pWidths = getWidthsOfRow();
193 const SwFrameFormat *pFormat = getTable()->GetFrameFormat();
194 OSL_ENSURE(pFormat,"Impossible");
195 if (!pFormat)
196 return pResult;
198 const SwFormatFrameSize &rSize = pFormat->GetFrameSize();
199 tools::ULong nTableSz = static_cast<tools::ULong>(rSize.GetWidth());
201 tools::Long nPageSize = 0;
202 bool bRelBoxSize = false;
204 rBase.GetTablePageSize( this, nPageSize, bRelBoxSize );
206 SwTwips nSz = 0;
207 for (const auto& rWidth : *pWidths)
209 nSz += rWidth;
210 SwTwips nCalc = nSz;
211 if ( bRelBoxSize )
212 nCalc = ( nCalc * nPageSize ) / nTableSz;
214 pResult->push_back( nCalc );
217 return pResult;
220 WidthsPtr WW8TableNodeInfoInner::getColumnWidthsBasedOnAllRows() const
222 WidthsPtr pWidths;
224 WW8TableCellGrid::Pointer_t pCellGrid =
225 mpParent->getParent()->getCellGridForTable(getTable(), false);
227 if (!pCellGrid)
229 const SwTable * pTable = getTable();
230 const SwTableLines& rTableLines = pTable->GetTabLines();
231 const size_t nNumOfLines = rTableLines.size();
233 // Go over all the rows - and for each row - calculate where
234 // there is a separator between columns
235 WidthsPtr pSeparators = std::make_shared<Widths>();
236 for ( size_t nLineIndex = 0; nLineIndex < nNumOfLines; ++nLineIndex )
238 const SwTableLine *pCurrentLine = rTableLines[nLineIndex];
239 const SwTableBoxes & rTabBoxes = pCurrentLine->GetTabBoxes();
240 size_t nBoxes = rTabBoxes.size();
241 if (nBoxes > MAXTABLECELLS)
242 nBoxes = MAXTABLECELLS;
244 sal_uInt32 nSeparatorPosition = 0;
245 for (size_t nBoxIndex = 0; nBoxIndex < nBoxes; ++nBoxIndex)
247 const SwFrameFormat* pBoxFormat = rTabBoxes[ nBoxIndex ]->GetFrameFormat();
248 const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
249 nSeparatorPosition += rLSz.GetWidth();
250 pSeparators->push_back(nSeparatorPosition);
254 // Sort the separator positions and remove any duplicates
255 std::sort(pSeparators->begin(), pSeparators->end());
256 std::vector<sal_uInt32>::iterator it = std::unique(pSeparators->begin(), pSeparators->end());
257 pSeparators->erase(it, pSeparators->end());
259 // Calculate the widths based on the position of the unique & sorted
260 // column separators
261 pWidths = std::make_shared<Widths>();
262 sal_uInt32 nPreviousWidth = 0;
263 for (const sal_uInt32 nCurrentWidth : *pSeparators)
265 pWidths->push_back(nCurrentWidth - nPreviousWidth);
266 nPreviousWidth = nCurrentWidth;
269 else
271 pWidths = pCellGrid->getWidthsOfRow(this);
274 return pWidths;
277 WidthsPtr WW8TableNodeInfoInner::getWidthsOfRow() const
279 WidthsPtr pWidths;
281 WW8TableCellGrid::Pointer_t pCellGrid =
282 mpParent->getParent()->getCellGridForTable(getTable(), false);
284 if (!pCellGrid)
286 const SwTableBox * pTabBox = getTableBox();
287 const SwTableLine * pTabLine = pTabBox->GetUpper();
288 const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
290 pWidths = std::make_shared<Widths>();
291 // number of cell written
292 sal_uInt32 nBoxes = rTabBoxes.size();
293 if (nBoxes > MAXTABLECELLS)
294 nBoxes = MAXTABLECELLS;
296 for (sal_uInt32 n = 0; n < nBoxes; n++)
298 const SwFrameFormat* pBoxFormat = rTabBoxes[ n ]->GetFrameFormat();
299 const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
301 pWidths->push_back(rLSz.GetWidth());
304 else
305 pWidths = pCellGrid->getWidthsOfRow(this);
307 return pWidths;
310 RowSpansPtr WW8TableNodeInfoInner::getRowSpansOfRow() const
312 RowSpansPtr pResult = std::make_shared<RowSpans>();
314 WW8TableCellGrid::Pointer_t pCellGrid =
315 mpParent->getParent()->getCellGridForTable(getTable(), false);
317 if (!pCellGrid)
319 const SwTableBox * pTabBox = getTableBox();
320 const SwTableLine * pTabLine = pTabBox->GetUpper();
321 const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
323 sal_uInt32 nBoxes = rTabBoxes.size();
324 if (nBoxes > MAXTABLECELLS)
325 nBoxes = MAXTABLECELLS;
327 for (sal_uInt32 n = 0; n < nBoxes; ++n)
329 pResult->push_back(rTabBoxes[n]->getRowSpan());
332 else
333 pResult = pCellGrid->getRowSpansOfRow(this);
335 return pResult;
339 #ifdef DBG_UTIL
340 std::string WW8TableNodeInfoInner::toString() const
342 static char buffer[256];
343 snprintf(buffer, sizeof(buffer),
344 "<tableinner depth=\"%" SAL_PRIuUINT32 "\""
345 " cell=\"%" SAL_PRIuUINT32 "\""
346 " row=\"%" SAL_PRIuUINT32 "\""
347 " endOfCell=\"%s\""
348 " endOfLine=\"%s\""
349 " shadowsBefore=\"%" SAL_PRIuUINT32 "\""
350 " shadowsAfter=\"%" SAL_PRIuUINT32 "\""
351 " vertMerge=\"%s\"/>",
352 mnDepth, mnCell, mnRow,
353 mbEndOfCell ? "yes" : "no",
354 mbEndOfLine ? "yes" : "no",
355 mnShadowsBefore,
356 mnShadowsAfter,
357 mbVertMerge ? "yes" : "no");
359 return std::string(buffer);
361 #endif
363 WW8TableNodeInfo::WW8TableNodeInfo(WW8TableInfo * pParent,
364 const SwNode * pNode)
365 : mpParent(pParent),
366 mnDepth(0),
367 mpNode(pNode),
368 mpNext(nullptr),
369 mpNextNode(nullptr)
373 WW8TableNodeInfo::~WW8TableNodeInfo()
377 #ifdef DBG_UTIL
378 std::string WW8TableNodeInfo::toString() const
380 static char buffer[1024];
381 snprintf(buffer, sizeof(buffer),
382 "<tableNodeInfo p=\"%p\" depth=\"%" SAL_PRIuUINT32 "\">"
383 ,this, getDepth());
385 std::string sResult(buffer);
387 for (const auto& rInner : mInners)
389 WW8TableNodeInfoInner::Pointer_t pInner = rInner.second;
390 sResult += pInner->toString();
392 sResult += dbg_out(*mpNode);
393 sResult += "</tableNodeInfo>";
395 return sResult;
397 #endif
399 void WW8TableNodeInfo::setDepth(sal_uInt32 nDepth)
401 mnDepth = nDepth;
403 Inners_t::iterator aIt = mInners.find(mnDepth);
405 if (aIt == mInners.end())
406 mInners[mnDepth] = std::make_shared<ww8::WW8TableNodeInfoInner>(this);
408 mInners[mnDepth]->setDepth(mnDepth);
411 void WW8TableNodeInfo::setEndOfLine(bool bEndOfLine)
413 WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
414 pInner->setEndOfLine(bEndOfLine);
416 #ifdef DBG_UTIL
417 SAL_INFO( "sw.ww8", "<endOfLine depth=\"" << mnDepth << "\">" << toString() << "</endOfLine>" );
418 #endif
421 void WW8TableNodeInfo::setEndOfCell(bool bEndOfCell)
423 WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
424 pInner->setEndOfCell(bEndOfCell);
426 #ifdef DBG_UTIL
427 SAL_INFO( "sw.ww8", "<endOfCell depth=\"" << mnDepth << "\">" << toString() << "</endOfCell>" );
428 #endif
431 void WW8TableNodeInfo::setFirstInTable(bool bFirstInTable)
433 WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
435 pInner->setFirstInTable(bFirstInTable);
437 #ifdef DBG_UTIL
438 SAL_INFO( "sw.ww8", "<firstInTable depth=\"" << mnDepth << "\">" << toString() << "</firstInTable>" );
439 #endif
442 void WW8TableNodeInfo::setVertMerge(bool bVertMerge)
444 WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
446 pInner->setVertMerge(bVertMerge);
448 #ifdef DBG_UTIL
449 SAL_INFO( "sw.ww8", "<vertMerge depth=\"" << mnDepth << "\">" << toString() << "</vertMerge>" );
450 #endif
453 void WW8TableNodeInfo::setTableBox(const SwTableBox * pTableBox)
455 getInnerForDepth(mnDepth)->setTableBox(pTableBox);
458 void WW8TableNodeInfo::setTable(const SwTable * pTable)
460 getInnerForDepth(mnDepth)->setTable(pTable);
463 void WW8TableNodeInfo::setNext(WW8TableNodeInfo * pNext)
465 mpNext = pNext;
467 #ifdef DBG_UTIL
468 SAL_INFO( "sw.ww8", "<setnext><from>" << toString() << "</from><to>" << pNext->toString() << "</to></setnext>" );
469 #endif
472 void WW8TableNodeInfo::setNextNode(const SwNode * pNode)
474 mpNextNode = pNode;
477 void WW8TableNodeInfo::setRect(const SwRect & rRect)
479 getInnerForDepth(mnDepth)->setRect(rRect);
482 void WW8TableNodeInfo::setCell(sal_uInt32 nCell)
484 getInnerForDepth(mnDepth)->setCell(nCell);
487 void WW8TableNodeInfo::setRow(sal_uInt32 nRow)
489 getInnerForDepth(mnDepth)->setRow(nRow);
492 void WW8TableNodeInfo::setShadowsBefore(sal_uInt32 nShadowsBefore)
494 getInnerForDepth(mnDepth)->setShadowsBefore(nShadowsBefore);
497 void WW8TableNodeInfo::setShadowsAfter(sal_uInt32 nShadowsAfter)
499 getInnerForDepth(mnDepth)->setShadowsAfter(nShadowsAfter);
503 sal_uInt32 WW8TableNodeInfo::getDepth() const
505 if (!mInners.empty())
506 return mInners.begin()->second->getDepth();
508 return mnDepth;
512 const SwTableBox * WW8TableNodeInfo::getTableBox() const
514 return getInnerForDepth(mnDepth)->getTableBox();
517 sal_uInt32 WW8TableNodeInfo::getCell() const
519 return getInnerForDepth(mnDepth)->getCell();
522 sal_uInt32 WW8TableNodeInfo::getRow() const
524 return getInnerForDepth(mnDepth)->getRow();
527 WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getFirstInner() const
529 WW8TableNodeInfoInner::Pointer_t pResult;
531 if (!mInners.empty())
532 pResult = mInners.begin()->second;
534 return pResult;
537 WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getInnerForDepth(sal_uInt32 nDepth) const
539 WW8TableNodeInfoInner::Pointer_t pResult;
541 Inners_t::const_iterator aIt = mInners.find(nDepth);
542 if (aIt != mInners.end())
544 pResult = aIt->second;
547 return pResult;
550 WW8TableInfo::WW8TableInfo()
554 WW8TableInfo::~WW8TableInfo()
558 WW8TableNodeInfo *
559 WW8TableInfo::processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
561 SwTableCellInfo aTableCellInfo(pTable);
563 while (aTableCellInfo.getNext())
565 SwRect aRect = aTableCellInfo.getRect();
567 SAL_INFO( "sw.ww8", "<CellFrame>" );
568 SAL_INFO( "sw.ww8", "<rect top=\"" << aRect.Top() << "\" bottom=\"" << aRect.Bottom()
569 << "\" left=\"" << aRect.Left() << "\" right=\"" << aRect.Right() << "\"/>" );
570 const SwTableBox * pTableBox = aTableCellInfo.getTableBox();
571 const SwStartNode * pSttNd = pTableBox->GetSttNd();
573 if (pSttNd != nullptr)
575 SwPaM aPam(*pSttNd, 0);
577 bool bDone = false;
580 SwNode & rNode = aPam.GetPoint()->GetNode();
582 insertTableNodeInfo(&rNode, pTable, pTableBox, 0, 0, 1, & aRect);
584 if (rNode.IsEndNode())
586 SwEndNode * pEndNode = rNode.GetEndNode();
587 SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
589 if (pTmpSttNd == pSttNd)
590 bDone = true;
593 aPam.GetPoint()->Adjust(SwNodeOffset(1));
595 while (!bDone);
598 SAL_INFO( "sw.ww8", "</CellFrame>" );
601 return reorderByLayout(pTable, rLastRowEnds);
604 void WW8TableInfo::processSwTable(const SwTable * pTable)
606 SAL_INFO( "sw.ww8", "<processSwTable>" );
608 WW8TableNodeInfo * pPrev = nullptr;
609 RowEndInners_t aLastRowEnds;
611 if (pTable->IsTableComplex() && pTable->HasLayout())
613 pPrev = processSwTableByLayout(pTable, aLastRowEnds);
614 #ifdef DBG_UTIL
615 SAL_INFO( "sw.ww8", getCellGridForTable(pTable)->toString());
616 #endif
618 else
620 const SwTableLines & rLines = pTable->GetTabLines();
622 for (size_t n = 0; n < rLines.size(); ++n)
624 const SwTableLine * pLine = rLines[n];
626 pPrev = processTableLine(pTable, pLine, static_cast<sal_uInt32>(n), 1, pPrev, aLastRowEnds);
631 if (pPrev)
633 SwTableNode * pTableNode = pTable->GetTableNode();
634 SwEndNode * pEndNode = pTableNode->EndOfSectionNode();
635 pPrev->setNextNode(pEndNode);
636 assert(!aLastRowEnds.empty());
637 for (auto &a : aLastRowEnds)
639 assert(a.second->isEndOfLine());
640 a.second->setFinalEndOfLine(true);
643 SAL_INFO( "sw.ww8", "</processSwTable>" );
646 WW8TableNodeInfo *
647 WW8TableInfo::processTableLine(const SwTable * pTable,
648 const SwTableLine * pTableLine,
649 sal_uInt32 nRow,
650 sal_uInt32 nDepth,
651 WW8TableNodeInfo * pPrev,
652 RowEndInners_t &rLastRowEnds)
654 SAL_INFO( "sw.ww8", "<processTableLine row=\"" << nRow << "\" depth=\"" << nDepth << "\">" );
656 const SwTableBoxes & rBoxes = pTableLine->GetTabBoxes();
658 for (size_t n = 0; n < rBoxes.size(); ++n)
660 const SwTableBox * pBox = rBoxes[n];
662 pPrev = processTableBox(pTable, pBox, nRow, static_cast<sal_uInt32>(n), nDepth, n == rBoxes.size() - 1, pPrev, rLastRowEnds);
665 SAL_INFO( "sw.ww8", "</processTableLine>" );
667 return pPrev;
670 WW8TableNodeInfo::Pointer_t
671 WW8TableInfo::processTableBoxLines(const SwTableBox * pBox,
672 const SwTable * pTable,
673 const SwTableBox * pBoxToSet,
674 sal_uInt32 nRow,
675 sal_uInt32 nCell,
676 sal_uInt32 nDepth)
678 SAL_INFO( "sw.ww8", "<processTableBoxLines depth=\"" << nDepth << "\" row=\"" << nRow
679 << "\" cell=\"" << nCell << "\">" );
681 const SwTableLines & rLines = pBox->GetTabLines();
682 WW8TableNodeInfo::Pointer_t pNodeInfo;
684 if (!rLines.empty())
686 for (size_t n = 0; n < rLines.size(); ++n)
688 const SwTableLine * pLine = rLines[n];
689 const SwTableBoxes & rBoxes = pLine->GetTabBoxes();
691 for (size_t nBox = 0; nBox < rBoxes.size(); ++nBox)
692 pNodeInfo = processTableBoxLines(rBoxes[nBox], pTable, pBoxToSet, nRow, nCell, nDepth);
695 else
697 const SwStartNode * pSttNd = pBox->GetSttNd();
698 const SwEndNode * pEndNd = pSttNd->EndOfSectionNode();
699 SwPaM aPaM(*pSttNd, 0);
700 SwPaM aEndPaM(*pEndNd, 0);
702 bool bDone = false;
703 while (!bDone)
705 SwNode & rNode = aPaM.GetPoint()->GetNode();
707 pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBoxToSet, nRow, nCell, nDepth);
709 if (aPaM.GetPoint()->GetNode() == aEndPaM.GetPoint()->GetNode())
710 bDone = true;
711 else
712 aPaM.GetPoint()->Adjust(SwNodeOffset(1));
716 SAL_INFO( "sw.ww8", "</processTableBoxLines>" );
718 return pNodeInfo;
721 static void updateFinalEndOfLine(RowEndInners_t &rLastRowEnds, WW8TableNodeInfo const * pEndOfCellInfo)
723 sal_Int32 nDepth = pEndOfCellInfo->getDepth();
724 WW8TableNodeInfoInner::Pointer_t pInner = pEndOfCellInfo->getInnerForDepth(nDepth);
726 auto aIt = rLastRowEnds.find(nDepth);
727 if (aIt == rLastRowEnds.end() || (pInner->getRow() > aIt->second->getRow()))
728 rLastRowEnds[nDepth] = pInner.get();
731 WW8TableNodeInfo *
732 WW8TableInfo::processTableBox(const SwTable * pTable,
733 const SwTableBox * pBox,
734 sal_uInt32 nRow,
735 sal_uInt32 nCell,
736 sal_uInt32 nDepth,
737 bool bEndOfLine,
738 WW8TableNodeInfo * pPrev,
739 RowEndInners_t &rLastRowEnds)
741 SAL_INFO( "sw.ww8", "<processTableBox row=\"" << nRow << "\" cell=\"" << nCell
742 << "\" depth=\"" << nDepth << "\">" );
744 WW8TableNodeInfo::Pointer_t pNodeInfo;
745 const SwTableLines & rLines = pBox->GetTabLines();
746 const SwStartNode * pSttNd = pBox->GetSttNd();
747 WW8TableNodeInfo::Pointer_t pEndOfCellInfo;
749 if (!rLines.empty())
751 pNodeInfo = processTableBoxLines(pBox, pTable, pBox, nRow, nCell, nDepth);
752 pNodeInfo->setEndOfCell(true);
753 if (bEndOfLine)
755 pNodeInfo->setEndOfLine(true);
756 updateFinalEndOfLine(rLastRowEnds, pNodeInfo.get());
759 for (size_t n = 0; n < rLines.size(); n++)
761 const SwTableLine * pLine = rLines[n];
763 pPrev = processTableLine(pTable, pLine, n, 1, pPrev, rLastRowEnds);
766 else
768 SwPaM aPaM(*pSttNd, 0);
770 bool bDone = false;
771 sal_uInt32 nDepthInsideCell = 0;
775 SwNode & rNode = aPaM.GetPoint()->GetNode();
777 if (rNode.IsStartNode())
779 if (nDepthInsideCell > 0)
780 pEndOfCellInfo.reset();
782 nDepthInsideCell++;
785 pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBox, nRow, nCell, nDepth);
787 if (pPrev)
788 pPrev->setNext(pNodeInfo.get());
790 pPrev = pNodeInfo.get();
792 if (nDepthInsideCell == 1 && rNode.IsTextNode())
793 pEndOfCellInfo = pNodeInfo;
795 if (rNode.IsEndNode())
797 nDepthInsideCell--;
799 if (nDepthInsideCell == 0 && !pEndOfCellInfo)
800 pEndOfCellInfo = pNodeInfo;
802 SwEndNode * pEndNode = rNode.GetEndNode( );
803 SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
804 if (pTmpSttNd == pSttNd)
805 bDone = true;
808 aPaM.GetPoint()->Adjust(SwNodeOffset(1));
810 while (!bDone);
812 if (pEndOfCellInfo)
814 pEndOfCellInfo->setEndOfCell(true);
816 if (bEndOfLine)
818 pEndOfCellInfo->setEndOfLine(true);
819 updateFinalEndOfLine(rLastRowEnds, pEndOfCellInfo.get());
824 SAL_INFO( "sw.ww8", "</processTableBox>" );
826 return pPrev;
829 WW8TableNodeInfo::Pointer_t WW8TableInfo::insertTableNodeInfo
830 (const SwNode * pNode,
831 const SwTable * pTable,
832 const SwTableBox * pTableBox,
833 sal_uInt32 nRow,
834 sal_uInt32 nCell,
835 sal_uInt32 nDepth,
836 SwRect const * pRect)
838 WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
840 if (!pNodeInfo)
842 pNodeInfo =
843 std::make_shared<ww8::WW8TableNodeInfo>(this, pNode);
844 mMap.emplace(pNode, pNodeInfo);
847 pNodeInfo->setDepth(nDepth + pNodeInfo->getDepth());
849 pNodeInfo->setTable(pTable);
850 pNodeInfo->setTableBox(pTableBox);
852 pNodeInfo->setCell(nCell);
853 pNodeInfo->setRow(nRow);
855 if (pNode->IsTextNode())
857 FirstInTableMap_t::const_iterator aIt = mFirstInTableMap.find(pTable);
858 if (aIt == mFirstInTableMap.end())
860 mFirstInTableMap[pTable] = pNode;
861 pNodeInfo->setFirstInTable(true);
865 if (pRect)
867 WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
869 pCellGrid->insert(*pRect, pNodeInfo.get());
870 pNodeInfo->setRect(*pRect);
873 #ifdef DBG_UTIL
874 SAL_INFO( "sw.ww8", pNodeInfo->toString());
875 #endif
876 return pNodeInfo;
879 WW8TableCellGrid::Pointer_t WW8TableInfo::getCellGridForTable
880 (const SwTable * pTable, bool bCreate)
882 WW8TableCellGrid::Pointer_t pResult;
883 CellGridMap_t::iterator aIt = mCellGridMap.find(pTable);
885 if (aIt == mCellGridMap.end())
887 if (bCreate)
889 pResult = std::make_shared<ww8::WW8TableCellGrid>();
890 mCellGridMap[pTable] = pResult;
893 else
894 pResult = mCellGridMap[pTable];
896 return pResult;
899 WW8TableNodeInfo::Pointer_t WW8TableInfo::getTableNodeInfo
900 (const SwNode * pNode)
902 WW8TableNodeInfo::Pointer_t pResult;
903 Map_t::iterator aIt = mMap.find(pNode);
905 if (aIt != mMap.end())
906 pResult = (*aIt).second;
908 return pResult;
911 const SwNode * WW8TableInfo::getNextNode(const SwNode * pNode)
913 const SwNode * pResult = nullptr;
915 WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
917 if (pNodeInfo)
919 WW8TableNodeInfo * pNextInfo = pNodeInfo->getNext();
921 if (pNextInfo != nullptr)
922 pResult = pNextInfo->getNode();
923 else
925 const SwNode * pNextNode = pNodeInfo->getNextNode();
927 if (pNextNode != nullptr)
928 pResult = pNextNode;
932 return pResult;
935 bool WW8TableNodeInfo::operator < (const WW8TableNodeInfo & rInfo) const
937 bool bRet = false;
939 if (rInfo.mpNode != nullptr)
941 if (mpNode == nullptr)
943 bRet = true;
945 else
947 if (mpNode->GetIndex() < rInfo.mpNode->GetIndex())
948 bRet = true;
952 return bRet;
955 bool CellInfo::operator < (const CellInfo & aCellInfo) const
957 bool aRet = false;
959 if (top() < aCellInfo.top())
960 aRet = true;
961 else if (top() == aCellInfo.top())
963 if (left() < aCellInfo.left())
964 aRet = true;
965 else if (left() == aCellInfo.left())
967 if (width() < aCellInfo.width())
968 aRet = true;
969 else if (width() == aCellInfo.width())
971 if (height() < aCellInfo.height())
972 aRet = true;
973 else if (height() == aCellInfo.height())
975 if (aCellInfo.getTableNodeInfo())
977 if (m_pNodeInfo == nullptr)
978 aRet = true;
979 else
981 aRet = *m_pNodeInfo < *aCellInfo.getTableNodeInfo();
989 return aRet;
992 #ifdef DBG_UTIL
993 std::string CellInfo::toString() const
995 static char sBuffer[256];
997 snprintf(sBuffer, sizeof(sBuffer),
998 "<cellinfo left=\"%" SAL_PRIdINT64 "\""
999 " right=\"%" SAL_PRIdINT64 "\""
1000 " top=\"%" SAL_PRIdINT64 "\""
1001 " bottom=\"%" SAL_PRIdINT64 "\""
1002 " node=\"%p\"/>",
1003 sal_Int64(left()),
1004 sal_Int64(right()),
1005 sal_Int64(top()),
1006 sal_Int64(bottom()),
1007 m_pNodeInfo);
1009 return sBuffer;
1011 #endif
1013 WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
1015 WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
1017 #ifdef DBG_UTIL
1018 SAL_INFO( "sw.ww8", pCellGrid->toString());
1019 #endif
1021 pCellGrid->addShadowCells();
1022 return pCellGrid->connectCells(rLastRowEnds);
1025 WW8TableCellGrid::WW8TableCellGrid()
1029 WW8TableCellGrid::~WW8TableCellGrid()
1033 WW8TableCellGridRow::Pointer_t WW8TableCellGrid::getRow(tools::Long nTop, bool bCreate)
1035 WW8TableCellGridRow::Pointer_t pResult;
1037 RowTops_t::iterator aIt = m_aRowTops.find(nTop);
1039 if (aIt == m_aRowTops.end())
1041 if (bCreate)
1043 pResult = std::make_shared<ww8::WW8TableCellGridRow>();
1044 m_aRows[nTop] = pResult;
1045 m_aRowTops.insert(nTop);
1048 else
1049 pResult = m_aRows[nTop];
1051 return pResult;
1054 WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsBegin() const
1056 return m_aRowTops.begin();
1059 WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsEnd() const
1061 return m_aRowTops.end();
1064 CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsBegin(tools::Long nTop)
1066 return getRow(nTop)->begin();
1069 CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsEnd(tools::Long nTop)
1071 return getRow(nTop)->end();
1074 void WW8TableCellGrid::insert(const SwRect & rRect,
1075 WW8TableNodeInfo * pNodeInfo,
1076 const tools::ULong * pFormatFrameWidth)
1078 CellInfo aCellInfo(rRect, pNodeInfo);
1080 if (pFormatFrameWidth != nullptr)
1081 aCellInfo.setFormatFrameWidth(*pFormatFrameWidth);
1083 WW8TableCellGridRow::Pointer_t pRow = getRow(rRect.Top());
1084 pRow->insert(aCellInfo);
1087 void WW8TableCellGrid::addShadowCells()
1089 SAL_INFO( "sw.ww8", "<addShadowCells>" );
1091 RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1093 while (aTopsIt != getRowTopsEnd())
1095 CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1096 CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
1098 RowSpansPtr pRowSpans = std::make_shared<RowSpans>();
1100 bool bBeginningOfCell = true;
1101 bool bVertMerge = false;
1102 SwRect aRect = aCellIt->getRect();
1103 sal_Int32 nRowSpan = 1;
1104 while (aCellIt != aCellEndIt)
1106 WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
1108 if (bBeginningOfCell)
1110 RowTops_t::const_iterator aRowSpanIt(aTopsIt);
1111 ++aRowSpanIt;
1113 if (aRowSpanIt != getRowTopsEnd() &&
1114 *aRowSpanIt < aCellIt->bottom())
1116 aRect.Top(*aRowSpanIt);
1117 tools::ULong nFormatFrameWidth = aCellIt->getFormatFrameWidth();
1118 insert(aRect, nullptr, &nFormatFrameWidth);
1120 bVertMerge = true;
1122 else
1123 bVertMerge = false;
1125 nRowSpan = 1;
1126 while (aRowSpanIt != getRowTopsEnd() &&
1127 *aRowSpanIt < aCellIt->bottom())
1129 ++aRowSpanIt;
1130 nRowSpan++;
1133 if (pNodeInfo)
1134 pRowSpans->push_back(nRowSpan);
1135 else
1136 pRowSpans->push_back(-nRowSpan);
1139 if (pNodeInfo)
1141 pNodeInfo->setVertMerge(bVertMerge);
1144 ++aCellIt;
1145 if (aCellIt != aCellEndIt)
1147 bBeginningOfCell = (aRect.Left() != aCellIt->left());
1148 aRect = aCellIt->getRect();
1152 WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
1153 if (pRow)
1154 pRow->setRowSpans(pRowSpans);
1156 ++aTopsIt;
1158 SAL_INFO( "sw.ww8", "</addShadowCells>" );
1161 WW8TableNodeInfo * WW8TableCellGrid::connectCells(RowEndInners_t &rLastRowEnds)
1163 RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1164 sal_uInt32 nRow = 0;
1165 WW8TableNodeInfo * pLastNodeInfo = nullptr;
1167 while (aTopsIt != getRowTopsEnd())
1169 CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1170 CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
1171 GridColsPtr pWidths = std::make_shared<Widths>();
1172 TableBoxVectorPtr pTableBoxes = std::make_shared<TableBoxVector>();
1174 sal_uInt32 nShadows = 0;
1175 sal_uInt32 nCell = 0;
1176 bool bBeginningOfCell = true;
1177 WW8TableNodeInfo * pEndOfCellInfo = nullptr;
1178 sal_uInt32 nDepthInCell = 0;
1179 while (aCellIt != aCellEndIt)
1181 tools::Long nCellX = aCellIt->left();
1182 WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
1183 if (pNodeInfo)
1185 const SwNode * pNode = pNodeInfo->getNode();
1187 if (pNode->IsStartNode())
1189 nDepthInCell++;
1190 pEndOfCellInfo = nullptr;
1193 if (nDepthInCell == 1 && pNode->IsTextNode())
1194 pEndOfCellInfo = pNodeInfo;
1196 pNodeInfo->setShadowsBefore(nShadows);
1197 pNodeInfo->setCell(nCell);
1198 pNodeInfo->setRow(nRow);
1199 if (pLastNodeInfo)
1201 pLastNodeInfo->setNext(pNodeInfo);
1202 pLastNodeInfo->setNextNode(pNode);
1204 pLastNodeInfo = pNodeInfo;
1205 nShadows = 0;
1207 if (pNode->IsEndNode())
1209 assert(nDepthInCell > 0 && "otherwise overflow");
1210 nDepthInCell--;
1212 if (nDepthInCell == 0 && !pEndOfCellInfo)
1213 pEndOfCellInfo = pNodeInfo;
1216 else
1218 nShadows++;
1221 if (bBeginningOfCell)
1223 pWidths->push_back(aCellIt->getFormatFrameWidth());
1225 if (pNodeInfo)
1226 pTableBoxes->push_back(pNodeInfo->getTableBox());
1227 else
1228 pTableBoxes->push_back(nullptr);
1231 ++aCellIt;
1232 bBeginningOfCell = false;
1234 if (aCellIt != aCellEndIt && aCellIt->left() != nCellX)
1236 nCell++;
1237 bBeginningOfCell = true;
1239 if (pEndOfCellInfo)
1241 pEndOfCellInfo->setEndOfCell(true);
1244 pEndOfCellInfo = nullptr;
1248 pLastNodeInfo->setShadowsAfter(nShadows);
1250 if (!pEndOfCellInfo)
1252 pEndOfCellInfo = pLastNodeInfo;
1255 pEndOfCellInfo->setEndOfCell(true);
1256 pLastNodeInfo->setEndOfLine(true);
1257 updateFinalEndOfLine(rLastRowEnds, pLastNodeInfo);
1259 WW8TableCellGridRow::Pointer_t pRow(getRow(*aTopsIt));
1260 pRow->setTableBoxVector(pTableBoxes);
1261 pRow->setWidths(pWidths);
1263 ++aTopsIt;
1264 nRow++;
1267 return pLastNodeInfo;
1270 #ifdef DBG_UTIL
1271 std::string WW8TableCellGrid::toString()
1273 std::string sResult = "<WW8TableCellGrid>";
1275 RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
1276 static char sBuffer[1024];
1277 while (aTopsIt != getRowTopsEnd())
1279 sResult += "<row y=\"";
1280 sResult += OString::number(*aTopsIt);
1281 sResult += "\">";
1283 CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
1284 CellInfoMultiSet::const_iterator aCellsEnd = getCellsEnd(*aTopsIt);
1286 while (aCellIt != aCellsEnd)
1288 snprintf(sBuffer, sizeof(sBuffer), "<cellInfo top=\"%" SAL_PRIdINT64 "\" bottom=\"%" SAL_PRIdINT64 "\" left=\"%" SAL_PRIdINT64 "\" right=\"%" SAL_PRIdINT64 "\">",
1289 sal_Int64(aCellIt->top()), sal_Int64(aCellIt->bottom()), sal_Int64(aCellIt->left()), sal_Int64(aCellIt->right()));
1290 sResult += sBuffer;
1292 WW8TableNodeInfo * pInfo = aCellIt->getTableNodeInfo();
1293 if (pInfo)
1294 sResult += pInfo->toString();
1295 else
1296 sResult += "<shadow/>\n";
1298 sResult += "</cellInfo>\n";
1299 ++aCellIt;
1302 WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
1303 WidthsPtr pWidths = pRow->getWidths();
1304 if (pWidths != nullptr)
1306 sResult += "<widths>";
1308 Widths::const_iterator aItEnd = pWidths->end();
1309 for (Widths::const_iterator aIt = pWidths->begin();
1310 aIt != aItEnd;
1311 ++aIt)
1313 if (aIt != pWidths->begin())
1314 sResult += ", ";
1316 snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
1317 sResult += sBuffer;
1320 sResult += "</widths>";
1323 RowSpansPtr pRowSpans = pRow->getRowSpans();
1324 if (pRowSpans)
1326 sResult += "<rowspans>";
1328 RowSpans::const_iterator aItEnd = pRowSpans->end();
1329 for (RowSpans::const_iterator aIt = pRowSpans->begin();
1330 aIt != aItEnd;
1331 ++aIt)
1333 if (aIt != pRowSpans->begin())
1334 sResult += ", ";
1336 snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
1337 sResult += sBuffer;
1340 sResult += "</rowspans>";
1343 sResult += "</row>\n";
1344 ++aTopsIt;
1347 sResult += "</WW8TableCellGrid>\n";
1349 return sResult;
1351 #endif
1353 TableBoxVectorPtr WW8TableCellGrid::getTableBoxesOfRow
1354 (WW8TableNodeInfoInner const * pNodeInfoInner)
1356 TableBoxVectorPtr pResult;
1357 WW8TableCellGridRow::Pointer_t pRow =
1358 getRow(pNodeInfoInner->getRect().Top(), false);
1360 if (pRow)
1362 pResult = pRow->getTableBoxVector();
1365 return pResult;
1368 WidthsPtr WW8TableCellGrid::getWidthsOfRow
1369 (WW8TableNodeInfoInner const * pNodeInfoInner)
1371 GridColsPtr pResult;
1373 WW8TableCellGridRow::Pointer_t pRow =
1374 getRow(pNodeInfoInner->getRect().Top(), false);
1376 if (pRow)
1378 pResult = pRow->getWidths();
1381 return pResult;
1384 RowSpansPtr WW8TableCellGrid::getRowSpansOfRow
1385 (WW8TableNodeInfoInner const * pNodeInfoInner)
1387 RowSpansPtr pResult;
1389 WW8TableCellGridRow::Pointer_t pRow =
1390 getRow(pNodeInfoInner->getRect().Top(), false);
1392 if (pRow)
1394 pResult = pRow->getRowSpans();
1397 return pResult;
1400 WW8TableCellGridRow::WW8TableCellGridRow()
1401 : m_pCellInfos(std::make_shared<CellInfoMultiSet>())
1405 WW8TableCellGridRow::~WW8TableCellGridRow()
1409 void WW8TableCellGridRow::insert(const CellInfo & rCellInfo)
1411 m_pCellInfos->insert(rCellInfo);
1413 #ifdef DBG_UTIL
1414 SAL_INFO( "sw.ww8", "<gridRowInsert>" << rCellInfo.toString() << "</gridRowInsert>" );
1415 #endif
1418 CellInfoMultiSet::const_iterator WW8TableCellGridRow::begin() const
1420 return m_pCellInfos->begin();
1423 CellInfoMultiSet::const_iterator WW8TableCellGridRow::end() const
1425 return m_pCellInfos->end();
1428 void WW8TableCellGridRow::setTableBoxVector(TableBoxVectorPtr const & pTableBoxVector)
1430 if (pTableBoxVector->size() > MAXTABLECELLS)
1431 pTableBoxVector->resize(MAXTABLECELLS);
1432 m_pTableBoxVector = pTableBoxVector;
1435 void WW8TableCellGridRow::setWidths(WidthsPtr const & pWidths)
1437 m_pWidths = pWidths;
1440 void WW8TableCellGridRow::setRowSpans(RowSpansPtr const & pRowSpans)
1442 m_pRowSpans = pRowSpans;
1446 CellInfo::CellInfo(const SwRect & aRect, WW8TableNodeInfo * pNodeInfo)
1447 : m_aRect(aRect), m_pNodeInfo(pNodeInfo), m_nFormatFrameWidth(0)
1449 if (pNodeInfo != nullptr)
1451 const SwTableBox * pBox = pNodeInfo->getTableBox();
1452 const SwFrameFormat * pFrameFormat = pBox->GetFrameFormat();
1453 const SwFormatFrameSize & rSize = pFrameFormat->GetFrameSize();
1455 m_nFormatFrameWidth = rSize.GetWidth();
1461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */