From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- lotuswordpro/source/filter/lwptablelayout.cxx | 1564 +++++++++++++++++++++++++ 1 file changed, 1564 insertions(+) create mode 100644 lotuswordpro/source/filter/lwptablelayout.cxx (limited to 'lotuswordpro/source/filter/lwptablelayout.cxx') diff --git a/lotuswordpro/source/filter/lwptablelayout.cxx b/lotuswordpro/source/filter/lwptablelayout.cxx new file mode 100644 index 000000000..c3d027e91 --- /dev/null +++ b/lotuswordpro/source/filter/lwptablelayout.cxx @@ -0,0 +1,1564 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: IBM Corporation + * + * Copyright: 2008 by IBM Corporation + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ +/** + * @file + * For LWP filter architecture prototype - table layouts + */ + +#include +#include "lwptablelayout.hxx" +#include +#include "lwpholder.hxx" +#include "lwptable.hxx" +#include "lwptblcell.hxx" +#include "lwprowlayout.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lwpframelayout.hxx" +#include +#include +#include +#include + +#include +#include + +LwpSuperTableLayout::LwpSuperTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) + : LwpPlacableLayout(objHdr, pStrm) +{ + m_pFrame.reset(new LwpFrame(this) ); +} + +LwpSuperTableLayout::~LwpSuperTableLayout() +{ +} +/** + * @short Read super table layout record + */ +void LwpSuperTableLayout::Read() +{ + LwpPlacableLayout::Read(); + m_pObjStrm->SkipExtra(); + +} +/** + * @short Get child table layout + * @return pointer to table layout + */ +LwpTableLayout* LwpSuperTableLayout::GetTableLayout() +{ + LwpObjectID *pID = &GetChildTail(); + + o3tl::sorted_vector aSeen; + while (pID && !pID->IsNull()) + { + bool bAlreadySeen = !aSeen.insert(pID).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + + LwpLayout* pLayout = dynamic_cast(pID->obj().get()); + if (!pLayout) + break; + if (pLayout->GetLayoutType() == LWP_TABLE_LAYOUT) + return dynamic_cast(pLayout); + pID = &pLayout->GetPrevious(); + } + + return nullptr; +} + +/** + * @short Get effective heading table layout, the one just before table layout is the only one which is effective + * @return LwpTableHeadingLayout* - pointer to table heading layout + */ +LwpTableHeadingLayout* LwpSuperTableLayout::GetTableHeadingLayout() +{ + LwpObjectID *pID = &GetChildTail(); + + o3tl::sorted_vector aSeen; + while (pID && !pID->IsNull()) + { + bool bAlreadySeen = !aSeen.insert(pID).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + + LwpLayout * pLayout = dynamic_cast(pID->obj().get()); + if (!pLayout) + break; + if (pLayout->GetLayoutType() == LWP_TABLE_HEADING_LAYOUT) + return dynamic_cast(pLayout); + pID = &pLayout->GetPrevious(); + } + + return nullptr; +} + +/** + * @short Register super table layout style + */ +void LwpSuperTableLayout::RegisterNewStyle() +{ + // if this layout is style of real table entry + LwpTableLayout* pTableLayout = GetTableLayout(); + if (pTableLayout != nullptr) + { + pTableLayout->SetFoundry(m_pFoundry); + pTableLayout->RegisterStyle(); + } +} +/** + * @short Judge whether table size is according to content, borrowed from Word Pro code + * @param + * @return sal_Bool + */ +bool LwpSuperTableLayout::IsSizeRightToContent() +{ + /* Only "with paragraph above" tables can size right to content. */ + if (GetRelativeType() == LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE) + return LwpPlacableLayout::IsSizeRightToContent(); + + return false; +} +/** + * @short Judge whether table is justifiable, borrowed from Word Pro code + * @param + * @return sal_Bool + */ +bool LwpSuperTableLayout::IsJustifiable() +{ + return (GetRelativeType() != LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE || IsSizeRightToContent()); +} +/** + * @short Get width of frame outside table + * @param pTableStyle - pointer of XFTableStyle + * @return double - table width + */ +double LwpSuperTableLayout::GetWidth() +{ + double dWidth = GetTableWidth(); + double dLeft = GetMarginsValue(MARGIN_LEFT); + double dRight = GetMarginsValue(MARGIN_RIGHT); + + return (dWidth + dLeft + dRight); +} +/** + * @short Get width of table + * @param pTableStyle - pointer of XFTableStyle + * @return double - table width + */ +double LwpSuperTableLayout::GetTableWidth() +{ + sal_Int32 nWidth = 0; + if(!IsJustifiable() || ((nWidth = LwpMiddleLayout::GetMinimumWidth()) <= 0)) + { + LwpTableLayout* pTableLayout = GetTableLayout(); + if(!pTableLayout) + { + SAL_WARN("lwp", "missing table layout, early return"); + return 0; + } + LwpTable *pTable = pTableLayout->GetTable(); + if(!pTable) + { + SAL_WARN("lwp", "missing table, early return"); + return 0; + } + double dDefaultWidth = pTable->GetWidth(); + sal_uInt16 nCol = pTable->GetColumn(); + + double dWidth = 0; + + for(sal_uInt16 i =0; i< nCol; i++) + { + LwpObjectID *pColumnID = &pTableLayout->GetColumnLayoutHead(); + LwpColumnLayout * pColumnLayout = dynamic_cast(pColumnID->obj().get()); + double dColumnWidth = dDefaultWidth; + o3tl::sorted_vector aSeen; + while (pColumnLayout) + { + bool bAlreadySeen = !aSeen.insert(pColumnLayout).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + if(pColumnLayout->GetColumnID() == i) + { + dColumnWidth = pColumnLayout->GetWidth(); + break; + } + pColumnID = &pColumnLayout->GetNext(); + pColumnLayout = dynamic_cast(pColumnID->obj().get()); + } + dWidth += dColumnWidth; + } + + return dWidth; + } + + double dLeft = GetMarginsValue(MARGIN_LEFT); + double dRight = GetMarginsValue(MARGIN_RIGHT); + return LwpTools::ConvertFromUnitsToMetric(nWidth)-dLeft-dRight; + +} +/** + * @short Apply shadow to table + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyShadow(XFTableStyle *pTableStyle) +{ + // use shadow property of supertable + std::unique_ptr pXFShadow(GetXFShadow()); + if(pXFShadow) + { + pTableStyle->SetShadow(pXFShadow->GetPosition(), pXFShadow->GetOffset(), pXFShadow->GetColor()); + } +} +/** + * @short Apply pattern fill to table style + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyPatternFill(XFTableStyle* pTableStyle) +{ + std::unique_ptr xXFBGImage(GetFillPattern()); + if (xXFBGImage) + { + pTableStyle->SetBackImage(xXFBGImage); + } +} + +/** + * @short Apply background to table style + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyBackGround(XFTableStyle* pTableStyle) +{ + if (IsPatternFill()) + { + ApplyPatternFill(pTableStyle); + } + else + { + ApplyBackColor(pTableStyle); + } +} +/** + * @short Apply back color to table + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyBackColor(XFTableStyle *pTableStyle) +{ + LwpColor* pColor = GetBackColor(); + if(pColor && pColor->IsValidColor()) + { + XFColor aColor(pColor->To24Color()); + pTableStyle->SetBackColor(aColor); + } +} +/** + * @short Apply watermark to table + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyWatermark(XFTableStyle *pTableStyle) +{ + std::unique_ptr xBGImage(GetXFBGImage()); + if (xBGImage) + { + pTableStyle->SetBackImage(xBGImage); + } +} +/** + * @short Apply alignment to table + * @param pTableStyle - pointer of XFTableStyle + * @return + */ +void LwpSuperTableLayout::ApplyAlignment(XFTableStyle * pTableStyle) +{ + LwpPoint aPoint; + if (LwpLayoutGeometry* pGeometry = GetGeometry()) + aPoint = pGeometry->GetOrigin(); + double dXOffset = LwpTools::ConvertFromUnitsToMetric(aPoint.GetX()); + + // add left padding to alignment distance + double dLeft = GetMarginsValue(MARGIN_LEFT); + + pTableStyle->SetAlign(enumXFAlignStart, dXOffset+ dLeft); +} +/** + * @short Add table to container + * @param pCont - pointer of container + * @return pCont + */ +void LwpSuperTableLayout::XFConvert(XFContentContainer* pCont) +{ + if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == GetRelativeType() + && (!GetContainerLayout().is() || !GetContainerLayout()->IsCell()) ) + { + LwpTableLayout * pTableLayout = GetTableLayout(); + if (pTableLayout) + { + pTableLayout->XFConvert(pCont); + } + } + else if(IsRelativeAnchored()) + { + //anchor to paragraph except "with paragraph above" + XFConvertFrame(pCont); + } + else if(m_pFrame) + { + //anchor to page, frame, cell + m_pFrame->XFConvert(pCont); + } +} +/** + * @short convert frame which anchor to page + * @param + * @return + */ +void LwpSuperTableLayout::XFConvertFrame(XFContentContainer* pCont, sal_Int32 nStart, sal_Int32 nEnd, bool bAll) +{ + if(!m_pFrame) + return; + + rtl::Reference xXFFrame; + if(nEnd < nStart) + { + xXFFrame.set(new XFFrame); + } + else + { + xXFFrame.set(new XFFloatFrame(nStart, nEnd, bAll)); + } + + m_pFrame->Parse(xXFFrame.get(), static_cast(nStart)); + //parse table, and add table to frame + LwpTableLayout * pTableLayout = GetTableLayout(); + if (pTableLayout) + { + pTableLayout->XFConvert(xXFFrame.get()); + } + //add frame to the container + pCont->Add(xXFFrame.get()); + +} +/** + * @short register frame style + * @param + * @return + */ +void LwpSuperTableLayout::RegisterFrameStyle() +{ + std::unique_ptr xFrameStyle(new XFFrameStyle); + m_pFrame->RegisterStyle(xFrameStyle); +} + +LwpTableLayout::LwpTableLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) + : LwpLayout(objHdr, pStrm) + , m_nRows(0) + , m_nCols(0) + , m_pDefaultCellLayout(nullptr) + , m_bConverted(false) +{ +} + +/** + * @short Get neighbour cell by specifying ROW+COL + * @param nRow + * @param nCol + * @return LwpCellLayout * + */ +LwpCellLayout * LwpTableLayout::GetCellByRowCol(sal_uInt16 nRow, sal_uInt16 nCol) +{ + if (nRow >= m_nRows || nCol >= m_nCols) + return nullptr; + + return m_WordProCellsMap[static_cast(nRow)*m_nCols + nCol]; +} + +/** + * @short traverse all table cells + * @param + * @param + * @param + */ +void LwpTableLayout::TraverseTable() +{ + sal_uInt32 nCount = m_nRows*m_nCols; + + // new cell map nRow*nCOl and initialize + m_WordProCellsMap.insert(m_WordProCellsMap.end(), nCount, m_pDefaultCellLayout); + + // set value + LwpObjectID* pRowID = &GetChildHead(); + LwpRowLayout * pRowLayout = dynamic_cast(pRowID->obj().get()); + o3tl::sorted_vector aSeen; + while (pRowLayout) + { + bool bAlreadySeen = !aSeen.insert(pRowLayout).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + + pRowLayout->SetRowMap(); + + // for 's analysis job + m_RowsMap[pRowLayout->GetRowID()] = pRowLayout; + pRowLayout->CollectMergeInfo(); + // end for 's analysis + + pRowID = &pRowLayout->GetNext(); + pRowLayout = dynamic_cast(pRowID->obj().get()); + } +} + +/** + * @short search the cell map + * @param nRow - row id (0 based) + * @param nRow - row id (0 based) + * @return LwpObjectID * - pointer to cell story object ID + */ +LwpObjectID * LwpTableLayout::SearchCellStoryMap(sal_uInt16 nRow, sal_uInt16 nCol) +{ + if (nRow >= m_nRows || nCol >= m_nCols ) + { + return nullptr; + } + + LwpCellLayout * pCell = GetCellByRowCol(nRow, nCol); + if (pCell) + { + // maybe connected cell layout + // maybe default cell layout + if (nRow != pCell->GetRowID() || nCol != pCell->GetColID()) + { + return nullptr; + } + return &pCell->GetContent(); + } + + return nullptr; +} + +/** + * @short Get parent super table layout of table layout + * @return LwpSuperTableLayout * - pointer of parent super table layout + */ +LwpSuperTableLayout * LwpTableLayout::GetSuperTableLayout() +{ + return dynamic_cast(GetParent().obj().get()); +} +/** + * @short Get table pointer + * @return LwpTable * - content table pointer + */ +LwpTable * LwpTableLayout::GetTable() +{ + return dynamic_cast(m_Content.obj().get()); +} +/** + * @short Get column style name by column ID + * @param sal_uInt16 -- col id(0 based) + * @return OUString - name of column style + */ +OUString LwpTableLayout::GetColumnWidth(sal_uInt16 nCol) +{ + if (nCol >= m_nCols) + { + assert(false); + return m_DefaultColumnStyleName; + } + + LwpColumnLayout * pCol = m_aColumns[nCol]; + if (pCol) + { + return pCol->GetStyleName(); + } + + return m_DefaultColumnStyleName; +} +/** + * @short analyze all columns to get whole table width and width of all columns + * @short and register all column styles + * @param none + */ +void LwpTableLayout::RegisterColumns() +{ + LwpTable* pTable = GetTable(); + if (!pTable) + throw std::range_error("corrupt LwpTableLayout"); + + LwpSuperTableLayout* pSuper = GetSuperTableLayout(); + if (!pSuper) + throw std::range_error("corrupt LwpTableLayout"); + + sal_uInt16 nCols = m_nCols; + + m_aColumns.resize(nCols); + std::unique_ptr pWidthCalculated( new bool[nCols] ); + for(sal_uInt16 i=0;iGetWidth(); + sal_uInt16 nJustifiableColumn = nCols; + + double dTableWidth = pSuper->GetTableWidth(); + + // Get total width of justifiable columns + // NOTICE: all default columns are regarded as justifiable columns + LwpObjectID* pColumnID = &GetColumnLayoutHead(); + LwpColumnLayout * pColumnLayout = dynamic_cast(pColumnID->obj().get()); + o3tl::sorted_vector aSeen; + while (pColumnLayout) + { + bool bAlreadySeen = !aSeen.insert(pColumnLayout).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + + auto nColId = pColumnLayout->GetColumnID(); + if (nColId >= nCols) + { + throw std::range_error("corrupt LwpTableLayout"); + } + m_aColumns[nColId] = pColumnLayout; + if (!pColumnLayout->IsJustifiable()) + { + pWidthCalculated[nColId] = true; + dTableWidth -= pColumnLayout->GetWidth(); + nJustifiableColumn --; + } + + pColumnID = &pColumnLayout->GetNext(); + pColumnLayout = dynamic_cast(pColumnID->obj().get()); + } + + // if all columns are not justifiable, the rightmost column will be changed to justifiable + if (nJustifiableColumn == 0 && nCols != 0) + { + nJustifiableColumn ++; + if (m_aColumns[nCols - 1]) + { + pWidthCalculated[nCols-1] = false; + dTableWidth += m_aColumns[nCols-1]->GetWidth(); + } + else + { + // this can't happen + dTableWidth = dDefaultColumn; + assert(false); + } + } + + // justifiable columns will share the remain width averagely + dDefaultColumn = nJustifiableColumn ? dTableWidth/nJustifiableColumn : 0; + + // register default column style + std::unique_ptr xColStyle(new XFColStyle); + xColStyle->SetWidth(static_cast(dDefaultColumn)); + + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + m_DefaultColumnStyleName = pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName(); + + // register existed column style + sal_uInt16 i=0; + for( i=0;iSetFoundry(m_pFoundry); + if(!pWidthCalculated[i]) + { + // justifiable ----register style with calculated value + m_aColumns[i]->SetStyleName(m_DefaultColumnStyleName); + } + else + { + // not justifiable ---- register style with original value + m_aColumns[i]->RegisterStyle(m_aColumns[i]->GetWidth()); + } + } + } +} +/** + * @short register all row styles + * @param none + */ +void LwpTableLayout::RegisterRows() +{ + LwpTable * pTable = GetTable(); + if (pTable == nullptr) + { + assert(false); + return; + } + + // register default row style + std::unique_ptr xRowStyle(new XFRowStyle); + if (m_nDirection & 0x0030) + { + xRowStyle->SetMinRowHeight(static_cast(pTable->GetHeight())); + } + else + { + xRowStyle->SetRowHeight(static_cast(pTable->GetHeight())); + } + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + m_DefaultRowStyleName = pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName(); + + // register style of rows + LwpObjectID * pRowID = &GetChildHead(); + LwpRowLayout * pRowLayout = dynamic_cast(pRowID->obj().get()); + while (pRowLayout) + { + pRowLayout->SetFoundry(m_pFoundry); + pRowLayout->RegisterStyle(); + + pRowID = &pRowLayout->GetNext(); + pRowLayout = dynamic_cast(pRowID->obj().get()); + } +} +/** + * @short register table style, if needed, including frame style + * @param none + */ +void LwpTableLayout::RegisterStyle() +{ + // get super table layout + LwpSuperTableLayout * pSuper = GetSuperTableLayout(); + if (!pSuper) + return; + + // get table + LwpTable * pTable = GetTable(); + if (pTable == nullptr) + { + SAL_WARN("lwp", "missing table, early return"); + return; + } + + // get row/column number of this table + m_nRows = pTable->GetRow(); + m_nCols = pTable->GetColumn(); + //http://www.danielsays.com/ss-gallery-win1x2x3x-lotus-word-pro-96.html + //tables with up to 255 rows and 8192 columns + //the row limit tallies with the casting of m_nCols to an unsigned char + //elsewhere + if (m_nRows > MAX_NUM_ROWS) + throw std::runtime_error("max legal row exceeded"); + if (m_nCols > MAX_NUM_COLS) + throw std::runtime_error("max legal column exceeded"); + + // get default cell layout of current table + LwpObjectID& rID= pTable->GetDefaultCellStyle(); + m_pDefaultCellLayout = dynamic_cast(rID.obj().get()); + + // register columns styles + RegisterColumns(); + + // register style of whole table + std::unique_ptr xTableStyle(new XFTableStyle); + + sal_uInt8 nType = pSuper->GetRelativeType(); + // If the table is not "with paragraph above" placement, create an frame style + // by supertable layout + if ( LwpLayoutRelativityGuts::LAY_INLINE_NEWLINE == nType + && (!pSuper->GetContainerLayout().is() || !pSuper->GetContainerLayout()->IsCell()) ) + { + //with para above + pSuper->ApplyBackGround(xTableStyle.get()); + pSuper->ApplyWatermark(xTableStyle.get()); + pSuper->ApplyShadow(xTableStyle.get()); + pSuper->ApplyAlignment(xTableStyle.get()); + xTableStyle->SetWidth(pSuper->GetTableWidth()); + } + else + { + pSuper->RegisterFrameStyle(); + xTableStyle->SetAlign(enumXFAlignCenter); + xTableStyle->SetWidth(pSuper->GetTableWidth()); + } + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + m_StyleName = pXFStyleManager->AddStyle(std::move(xTableStyle)).m_pStyle->GetStyleName(); + + //convert to OO table now and register row style traverse + TraverseTable(); + + SplitConflictCells(); + + // Register rows layouts, it must be after SplitConflictCells + RegisterRows(); + + // Parse table + ParseTable(); + + // the old code doesn't check if the LwpFoundry pointer is NULL, + // so the NULL pointer cause sodc freeze. Add code to check the pointer. + if (GetFoundry()) + PutCellVals(GetFoundry(), pTable->GetObjectID()); +} +/** + * @short read table layout + * @param none + */ +void LwpTableLayout::ParseTable() +{ + // get super table layout + LwpSuperTableLayout* pSuper = GetSuperTableLayout(); + if (!pSuper) + { + throw std::runtime_error("missing super table"); + } + + if (m_pXFTable) + { + throw std::runtime_error("this table is already parsed"); + } + + // set name of object + m_pXFTable.set(new XFTable); + + m_pXFTable->SetTableName(pSuper->GetName().str()); + // set table style + m_pXFTable->SetStyleName(m_StyleName); + + sal_uInt16 nRow = m_nRows; + sal_uInt8 nCol = static_cast(m_nCols); + + //process header rows + LwpTableHeadingLayout* pTableHeading; + pTableHeading = pSuper->GetTableHeadingLayout(); + if (pTableHeading) + { + sal_uInt16 nStartHeadRow; + sal_uInt16 nEndHeadRow; + pTableHeading->GetStartEndRow(nStartHeadRow,nEndHeadRow); + if (nStartHeadRow != 0) + ConvertTable(m_pXFTable,0,nRow,0,nCol); + else + { + sal_uInt16 nContentRow = ConvertHeadingRow(m_pXFTable,nStartHeadRow,nEndHeadRow+1); + ConvertTable(m_pXFTable,nContentRow,nRow,0,nCol); + } + } + else + ConvertTable(m_pXFTable,0,nRow,0,nCol); +} + +/** + * @short read table layout + * @param none + */ +void LwpTableLayout::Read() +{ + LwpLayout::Read(); + + // before layout hierarchy rework! + if(LwpFileHeader::m_nFileRevision < 0x000b) + { + assert(false); + } + m_ColumnLayout.ReadIndexed(m_pObjStrm.get()); + + m_pObjStrm->SkipExtra(); +} + +/** + * @short Convert table + * @param + * @return pCont - container which will contain table + */ +void LwpTableLayout::XFConvert(XFContentContainer* pCont) +{ + if (!m_pXFTable) + return; + if (m_bConverted) + throw std::runtime_error("already added to a container"); + pCont->Add(m_pXFTable.get()); + m_bConverted = true; +} + +/** + * @short convert heading row + * @param pXFTable - pointer of table + * @param nStartRow - start heading row ID + * @param nEndRow - end heading row ID + */ +sal_uInt16 LwpTableLayout::ConvertHeadingRow( + rtl::Reference const & pXFTable, sal_uInt16 nStartHeadRow, sal_uInt16 nEndHeadRow) +{ + sal_uInt16 nContentRow; + LwpTable* pTable = GetTable(); + assert(pTable); + sal_uInt8 nCol = static_cast(pTable->GetColumn()); + rtl::Reference pTmpTable( new XFTable ); + + ConvertTable(pTmpTable,nStartHeadRow,nEndHeadRow,0,nCol); + + sal_uInt16 nRowNum = pTmpTable->GetRowCount(); + std::vector CellMark(nRowNum); + + if (nRowNum == 1) + { + XFRow* pXFRow = pTmpTable->GetRow(1); + pXFTable->AddHeaderRow(pXFRow); + pTmpTable->RemoveRow(1); + nContentRow = nEndHeadRow; + } + else + { + sal_uInt8 nFirstColSpann = 1; + const bool bFindFlag = FindSplitColMark(pTmpTable.get(), CellMark, nFirstColSpann); + + if (bFindFlag)//split to 2 cells + { + SplitRowToCells(pTmpTable.get(), pXFTable, nFirstColSpann, CellMark.data()); + nContentRow = nEndHeadRow; + } + else//can not split,the first row will be the heading row,the rest will be content row + { + XFRow* pXFRow = pTmpTable->GetRow(1); + pXFTable->AddHeaderRow(pXFRow); + pTmpTable->RemoveRow(1); + auto iter = m_RowsMap.find(0); + if (iter == m_RowsMap.end()) + { + SAL_WARN("lwp", "row 0 is unknown"); + nContentRow = 0; + } + else + nContentRow = iter->second->GetCurMaxSpannedRows(0,nCol); + } + } + return nContentRow; +} + +void LwpTableLayout::SplitRowToCells(XFTable* pTmpTable, rtl::Reference const & pXFTable, + sal_uInt8 nFirstColSpann,const sal_uInt8* pCellMark) +{ + sal_uInt16 i; + sal_uInt16 nRowNum = pTmpTable->GetRowCount(); + LwpTable* pTable = GetTable(); + assert(pTable); + sal_uInt8 nCol = static_cast(pTable->GetColumn()); + + rtl::Reference xXFRow(new XFRow); + + //register style for heading row + double fHeight = 0; + OUString styleName; + std::unique_ptr xRowStyle(new XFRowStyle); + XFRow* pRow = pTmpTable->GetRow(1); + if (!pRow) + throw std::runtime_error("missing row"); + styleName = pRow->GetStyleName(); + + // get settings of the row and assign them to new row style + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + XFRowStyle *pTempRowStyle = static_cast(pXFStyleManager->FindStyle(styleName)); + if (pTempRowStyle) + *xRowStyle = *pTempRowStyle; + + for (i=1;i<=nRowNum;i++) + { + styleName = pTmpTable->GetRow(i)->GetStyleName(); + fHeight+=static_cast(pXFStyleManager->FindStyle(styleName))->GetRowHeight(); + } + if (m_nDirection & 0x0030) + { + xRowStyle->SetMinRowHeight(static_cast(fHeight)); + } + else + { + xRowStyle->SetRowHeight(static_cast(fHeight)); + } + xXFRow->SetStyleName(pXFStyleManager->AddStyle(std::move(xRowStyle)).m_pStyle->GetStyleName()); + + //construct heading row + rtl::Reference xXFCell1(new XFCell); + rtl::Reference xXFCell2(new XFCell); + rtl::Reference xSubTable1(new XFTable); + rtl::Reference xSubTable2(new XFTable); + rtl::Reference xNewCell; + + for (i=1;i<=nRowNum;i++) + { + XFRow* pOldRow = pTmpTable->GetRow(i); + rtl::Reference xNewRow(new XFRow); + xNewRow->SetStyleName(pOldRow->GetStyleName()); + for (sal_uInt8 j=1;j<=pCellMark[i];j++) + { + xNewCell = pOldRow->GetCell(j); + xNewRow->AddCell(xNewCell); + } + xSubTable1->AddRow(xNewRow); + } + ConvertColumn(xSubTable1, 0, nFirstColSpann);//add column info + + xXFCell1->Add(xSubTable1.get()); + xXFCell1->SetColumnSpaned(nFirstColSpann); + xXFRow->AddCell(xXFCell1); + + for (i=1;i<=nRowNum;i++) + { + XFRow* pOldRow = pTmpTable->GetRow(i); + rtl::Reference xNewRow(new XFRow); + xNewRow->SetStyleName(pOldRow->GetStyleName()); + for(sal_Int32 j=pCellMark[i]+1;j<=pOldRow->GetCellCount();j++) + { + xNewCell = pOldRow->GetCell(j); + xNewRow->AddCell(xNewCell); + } + xSubTable2->AddRow(xNewRow); + + } + ConvertColumn(xSubTable2, nFirstColSpann, nCol);//add column info + xXFCell2->Add(xSubTable2.get()); + xXFCell2->SetColumnSpaned(nCol-nFirstColSpann); + xXFRow->AddCell(xXFCell2); + + pXFTable->AddHeaderRow(xXFRow.get()); + + //remove tmp table + for (i=1;i<=nRowNum;i++) + { + pTmpTable->RemoveRow(i); + } +} + +/** + * @short find if the heading rows can be split to 2 cells + * @param pXFTable - pointer of tmp XFtable + * @param CellMark - pointer of cell mark array + */ +bool LwpTableLayout::FindSplitColMark(XFTable* pXFTable, std::vector& rCellMark, + sal_uInt8& nMaxColSpan) +{ + sal_uInt16 nRowNum = pXFTable->GetRowCount(); + sal_uInt8 nColNum = static_cast(pXFTable->GetColumnCount()); + sal_uInt8 nCount; + sal_uInt8 nColSpan; + bool bFindFlag = false; + XFRow* pTmpRow; + + for(sal_uInt8 i=1;i<=nColNum;i++) + { + sal_uInt16 nRowLoop; + + //find current max column span + nMaxColSpan = 1; + for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++) + { + nColSpan = 0; + for(sal_uInt8 nCellLoop=1; nCellLoopGetRow(nRowLoop); + XFCell* pCell = pTmpRow->GetCell(nCellLoop); + if (pCell) + nColSpan += static_cast(pCell->GetColSpaned()); + else + return false; + } + if (nColSpan > nMaxColSpan) + nMaxColSpan = nColSpan; + rCellMark.at(nRowLoop) = 0;//reset all cell mark to zero + } + + //find if other row has the same column + for (nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++) + { + pTmpRow = pXFTable->GetRow(nRowLoop); + nCount = 0; + sal_Int32 nCellMark = 0; + for (sal_Int32 nCellLoop=1; nCellLoop<=pTmpRow->GetCellCount(); nCellLoop++) + { + if (nCount>nMaxColSpan) + break; + nCount+= static_cast(pTmpRow->GetCell(nCellLoop)->GetColSpaned()); + if (nCount == nMaxColSpan) + { + nCellMark = nCellLoop; + break; + } + } + if (nCellMark == 0) + break; + else + rCellMark.at(nRowLoop) = nCellMark; + } + for(nRowLoop=1;nRowLoop<=nRowNum;nRowLoop++)//check if all ==0,break + { + if (rCellMark.at(nRowLoop) == 0) + break; + } + if (nRowLoop == nRowNum+1) + { + bFindFlag = true; + return bFindFlag; + } + + } + return bFindFlag; +} + +static bool operator==(const TableConvertAttempt& a, const TableConvertAttempt& b) +{ + return a.mnStartRow == b.mnStartRow && + a.mnEndRow == b.mnEndRow && + a.mnStartCol== b.mnStartCol && + a.mnEndCol == b.mnEndCol; +} + +/** + * @short convert word pro table to SODC table + * @param pXFTable - pointer of table + * @param nStartRow - start row ID + * @param nEndRow - end row ID + * @param nStartCol - start column ID + * @param nEndCol - end column ID + */ +void LwpTableLayout::ConvertTable(rtl::Reference const & pXFTable, sal_uInt16 nStartRow, + sal_uInt16 nEndRow,sal_uInt8 nStartCol,sal_uInt8 nEndCol) +{ + TableConvertAttempt aConversionAttempt(nStartRow, nEndRow, nStartCol, nEndCol); + auto itr = std::find(m_aConvertingStack.begin(), m_aConvertingStack.end(), aConversionAttempt); + if (itr != m_aConvertingStack.end()) + { + SAL_WARN("lwp", "already trying to convert this range"); + return; + } + + m_aConvertingStack.push_back(aConversionAttempt); + + //out put column info TO BE CHANGED + ConvertColumn(pXFTable,nStartCol,nEndCol); + + std::map::iterator iter; + + for (sal_uInt16 i=nStartRow; isecond; + if (pRow->GetCurMaxSpannedRows(nStartCol,nEndCol) == 1) + { + pRow->ConvertCommonRow(pXFTable,nStartCol,nEndCol); + i++; + } + else + { + pRow->ConvertRow(pXFTable,nStartCol,nEndCol); + i += pRow->GetCurMaxSpannedRows(nStartCol,nEndCol); + } + } + } + + m_aConvertingStack.pop_back(); +} + +/** + * @short apply numeric value and formula to cell + * @param pFoundry - pointer of foundry + * @param aTableID - table ID + */ +void LwpTableLayout::PutCellVals(LwpFoundry* pFoundry, LwpObjectID aTableID) +{ + + // The old code doesn't check if the LwpFoundry pointer is NULL, so the NULL + // pointer cause sodc frozen. Add code to check the pointer. + if( !pFoundry ) return; + + try{ + + LwpDLVListHeadHolder* pHolder = dynamic_cast(pFoundry->GetNumberManager().GetTableRangeID().obj().get()); + + LwpTableRange* pTableRange = pHolder ? dynamic_cast(pHolder->GetHeadID().obj().get()) : nullptr; + + //Look up the table + o3tl::sorted_vector aTableSeen; + while (pTableRange) + { + bool bAlreadySeenTable = !aTableSeen.insert(pTableRange).second; + if (bAlreadySeenTable) + throw std::runtime_error("loop in conversion"); + LwpObjectID aID = pTableRange->GetTableID(); + if (aID == aTableID) + { + break; + } + pTableRange = pTableRange->GetNext(); + } + + if (!pTableRange) + return; + + LwpCellRange* pRange = dynamic_cast(pTableRange->GetCellRangeID().obj().get()); + if (!pRange) + return; + + LwpFolder* pFolder = dynamic_cast(pRange->GetFolderID().obj().get()); + if (!pFolder) + return; + + LwpObjectID aRowListID = pFolder->GetChildHeadID(); + LwpRowList* pRowList = dynamic_cast(aRowListID.obj().get()); + + //loop the rowlist + o3tl::sorted_vector aOuterSeen; + while (pRowList) + { + bool bAlreadySeenOuter = !aOuterSeen.insert(pRowList).second; + if (bAlreadySeenOuter) + throw std::runtime_error("loop in conversion"); + sal_uInt16 nRowID = pRowList->GetRowID(); + { + LwpCellList* pCellList = dynamic_cast(pRowList->GetChildHeadID().obj().get()); + //loop the cellList + o3tl::sorted_vector aSeen; + while (pCellList) + { + bool bAlreadySeen = !aSeen.insert(pCellList).second; + if (bAlreadySeen) + throw std::runtime_error("loop in conversion"); + + {//put cell + sal_uInt16 nColID = pCellList->GetColumnID(); + + XFCell* pCell = GetCellsMap(nRowID,static_cast(nColID)); + if (!pCell) + { + throw std::runtime_error("Hidden cell would not be in cellsmap"); + } + + pCellList->Convert(pCell, this); + + //process paragraph + PostProcessParagraph(pCell, nRowID, nColID); + + } + pCellList = dynamic_cast(pCellList->GetNextID().obj().get()); + } + } + pRowList = dynamic_cast(pRowList->GetNextID().obj().get()); + } + + }catch (...) { + SAL_WARN("lwp", "bad PutCellVals"); + } +} + +/** + * @short 1. set number right alignment to right if number 2. remove tab added before if number + * @param pCell - cell which to be process + * @param nRowID - row number in Word Pro file + * @param nColID - column number in Word Pro file + */ +void LwpTableLayout::PostProcessParagraph(XFCell *pCell, sal_uInt16 nRowID, sal_uInt16 nColID) +{ + // if number right, set alignment to right + LwpCellLayout * pCellLayout = GetCellByRowCol(nRowID, nColID); + if(!pCellLayout) + return; + + rtl::Reference first( + pCell->FindFirstContent(enumXFContentPara)); + XFParagraph * pXFPara = static_cast(first.get()); + if (!pXFPara) + return; + XFColor aNullColor; + + OUString sNumfmt = pCellLayout->GetNumfmtName(); + bool bColorMod = false; + XFNumberStyle* pNumStyle = nullptr; + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + if (!sNumfmt.isEmpty()) + { + pNumStyle = static_cast(pXFStyleManager->FindStyle(sNumfmt)); + XFColor aColor = pNumStyle->GetColor(); + if ( aColor != aNullColor ) + bColorMod = true;//end + } + + XFParaStyle * pStyle = pXFStyleManager->FindParaStyle(pXFPara->GetStyleName()); + if (!((pStyle && pStyle->GetNumberRight()) || bColorMod)) + return; + + std::unique_ptr xOverStyle(new XFParaStyle); + + if (pStyle) + { + *xOverStyle = *pStyle; + + if (pStyle->GetNumberRight()) + xOverStyle->SetAlignType(enumXFAlignEnd); + } + + if (bColorMod) + { + rtl::Reference xFont = xOverStyle->GetFont(); + if (xFont.is()) + { + XFColor aColor = xFont->GetColor(); + if (aColor == aNullColor) + { + rtl::Reference pNewFont(new XFFont); + aColor = pNumStyle->GetColor(); + pNewFont->SetColor(aColor); + xOverStyle->SetFont(pNewFont); + } + } + } + + xOverStyle->SetStyleName(""); + OUString StyleName + = pXFStyleManager->AddStyle(std::move(xOverStyle)).m_pStyle->GetStyleName(); + + pXFPara->SetStyleName(StyleName); +} + +/** + * @short Parse all cols of table + * @param pXFTable - pointer to created XFTable + */ +void LwpTableLayout::ConvertColumn(rtl::Reference const & pXFTable, sal_uInt8 nStartCol, sal_uInt8 nEndCol) +{ + LwpTable * pTable = GetTable(); + if (!pTable) + { + assert(false); + return; + } + + for (sal_uInt32 iLoop = 0; iLoop < static_cast(nEndCol)-nStartCol; ++iLoop) + { + // add row to table + LwpObjectID *pColID = &GetColumnLayoutHead(); + LwpColumnLayout * pColumnLayout = dynamic_cast(pColID->obj().get()); + while (pColumnLayout) + { + if (pColumnLayout->GetColumnID() == (iLoop+nStartCol)) + { + pXFTable->SetColumnStyle(iLoop+1, pColumnLayout->GetStyleName()); + break; + } + pColID = &pColumnLayout->GetNext(); + pColumnLayout = dynamic_cast(pColID->obj().get()); + } + if (!pColumnLayout) + { + pXFTable->SetColumnStyle(iLoop+1, m_DefaultColumnStyleName); + } + } +} +/** + * @short split conflict merged cells + */ +void LwpTableLayout::SplitConflictCells() +{ + LwpTable * pTable = GetTable(); + if (!pTable) + return; + sal_uInt16 nCol = pTable->GetColumn(); + sal_uInt16 nRow = pTable->GetRow(); + + sal_uInt16 nEffectRows; + std::map::iterator iter1; + std::map::iterator iter2; + LwpRowLayout* pRowLayout; + LwpRowLayout* pEffectRow; + + for (sal_uInt16 i=0; isecond; + if (!pRowLayout->GetMergeCellFlag()) + { + i++; + continue; + } + else + { + nEffectRows = i + pRowLayout->GetCurMaxSpannedRows(0,static_cast(nCol)); + + for (sal_uInt16 j = i+1; jsecond; + if (!pEffectRow->GetMergeCellFlag()) + continue; + else + pEffectRow->SetCellSplit(nEffectRows); + } + i = nEffectRows; + } + }//end for + +} +/** + * @short add default row which are missing in the file + * @param pXFTable - pointer to new created table + * @param nStartCol - starting column + * @param nEndCol - end column + * @return pXFTable + */ +void LwpTableLayout::ConvertDefaultRow(rtl::Reference const & pXFTable, sal_uInt8 nStartCol, + sal_uInt8 nEndCol, sal_uInt16 nRowID) +{ + // current row doesn't exist in the file + rtl::Reference xRow(new XFRow); + xRow->SetStyleName(m_DefaultRowStyleName); + + for (sal_uInt16 j =0;j < nEndCol-nStartCol; j++) + { + // if table has default cell layout, use it to ConvertCell + // otherwise use blank cell + rtl::Reference xCell; + if (m_pDefaultCellLayout) + { + LwpTable* pTable = GetTable(); + assert(pTable); + xCell = m_pDefaultCellLayout->DoConvertCell( + pTable->GetObjectID(),nRowID,j+nStartCol); + } + else + { + xCell.set(new XFCell); + } + xRow->AddCell(xCell); + } + + pXFTable->AddRow(xRow); +} + +/** + * @short set cell map info + * @param pXFCell - pointer to xfcell + * @param nRow - row id + * @param nCol - column id + */ +void LwpTableLayout::SetCellsMap(sal_uInt16 nRow1, sal_uInt8 nCol1, + sal_uInt16 nRow2, sal_uInt8 nCol2, XFCell* pXFCell) +{ + m_CellsMap.insert({{nRow1, nCol1}, {nRow2, nCol2}}, pXFCell); +} + +/** + * @short get cell map info + * @param nRow - row id + * @param nCol - column id + * @return pXFCell + */ +XFCell* LwpTableLayout::GetCellsMap(sal_uInt16 nRow, sal_uInt8 nCol) +{ + auto results = m_CellsMap.search({{nRow, nCol}, {nRow, nCol}}, rt_type::search_type::overlap); + if (results.begin() == results.end()) + return nullptr; + // return the last thing inserted for this position + return std::prev(results.end())->GetCell(); +} +/** + * @descr Get row layout by row id + * @param nRow - row id + */ +LwpRowLayout* LwpTableLayout::GetRowLayout(sal_uInt16 nRow) +{ + LwpObjectID *pRowID = &GetChildHead(); + LwpRowLayout * pRowLayout = dynamic_cast(pRowID->obj().get()); + while (pRowLayout) + { + if(pRowLayout->GetRowID() == nRow) + return pRowLayout; + + pRowID = &pRowLayout->GetNext(); + pRowLayout = dynamic_cast(pRowID->obj().get()); + } + return nullptr; +} + +//add end by +LwpColumnLayout::LwpColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) + : LwpVirtualLayout(objHdr, pStrm) + , ccolid(0) + , cwidth(0) +{} + +LwpColumnLayout::~LwpColumnLayout() +{} +void LwpColumnLayout::Read() +{ + LwpObjectStream* pStrm = m_pObjStrm.get(); + + LwpVirtualLayout::Read(); + + sal_uInt16 colid; + + colid = pStrm->QuickReaduInt16(); // forced to lushort + ccolid = static_cast(colid); + cwidth = pStrm->QuickReadInt32(); + + pStrm->SkipExtra(); +} + +void LwpColumnLayout::RegisterStyle(double dCalculatedWidth) +{ + std::unique_ptr xColStyle(new XFColStyle); + xColStyle->SetWidth(static_cast(dCalculatedWidth)); + XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); + m_StyleName = pXFStyleManager->AddStyle(std::move(xColStyle)).m_pStyle->GetStyleName(); +} + +LwpTableHeadingLayout::LwpTableHeadingLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) + : LwpTableLayout(objHdr, pStrm) + , cStartRow(0) + , cEndRow(0) +{} + +LwpTableHeadingLayout::~LwpTableHeadingLayout() +{} +/** + * @short read table heading layout + * @param + * @return + */ +void LwpTableHeadingLayout::Read() +{ + LwpTableLayout::Read(); + + cStartRow = m_pObjStrm->QuickReaduInt16(); + cEndRow = m_pObjStrm->QuickReaduInt16(); + + m_pObjStrm->SkipExtra(); + +} +/** + * @short get start and end row number of table heading + * @param + * @return *pStartRow - starting row number + * @return *pEndRow - end row number + */ +void LwpTableHeadingLayout::GetStartEndRow(sal_uInt16& nStartRow, sal_uInt16& nEndRow) +{ + nStartRow = cStartRow; + nEndRow = cEndRow; +} + +LwpSuperParallelColumnLayout::LwpSuperParallelColumnLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm) +{ +} +LwpSuperParallelColumnLayout::~LwpSuperParallelColumnLayout() +{} + +void LwpSuperParallelColumnLayout::Read() +{ + LwpSuperTableLayout::Read(); + m_pObjStrm->SkipExtra(); + +} + +LwpSuperGlossaryLayout::LwpSuperGlossaryLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpSuperTableLayout(objHdr, pStrm) +{ +} + +LwpSuperGlossaryLayout::~LwpSuperGlossaryLayout() +{ +} + +void LwpSuperGlossaryLayout::Read() +{ + LwpSuperTableLayout::Read(); + m_pObjStrm->SkipExtra(); +} + +LwpParallelColumnsLayout::LwpParallelColumnsLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpTableLayout(objHdr, pStrm) +{ +} + +LwpParallelColumnsLayout::~LwpParallelColumnsLayout() +{ +} + +void LwpParallelColumnsLayout::Read() +{ + LwpTableLayout::Read(); + m_pObjStrm->SkipExtra(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3