/* -*- 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 - cell layouts */ #include #include "lwpcelllayout.hxx" #include "lwpnumericfmt.hxx" #include "lwptable.hxx" #include "lwprowlayout.hxx" #include #include #include #include #include #include #include #include LwpCellLayout::LwpCellLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) : LwpMiddleLayout(objHdr, pStrm) , m_bConvertCell(false) , crowid(0) , ccolid(0) , cType(LDT_NONE) { } LwpCellLayout::~LwpCellLayout() {} /** * @short Get table layout pointer, if default cell layout, return NULL * @param LwpTableLayout * * @return */ LwpTableLayout * LwpCellLayout::GetTableLayout() { LwpRowLayout * pRow = dynamic_cast(GetParent().obj().get()); if(!pRow) { return nullptr; } LwpTableLayout * pTableLayout = pRow->GetParentTableLayout(); return pTableLayout; } /** * @short Get table pointer, if default cell layout, return NULL * @param LwpTable * * @return */ LwpTable * LwpCellLayout::GetTable() { LwpTableLayout * pTableLayout = GetTableLayout(); if(!pTableLayout) { return nullptr; } LwpTable *pTable = pTableLayout->GetTable(); return pTable; } /** * @short Set current cell layout to cell layout map * @param * @return */ void LwpCellLayout::SetCellMap() { LwpTableLayout * pTableLayout = GetTableLayout(); if (pTableLayout) pTableLayout->SetWordProCellMap(crowid, ccolid, this); } /** * @short Get actual width of this cell layout * @param * @return width (cm) */ double LwpCellLayout::GetActualWidth() { //Get table layout LwpTableLayout * pTableLayout = GetTableLayout(); if (pTableLayout == nullptr) { return GetGeometryWidth(); } OUString strColStyle = pTableLayout->GetColumnWidth(ccolid); XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); XFColStyle *pStyle = static_cast(pXFStyleManager->FindStyle(strColStyle)); if(pStyle) { return pStyle->GetWidth(); } return GetGeometryWidth(); } /** * @short Apply padding to cell style * @param pCellStyle - pointer of XFCellStyle * @return */ void LwpCellLayout::ApplyPadding(XFCellStyle *pCellStyle) { double fLeft = GetMarginsValue(MARGIN_LEFT); double fRight = GetMarginsValue(MARGIN_RIGHT); double fTop = GetMarginsValue(MARGIN_TOP); double fBottom = GetMarginsValue(MARGIN_BOTTOM); pCellStyle->SetPadding(static_cast(fLeft),static_cast(fRight),static_cast(fTop),static_cast(fBottom)); } /** * @short Apply border to cell style according to cell position, default cell layout won't use this function * @param * @return pCellStyle - pointer of XFCellStyle */ void LwpCellLayout::ApplyBorders(XFCellStyle *pCellStyle) { // judge cell border type LwpCellBorderType eType = GetCellBorderType(crowid, ccolid, GetTableLayout()); // get left cell and judge if neighbour border is different std::unique_ptr xBorders(GetXFBorders()); if (!xBorders) { return; } switch (eType) { case enumNoBottomBorder: xBorders->SetWidth(enumXFBorderBottom, 0); break; case enumNoLeftBorder: xBorders->SetWidth(enumXFBorderLeft, 0); break; case enumNoLeftNoBottomBorder: xBorders->SetWidth(enumXFBorderBottom, 0); xBorders->SetWidth(enumXFBorderLeft, 0); break; case enumWholeBorder: break; default: assert(false); } pCellStyle->SetBorders(xBorders.release()); } /** * @short Apply watermark to cell style * @param pCellStyle - pointer of XFCellStyle * @return */ void LwpCellLayout::ApplyWatermark(XFCellStyle *pCellStyle) { std::unique_ptr xBGImage(GetXFBGImage()); if (xBGImage) { pCellStyle->SetBackImage(xBGImage); } } /** * @short Apply pattern fill to cell style * @param pCellStyle - pointer of XFCellStyle * @return */ void LwpCellLayout::ApplyPatternFill(XFCellStyle* pCellStyle) { std::unique_ptr xXFBGImage(GetFillPattern()); if (xXFBGImage) { pCellStyle->SetBackImage(xXFBGImage); } } /** * @short Apply background to cell style * @param pCellStyle - pointer of XFCellStyle * @return */ void LwpCellLayout::ApplyBackGround(XFCellStyle* pCellStyle) { if (IsPatternFill()) { ApplyPatternFill(pCellStyle); } else { ApplyBackColor(pCellStyle); } } /** * @short Apply back color to cell style * @param pCellStyle - pointer of XFCellStyle * @return */ void LwpCellLayout::ApplyBackColor(XFCellStyle *pCellStyle) { LwpColor* pColor = GetBackColor(); if(pColor && pColor->IsValidColor()) { XFColor aXFColor(pColor->To24Color()); pCellStyle->SetBackColor(aXFColor); } } /** * @short register style of cell layout * @param pCellStyle The style of the cell, which would be applied to the cell. * @return */ void LwpCellLayout::ApplyFmtStyle(XFCellStyle *pCellStyle) { LwpLayoutNumerics* pLayoutNumerics = dynamic_cast(cLayNumerics.obj().get()); if (!pLayoutNumerics) { // if current layout doesn't have format, go to based on layout LwpCellLayout* pCellLayout = dynamic_cast(GetBasedOnStyle().get()); if (pCellLayout) { pLayoutNumerics = dynamic_cast(pCellLayout->GetNumericsObject().obj().get()); } } // apply format style if (pLayoutNumerics) { XFStyle* pStyle = pLayoutNumerics->Convert(); if (pStyle) { XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); m_NumfmtName = pXFStyleManager->AddStyle(std::unique_ptr(pStyle)).m_pStyle->GetStyleName(); pCellStyle->SetDataStyle(m_NumfmtName); } } } /** * @short get style name according to cell position, only table default cells use this function * @param nRow - default cell position row number * @param nCol - default cell position col number * @return OUString - registered cell style name */ OUString const & LwpCellLayout::GetCellStyleName(sal_uInt16 nRow, sal_uInt16 nCol, LwpTableLayout * pTableLayout) { // judge cell border type LwpCellBorderType eType = GetCellBorderType(nRow, nCol, pTableLayout); return m_CellStyleNames[eType]; } /** * Make the XFCell * @param aTableID - ID of the table which this cell belongs to * @param bIsTopRow - whether current cell is top row * @param bIsRightCol - whether current cell is the rightest column * @return XFCell* */ rtl::Reference LwpCellLayout::ConvertCell(LwpObjectID aTableID, sal_uInt16 nRow, sal_uInt16 nCol) { // if cell layout is aTableID's default cell layout // it can't have any content, bypass these code LwpTable * pTable = dynamic_cast(aTableID.obj().get()); if (!pTable) { assert(false); return nullptr; } rtl::Reference xXFCell(new XFCell); OUString aStyleName = m_StyleName; // if cell layout is aTableID's default cell layout // we should adjust its style by current position if (pTable->GetDefaultCellStyle() == GetObjectID()) { aStyleName = GetCellStyleName(nRow, nCol, pTable->GetTableLayout().get()); } // content of cell LwpStory* pStory = dynamic_cast(m_Content.obj().get()); if (pStory) { pStory->XFConvert(xXFCell.get()); } ApplyProtect(xXFCell.get(), aTableID); xXFCell->SetStyleName(aStyleName); return xXFCell; } LwpPara* LwpCellLayout::GetLastParaOfPreviousStory() { LwpObjectID* pPreStoryID = GetPreviousCellStory(); if (pPreStoryID && !(pPreStoryID->IsNull())) { LwpStory* pPreStory = dynamic_cast(pPreStoryID->obj(VO_STORY).get()); if (!pPreStory) { SAL_WARN("lwp", "unexpected null VO_STORY"); return nullptr; } return dynamic_cast(pPreStory->GetLastPara().obj(VO_PARA).get()); } else { return nullptr; } } /** * @short Get previous cell which used for bullet inside cell * @param * @return LwpObjectID * - object ID of cell content story */ LwpObjectID * LwpCellLayout::GetPreviousCellStory() { LwpTable *pTable = GetTable(); if (!pTable) { assert(false); return nullptr; } sal_uInt16 nRow = crowid; sal_uInt16 nCol = ccolid; // if table is reset paragraph in columns, get cell on the top side of current cell if (pTable->IsNumberDown()) { if (nRow == 0) { return nullptr; } nRow -=1; } else { // if not, get cell on the left side of current cell if (nCol == 0) { if (nRow == 0) { return nullptr; } else { nRow--; nCol = pTable->GetColumn() - 1; } } else { nCol -=1; } } // get the object id pointer of previous cell story LwpTableLayout * pTableLayout = GetTableLayout(); if (!pTableLayout) { assert(false); return nullptr; } return pTableLayout->SearchCellStoryMap(nRow, nCol); } /** * @short judge border type by cell neighbour * @param nRow * @param nCol * @param pTableLayout * @return LwpCellBorderType */ LwpCellBorderType LwpCellLayout::GetCellBorderType(sal_uInt16 nRow, sal_uInt16 nCol, LwpTableLayout * pTableLayout) { if (!pTableLayout) return enumWholeBorder; // get left cell and judge if neighbour border is different std::unique_ptr xBorders(GetXFBorders()); if (!xBorders) { return enumWholeBorder; } XFBorder& rLeftBorder = xBorders->GetLeft(); XFBorder& rBottomBorder = xBorders->GetBottom(); bool bNoLeftBorder = false; bool bNoBottomBorder = false; LwpCellLayout * pLeftNeighbour = GetCellByRowCol(nRow, GetLeftColID(nCol), pTableLayout); if (pLeftNeighbour) { std::unique_ptr pNeighbourBorders = pLeftNeighbour->GetXFBorders(); if (pNeighbourBorders) { XFBorder& rRightBorder = pNeighbourBorders->GetRight(); if (rLeftBorder == rRightBorder) { // for these 2 types cell, left border should be ignored for sake of avoiding duplication border // but if left border is different with right border of left cell // we should not ignored it bNoLeftBorder = true; } } } LwpCellLayout * pBelowNeighbour = GetCellByRowCol(GetBelowRowID(nRow), nCol, pTableLayout); if (pBelowNeighbour) //&& (eType == enumRightNotLastCellBorder || eType == enumLeftNotLastCellBorder) ) { std::unique_ptr pBelowBorders = pBelowNeighbour->GetXFBorders(); if (pBelowBorders) { XFBorder& rTopBorder = pBelowBorders->GetTop(); if (rTopBorder == rBottomBorder) { // for these 2 types cell, bottom border should be ignored for sake of avoiding duplication border // but if bottom border is different with right border of left cell // we should not ignored it bNoBottomBorder = true; } } } xBorders.reset(); if (bNoBottomBorder) { if (bNoLeftBorder) { return enumNoLeftNoBottomBorder; } return enumNoBottomBorder; } if (bNoLeftBorder) { return enumNoLeftBorder; } return enumWholeBorder; } /** * @short Get neighbour cell by specifying ROW+COL * @param nRow * @param nCol * @return LwpCellLayout * */ LwpCellLayout * LwpCellLayout::GetCellByRowCol(sal_uInt16 nRow, sal_uInt16 nCol, LwpTableLayout * pTableLayout) { return pTableLayout->GetCellByRowCol(nRow, nCol); } /** * @short Register table's default cell layout * @param * @return */ void LwpCellLayout::RegisterDefaultCell() { XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); for (sal_uInt16 eLoop = enumWholeBorder; eLoop < enumCellBorderTopLimit; eLoop++) { // register cell style std::unique_ptr xCellStyle(new XFCellStyle()); ApplyPadding(xCellStyle.get()); ApplyBackColor(xCellStyle.get()); ApplyWatermark(xCellStyle.get()); ApplyFmtStyle(xCellStyle.get()); xCellStyle->SetAlignType(enumXFAlignNone, GetVerticalAlignmentType()); std::unique_ptr xBorders(GetXFBorders()); if (xBorders) { switch(eLoop) { case enumNoBottomBorder: //| | // remove bottom line xBorders->SetWidth(enumXFBorderBottom, 0); break; case enumNoLeftNoBottomBorder: // | // remove left and bottom xBorders->SetWidth(enumXFBorderLeft, 0); xBorders->SetWidth(enumXFBorderBottom, 0); break; case enumWholeBorder: //|| // nothing to remove break; case enumNoLeftBorder: //| | // remove left line xBorders->SetWidth(enumXFBorderLeft, 0); break; default: assert(false); } xCellStyle->SetBorders(xBorders.release()); } m_CellStyleNames[eLoop] = pXFStyleManager->AddStyle(std::move(xCellStyle)).m_pStyle->GetStyleName(); } } /** * @short Register 4 types of cell style and register content styles * @param * @param * @param * @return */ void LwpCellLayout::RegisterStyle() { rtl::Reference xParent(dynamic_cast(GetParent().obj().get())); if (!xParent.is() || xParent->GetLayoutType() != LWP_ROW_LAYOUT) { // default cell layout, we must register 4 styles for it RegisterDefaultCell(); return; } // register cell style std::unique_ptr xCellStyle(new XFCellStyle); ApplyPadding(xCellStyle.get()); ApplyBackGround(xCellStyle.get()); ApplyWatermark(xCellStyle.get()); ApplyFmtStyle(xCellStyle.get()); ApplyBorders(xCellStyle.get()); xCellStyle->SetAlignType(enumXFAlignNone, GetVerticalAlignmentType()); XFStyleManager* pXFStyleManager = LwpGlobalMgr::GetInstance()->GetXFStyleManager(); m_StyleName = pXFStyleManager->AddStyle(std::move(xCellStyle)).m_pStyle->GetStyleName(); // content object register styles rtl::Reference pObj = m_Content.obj(); if (pObj.is()) { pObj->SetFoundry(m_pFoundry); pObj->DoRegisterStyle(); } //register child layout style RegisterChildStyle(); } /** * @short Read cell layout * @param * @return */ void LwpCellLayout::Read() { LwpObjectStream* pStrm = m_pObjStrm.get(); LwpMiddleLayout::Read(); // before the layout hierarchy rework if (LwpFileHeader::m_nFileRevision < 0x000b) { assert(false); } else { crowid = pStrm->QuickReaduInt16(); ccolid = static_cast(pStrm->QuickReaduInt16()); // written as a lushort sal_uInt16 type; type = pStrm->QuickReaduInt16(); pStrm->SkipExtra(); cType = static_cast(type); cLayNumerics.ReadIndexed(pStrm); cLayDiagonalLine.ReadIndexed(pStrm); pStrm->SkipExtra(); } } /** * Apply protect attribute to cell of table * @param aTableID - ID of the table which the cell belongs to * @param * @return XFCell* */ void LwpCellLayout::ApplyProtect(XFCell * pCell, LwpObjectID aTableID) { bool bProtected = false; // judge current cell if (GetIsProtected()) { bProtected = true; } else { // judge base on LwpCellLayout * pBase = dynamic_cast(GetBasedOnStyle().get()); if (pBase && pBase->GetIsProtected()) { bProtected = true; } else { // judge whole table LwpTable * pTable = dynamic_cast(aTableID.obj().get()); rtl::Reference xTableLayout(pTable ? pTable->GetTableLayout() : nullptr); LwpSuperTableLayout * pSuper = xTableLayout.is() ? xTableLayout->GetSuperTableLayout() : nullptr; if (pSuper && pSuper->GetIsProtected()) { bProtected = true; } } } pCell->SetProtect(bProtected); } LwpConnectedCellLayout::LwpConnectedCellLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) : LwpCellLayout(objHdr, pStrm) , cnumrows(0) , cnumcols(0) , m_nRealrowspan(0) , m_nRealcolspan(0) { } LwpConnectedCellLayout::~LwpConnectedCellLayout() {} /** * @short Set current connected cell layout to cell layout map * @param pCellLayoutMap - cell layout map reference * @return */ void LwpConnectedCellLayout::SetCellMap() { LwpTableLayout * pTableLayout = GetTableLayout(); if (!pTableLayout) return; sal_uInt16 nRowSpan = m_nRealrowspan; for (sal_uInt16 iLoop = 0; iLoop < nRowSpan; iLoop ++) { for (sal_uInt16 jLoop = 0; jLoop < cnumcols; jLoop ++) pTableLayout->SetWordProCellMap(iLoop + crowid, jLoop + ccolid, this); } } /** * @short judge border type by cell neighbour * @param nRow * @param nCol * @param pTableLayout * @return LwpCellBorderType */ LwpCellBorderType LwpConnectedCellLayout::GetCellBorderType(sal_uInt16 nRow, sal_uInt16 nCol, LwpTableLayout * pTableLayout) { if (!pTableLayout) throw std::runtime_error("missing table layout"); sal_uInt16 nRowSpan = m_nRealrowspan; // get left cell and judge if neighbour border is different std::unique_ptr xBorders(GetXFBorders()); if( !xBorders) { return enumWholeBorder; } XFBorder& rLeftBorder = xBorders->GetLeft(); XFBorder& rBottomBorder = xBorders->GetBottom(); bool bNoLeftBorder = true; bool bNoBottomBorder = true; if (nCol == 0) { bNoLeftBorder = false; } else { for (sal_uInt16 iLoop=0; iLoop < nRowSpan; iLoop++) { LwpCellLayout * pLeftNeighbour = GetCellByRowCol(nRow+iLoop, GetLeftColID(nCol), pTableLayout); if (pLeftNeighbour) { std::unique_ptr pNeighbourBorders(pLeftNeighbour->GetXFBorders()); if (pNeighbourBorders) { XFBorder& rRightBorder = pNeighbourBorders->GetRight(); if (rLeftBorder != rRightBorder) { // if left border is different with right border of left cell // we should not ignored it bNoLeftBorder = false; break; } } } } } LwpTable* pTable = pTableLayout->GetTable(); if (!pTable) throw std::runtime_error("missing table"); if ( (nRow + nRowSpan) == pTable->GetRow()) { bNoBottomBorder = false; } else { for (sal_uInt16 iLoop = 0; iLoop < cnumcols; iLoop ++) { LwpCellLayout * pBelowNeighbour = GetCellByRowCol(nRow + nRowSpan, nCol+iLoop, pTableLayout); if (pBelowNeighbour) { std::unique_ptr pBelowBorders(pBelowNeighbour->GetXFBorders()); if (pBelowBorders) { XFBorder& rTopBorder = pBelowBorders->GetTop(); if (rTopBorder != rBottomBorder) { // if bottom border is different with right border of left cell // we should not ignored it bNoBottomBorder = false; break; } } } } } xBorders.reset(); if (bNoBottomBorder) { if (bNoLeftBorder) { return enumNoLeftNoBottomBorder; } return enumNoBottomBorder; } if (bNoLeftBorder) { return enumNoLeftBorder; } return enumWholeBorder; } /** * @short Read connected cell layout * @param * @return */ void LwpConnectedCellLayout::Read() { LwpCellLayout::Read(); cnumrows = m_pObjStrm->QuickReaduInt16(); sal_uInt16 numcols = m_pObjStrm->QuickReaduInt16(); // written as a lushort cnumcols = static_cast(numcols); m_nRealrowspan = cnumrows; if (comphelper::IsFuzzing()) m_nRealrowspan = std::min(m_nRealrowspan, 128); m_nRealcolspan = cnumcols; m_pObjStrm->SkipExtra(); } rtl::Reference LwpConnectedCellLayout::ConvertCell(LwpObjectID aTableID, sal_uInt16 nRow, sal_uInt16 nCol) { rtl::Reference xXFCell = LwpCellLayout::ConvertCell(aTableID, nRow, nCol); xXFCell->SetColumnSpaned(cnumcols); return xXFCell; } /** * @short parse connected cell layout * @param pOutputStream - output stream * @return */ void LwpConnectedCellLayout::Parse(IXFStream* /*pOutputStream*/) { } LwpHiddenCellLayout::LwpHiddenCellLayout(LwpObjectHeader const &objHdr, LwpSvStream* pStrm) : LwpCellLayout(objHdr, pStrm) {} LwpHiddenCellLayout::~LwpHiddenCellLayout() {} /** * @short Set current hidden cell layout to cell layout map * @param * @return */ void LwpHiddenCellLayout::SetCellMap() { } /** * @short Read hidden cell layout * @param * @return */ void LwpHiddenCellLayout::Read() { LwpCellLayout::Read(); cconnectedlayout.ReadIndexed(m_pObjStrm.get()); m_pObjStrm->SkipExtra(); } /** * @short Convert hidden cell layout * @param aTableID - Object ID of table * @return XFCell * - pointer to converted cell */ rtl::Reference LwpHiddenCellLayout::ConvertCell(LwpObjectID aTableID, sal_uInt16 nRow, sal_uInt16 nCol) { if (!cconnectedlayout.obj().is()) return nullptr; LwpConnectedCellLayout* pConnCell = dynamic_cast(cconnectedlayout.obj().get()); if (!pConnCell || nRow < (pConnCell->GetNumrows()+pConnCell->GetRowID())) return nullptr; // if the hidden cell should be displayed for limit of SODC // use the default cell layout rtl::Reference xXFCell; LwpTable *pTable = dynamic_cast(aTableID.obj().get()); if (pTable) { LwpCellLayout *pDefault = dynamic_cast(pTable->GetDefaultCellStyle().obj().get()); if (pDefault) { xXFCell = pDefault->DoConvertCell(aTableID, nRow, nCol); } else { xXFCell = pConnCell->DoConvertCell(aTableID, nRow, nCol); } xXFCell->SetColumnSpaned(pConnCell->GetNumcols()); } else { assert(false); } return xXFCell; } /** * @short parse hidden cell layout * @param pOutputStream - output stream * @return */ void LwpHiddenCellLayout::Parse(IXFStream* /*pOutputStream*/) { } LwpParallelColumnsBlock::LwpParallelColumnsBlock(LwpObjectHeader const &objHdr, LwpSvStream* pStrm):LwpCellLayout(objHdr, pStrm) {} LwpParallelColumnsBlock::~LwpParallelColumnsBlock() {} void LwpParallelColumnsBlock::Read() { LwpCellLayout::Read(); m_pObjStrm->SkipExtra(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */