/* -*- 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: */