547 lines
17 KiB
C++
547 lines
17 KiB
C++
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2023
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
|
||
|
||
#include "TableCellPropertiesMapping.h"
|
||
|
||
namespace DocFileFormat
|
||
{
|
||
TableCellPropertiesMapping::TableCellPropertiesMapping (XMLTools::CStringXmlWriter* pWriter,
|
||
const std::vector<short>* grid, int gridIndex, int cellIndex, unsigned int depth) :
|
||
PropertiesMapping(pWriter)
|
||
{
|
||
_depth = depth;
|
||
_width = 0;
|
||
|
||
_gridIndex = gridIndex;
|
||
_grid = grid;
|
||
_cellIndex = cellIndex;
|
||
|
||
_brcTop = NULL;
|
||
_brcLeft = NULL;
|
||
_brcRight = NULL;
|
||
_brcBottom = NULL;
|
||
|
||
_tcPr = new XMLTools::XMLElement(L"w:tcPr");
|
||
_tcMar = new XMLTools::XMLElement(L"w:tcMar");
|
||
_tcBorders = new XMLTools::XMLElement(L"w:tcBorders");
|
||
|
||
_ftsWidth = Global::nil;
|
||
}
|
||
|
||
TableCellPropertiesMapping::~TableCellPropertiesMapping()
|
||
{
|
||
RELEASEOBJECT(_tcPr);
|
||
RELEASEOBJECT(_tcMar);
|
||
RELEASEOBJECT(_tcBorders);
|
||
}
|
||
}
|
||
|
||
namespace DocFileFormat
|
||
{
|
||
void TableCellPropertiesMapping::Apply (IVisitable* visited)
|
||
{
|
||
TablePropertyExceptions* tapx = static_cast<TablePropertyExceptions*>(visited);
|
||
int nComputedCellWidth = 0, nComputedCellWidths = 0;
|
||
|
||
_gridSpan = 0;
|
||
_bCoverCell = false;
|
||
|
||
unsigned int iTap_current = 1;
|
||
|
||
for ( std::vector<SinglePropertyModifier>::iterator iter = tapx->grpprl->begin(); iter != tapx->grpprl->end(); iter++ )
|
||
{
|
||
DWORD code = iter->OpCode;
|
||
|
||
switch(iter->OpCode)
|
||
{
|
||
case sprmPItap:
|
||
{
|
||
iTap_current = FormatUtils::BytesToUInt32( iter->Arguments, 0, iter->argumentsSize );
|
||
}break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
bool bPresentDefTable = false;
|
||
for (std::vector<SinglePropertyModifier>::iterator iter = tapx->grpprl->begin(); iter != tapx->grpprl->end(); ++iter)
|
||
{
|
||
switch (iter->OpCode)
|
||
{
|
||
case sprmOldTDefTable:
|
||
case sprmTDefTable:
|
||
{
|
||
if (!bPresentDefTable) //118854.doc
|
||
{
|
||
bPresentDefTable = true;
|
||
|
||
SprmTDefTable tdef(iter->Arguments, iter->argumentsSize);
|
||
|
||
bool bUseWidth = true;
|
||
|
||
for (size_t j = 0; j < tdef.rgTc80.size(); ++j)
|
||
{ // 1bc0f6c0-b226-4bcb-912c-e7f97b009d8a.doc
|
||
// Технические_Требования_1_287_ДИТ.DOC
|
||
if (tdef.rgTc80[j].horzMerge == 0 && tdef.rgTc80[j].wWidth < 1)
|
||
{
|
||
//bUseWidth = false;
|
||
break;
|
||
}
|
||
}
|
||
int cc = tdef.numberOfColumns;
|
||
|
||
_tGrid = tdef.rgdxaCenter;
|
||
_tcDef = tdef.rgTc80[(std::min)(_cellIndex, (int)tdef.rgTc80.size() - 1)];
|
||
|
||
appendValueElement( _tcPr, L"textDirection", FormatUtils::MapValueToWideString( _tcDef.textFlow, &Global::TextFlowMap[0][0], 6, 6 ), false );
|
||
|
||
if ( _tcDef.vertMerge == Global::fvmMerge )
|
||
{
|
||
appendValueElement( _tcPr, L"vMerge", L"continue", false );
|
||
}
|
||
else if ( _tcDef.vertMerge == Global::fvmRestart )
|
||
{
|
||
appendValueElement( _tcPr, L"vMerge", L"restart", false );
|
||
}
|
||
|
||
appendValueElement( _tcPr, L"vAlign", FormatUtils::MapValueToWideString( _tcDef.vertAlign, &Global::VerticalAlignMap[0][0], 3, 7 ), false );
|
||
|
||
if ( _tcDef.fFitText )
|
||
{
|
||
appendValueElement( _tcPr, L"tcFitText", L"", false );
|
||
}
|
||
|
||
if ( _tcDef.fNoWrap )
|
||
{
|
||
appendValueElement( _tcPr, L"noWrap", L"", true );
|
||
}
|
||
//int ind = (std::min)(_cellIndex, (int)tdef.rgTc80.size() - 1);
|
||
//int ind1 = ind;
|
||
//while (ind1 < tdef.rgdxaCenter.size() - 1)
|
||
//{
|
||
// int sz = tdef.rgdxaCenter[ ind1 + 1] - tdef.rgdxaCenter[ ind1 ] ;
|
||
// if (sz > 1)
|
||
// break;
|
||
// ind1++;
|
||
//}
|
||
_ftsWidth = (Global::CellWidthType)(_tcDef.ftsWidth);
|
||
|
||
if (_cellIndex < tdef.rgTc80.size())
|
||
{
|
||
if (tdef.rgTc80[_cellIndex].horzMerge == 1)
|
||
{
|
||
for (size_t i = _cellIndex; i < tdef.rgTc80.size(); i++)
|
||
{
|
||
if (tdef.rgTc80[i].horzMerge < 1)
|
||
break;
|
||
|
||
nComputedCellWidth += tdef.rgdxaCenter[i + 1] - tdef.rgdxaCenter[i];
|
||
_gridSpan++;
|
||
}
|
||
}
|
||
else if (tdef.rgTc80[_cellIndex].horzMerge == 2)
|
||
{//skip cover cell
|
||
_gridSpan = 1;
|
||
nComputedCellWidth = 0;
|
||
_bCoverCell = true;
|
||
|
||
}
|
||
else
|
||
{
|
||
_gridSpan = 1;
|
||
|
||
nComputedCellWidths += (tdef.rgdxaCenter[_cellIndex + 1] - tdef.rgdxaCenter[0]);
|
||
nComputedCellWidth += bUseWidth ? tdef.rgTc80[_cellIndex].wWidth :
|
||
(tdef.rgdxaCenter[_cellIndex + 1] - tdef.rgdxaCenter[_cellIndex]);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
|
||
}
|
||
|
||
if (!IsTableBordersDefined(tapx->grpprl))
|
||
{
|
||
_brcTop = std::shared_ptr<BorderCode>(new BorderCode(*_tcDef.brcTop));
|
||
_brcLeft = std::shared_ptr<BorderCode>(new BorderCode(*_tcDef.brcLeft));
|
||
_brcRight = std::shared_ptr<BorderCode>(new BorderCode(*_tcDef.brcRight));
|
||
_brcBottom = std::shared_ptr<BorderCode>(new BorderCode(*_tcDef.brcBottom));
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case sprmTDxaCol:
|
||
{
|
||
}break;
|
||
case sprmTCellPadding:
|
||
{
|
||
unsigned char first = iter->Arguments[0];
|
||
unsigned char lim = iter->Arguments[1];
|
||
unsigned char ftsMargin = iter->Arguments[3];
|
||
short wMargin = FormatUtils::BytesToInt16( iter->Arguments, 4, iter->argumentsSize );
|
||
|
||
if ( ( _cellIndex >= first ) && ( _cellIndex < lim ) )
|
||
{
|
||
if ( FormatUtils::GetBitFromInt( iter->Arguments[2], 0 ) == true )
|
||
{
|
||
appendDxaElement( _tcMar, L"top", FormatUtils::IntToWideString( wMargin ), true );
|
||
}
|
||
|
||
if ( FormatUtils::GetBitFromInt( iter->Arguments[2], 1 ) == true )
|
||
{
|
||
appendDxaElement( _tcMar, L"left", FormatUtils::IntToWideString( wMargin ), true );
|
||
}
|
||
|
||
if ( FormatUtils::GetBitFromInt( iter->Arguments[2], 2 ) == true )
|
||
{
|
||
appendDxaElement( _tcMar, L"bottom", FormatUtils::IntToWideString( wMargin ), true );
|
||
}
|
||
|
||
if ( FormatUtils::GetBitFromInt( iter->Arguments[2], 3 ) == true )
|
||
{
|
||
appendDxaElement( _tcMar, L"right", FormatUtils::IntToWideString( wMargin ), true );
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case sprmTDefTableShd80:
|
||
{
|
||
if (!tapx->IsSkipShading97()) // если такой операнд единственный то учитываем его, иначе скипаем его
|
||
{
|
||
apppendCellShading(iter->Arguments, iter->argumentsSize, _cellIndex);
|
||
}
|
||
}break;
|
||
case sprmOldTDefTableShd:
|
||
case sprmTDefTableShd:
|
||
{ // cell shading for cells 0-20
|
||
apppendCellShading(iter->Arguments, iter->argumentsSize, _cellIndex);
|
||
}break;
|
||
|
||
case sprmTDefTableShd2nd:
|
||
{ // cell shading for cells 21-42
|
||
apppendCellShading(iter->Arguments, iter->argumentsSize, (_cellIndex - 21));
|
||
}break;
|
||
case sprmTDefTableShd3rd:
|
||
{ // cell shading for cells 43-62
|
||
apppendCellShading(iter->Arguments, iter->argumentsSize, (_cellIndex - 43));
|
||
}break;
|
||
case sprmTCellWidth:
|
||
{ //width
|
||
unsigned char first = iter->Arguments[0];
|
||
unsigned char lim = iter->Arguments[1];
|
||
|
||
if ((_cellIndex >= first) && (_cellIndex < lim))
|
||
{
|
||
_ftsWidth = (Global::CellWidthType)(iter->Arguments[2]);
|
||
_width = FormatUtils::BytesToInt16(iter->Arguments, 3, iter->argumentsSize);
|
||
}
|
||
}
|
||
break;
|
||
case sprmTVertAlign:
|
||
{ //vertical alignment
|
||
unsigned char first = iter->Arguments[0];
|
||
unsigned char lim = iter->Arguments[1];
|
||
|
||
if ((_cellIndex >= first) && (_cellIndex < lim))
|
||
{
|
||
appendValueElement(_tcPr, L"vAlign", FormatUtils::MapValueToWideString( (VerticalCellAlignment)iter->Arguments[2], &VerticalCellAlignmentMap[0][0], 3, 7 ), true );
|
||
}
|
||
}
|
||
break;
|
||
case sprmTFitText:
|
||
{ //Autofit
|
||
unsigned char first = iter->Arguments[0];
|
||
unsigned char lim = iter->Arguments[1];
|
||
|
||
if ( ( _cellIndex >= first ) && ( _cellIndex < lim ) )
|
||
{
|
||
appendValueElement( _tcPr, L"tcFitText", FormatUtils::IntToWideString( iter->Arguments[2] ), true );
|
||
}
|
||
}
|
||
break;
|
||
case sprmTTableBorders80:
|
||
{
|
||
const int size = 4;
|
||
unsigned char brc80[size];
|
||
|
||
memcpy(brc80, iter->Arguments, size);
|
||
if (!_brcTop)
|
||
_brcTop = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
|
||
memcpy(brc80, (iter->Arguments + 4), size);
|
||
if (!_brcLeft)
|
||
_brcLeft = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
|
||
memcpy(brc80, (iter->Arguments + 8), size);
|
||
if (!_brcBottom)
|
||
_brcBottom = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
|
||
memcpy(brc80, (iter->Arguments + 12), size);
|
||
if (!_brcRight)
|
||
_brcRight = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
|
||
//memcpy(brc80, (iter->Arguments + 16), size);
|
||
//_brcHorz = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
|
||
//memcpy(brc80, (iter->Arguments + 20), size);
|
||
//_brcVert = std::shared_ptr<BorderCode>(new BorderCode(brc80, size));
|
||
}break;
|
||
case sprmOldTTableBorders:
|
||
case sprmTTableBorders:
|
||
{
|
||
const int size = 8;
|
||
unsigned char brc[size];
|
||
|
||
memcpy(brc, iter->Arguments, size);
|
||
if (!_brcTop)
|
||
_brcTop = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
|
||
memcpy(brc, (iter->Arguments + 8), size);
|
||
if (!_brcLeft)
|
||
_brcLeft = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
|
||
memcpy(brc, (iter->Arguments + 16), size);
|
||
if (!_brcBottom)
|
||
_brcBottom = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
|
||
memcpy(brc, (iter->Arguments + 24), size);
|
||
if (!_brcRight)
|
||
_brcRight = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
|
||
//memcpy(brc, (iter->Arguments + 32), size);
|
||
//_brcHorz = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
|
||
//memcpy(brc, (iter->Arguments + 40), size);
|
||
//_brcVert = std::shared_ptr<BorderCode>(new BorderCode(brc, size));
|
||
}break;
|
||
case sprmOldTSetBrc:
|
||
case sprmTSetBrc:
|
||
{ //borders (cell definition)
|
||
unsigned char min = iter->Arguments[0];
|
||
unsigned char max = iter->Arguments[1];
|
||
|
||
int bordersToApply = (int)( iter->Arguments[2] );
|
||
|
||
if ( ( _cellIndex >= min ) && ( _cellIndex < max ) )
|
||
{
|
||
const int brcSize = 8;
|
||
unsigned char brcBytes[brcSize];
|
||
memcpy( brcBytes, ( iter->Arguments + 3 ), brcSize );
|
||
|
||
if( FormatUtils::BitmaskToBool( bordersToApply, 0x01 ) )
|
||
{
|
||
_brcTop = std::shared_ptr<BorderCode>(new BorderCode( brcBytes, brcSize ));
|
||
}
|
||
if( FormatUtils::BitmaskToBool( bordersToApply, 0x02 ) )
|
||
{
|
||
_brcLeft = std::shared_ptr<BorderCode>(new BorderCode( brcBytes, brcSize ));
|
||
}
|
||
if ( FormatUtils::BitmaskToBool( bordersToApply, 0x04 ) )
|
||
{
|
||
_brcBottom = std::shared_ptr<BorderCode>(new BorderCode( brcBytes, brcSize ));
|
||
}
|
||
if ( FormatUtils::BitmaskToBool( bordersToApply, 0x08 ) )
|
||
{
|
||
_brcRight = std::shared_ptr<BorderCode>(new BorderCode( brcBytes, brcSize ));
|
||
}
|
||
}
|
||
}break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
int nComputedCellWidthsGrid = 0;
|
||
|
||
for (size_t ccc = 0; ccc < _grid->size() && ccc <= _gridIndex; ccc++)
|
||
{
|
||
nComputedCellWidthsGrid += _grid->at(ccc);
|
||
}//zadost.doc
|
||
if (_gridSpan <= 1 && nComputedCellWidth > _width/* && _width > 1*/ && nComputedCellWidths > nComputedCellWidthsGrid)
|
||
{
|
||
int width_current = 0;
|
||
for (int i = _gridIndex; i < _grid->size(); i++)
|
||
{
|
||
width_current += _grid->at(i);
|
||
if (width_current >= nComputedCellWidth)
|
||
break;
|
||
_gridSpan++;
|
||
}
|
||
_width = nComputedCellWidth;
|
||
}
|
||
|
||
XMLTools::XMLElement tcW ( L"w:tcW" );
|
||
|
||
if (_width > 1 || nComputedCellWidth > 0)
|
||
{
|
||
if (_ftsWidth == Global::CellWidthType::nil)
|
||
_ftsWidth = Global::CellWidthType::dxa;
|
||
}
|
||
else _ftsWidth = Global::CellWidthType::Auto;
|
||
|
||
XMLTools::XMLAttribute tcWVal ( L"w:w", FormatUtils::IntToWideString( _width > 1 ? _width : nComputedCellWidth) );
|
||
XMLTools::XMLAttribute tcWType ( L"w:type", FormatUtils::MapValueToWideString(_ftsWidth, &Global::CellWidthTypeMap[0][0], 4, 5 ));
|
||
|
||
tcW.AppendAttribute( tcWVal );
|
||
tcW.AppendAttribute( tcWType );
|
||
_tcPr->AppendChild( tcW );
|
||
|
||
if ( _gridSpan == 1 && ( _gridIndex < (int)_grid->size() ) && ( nComputedCellWidths > nComputedCellWidthsGrid ) )
|
||
{
|
||
//check the number of merged cells
|
||
for ( size_t i = _gridIndex + 1; i < _grid->size(); i++ )
|
||
{
|
||
_gridSpan++;
|
||
|
||
nComputedCellWidthsGrid += _grid->at( i );
|
||
|
||
if ( nComputedCellWidthsGrid >= nComputedCellWidths )
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (_gridSpan > 1)
|
||
{
|
||
appendValueElement( _tcPr, L"gridSpan", FormatUtils::IntToWideString( _gridSpan ), true );
|
||
}
|
||
|
||
//append margins
|
||
if (_tcMar->GetChildCount() > 0)
|
||
{
|
||
_tcPr->AppendChild( *(_tcMar) );
|
||
}
|
||
|
||
//append borders
|
||
if (_brcTop)
|
||
{
|
||
XMLTools::XMLElement topBorder( L"w:top" );
|
||
appendBorderAttributes(_brcTop.get(), &topBorder);
|
||
addOrSetBorder(_tcBorders, &topBorder );
|
||
}
|
||
|
||
if (_brcLeft )
|
||
{
|
||
XMLTools::XMLElement leftBorder( L"w:left" );
|
||
appendBorderAttributes(_brcLeft.get(), &leftBorder);
|
||
addOrSetBorder(_tcBorders, &leftBorder);
|
||
}
|
||
|
||
if (_brcBottom)
|
||
{
|
||
XMLTools::XMLElement bottomBorder( L"w:bottom" );
|
||
appendBorderAttributes(_brcBottom.get(), &bottomBorder);
|
||
addOrSetBorder(_tcBorders, &bottomBorder);
|
||
}
|
||
|
||
if (_brcRight)
|
||
{
|
||
XMLTools::XMLElement rightBorder( L"w:right" );
|
||
appendBorderAttributes( _brcRight.get(), &rightBorder );
|
||
addOrSetBorder( _tcBorders, &rightBorder );
|
||
}
|
||
|
||
if ( _tcBorders->GetChildCount() > 0 )
|
||
{
|
||
_tcPr->AppendChild( *(_tcBorders) );
|
||
}
|
||
|
||
//write Properties
|
||
if ((_tcPr->GetChildCount() > 0) || (_tcPr->GetAttributeCount() > 0))
|
||
m_pXmlWriter->WriteString(_tcPr->GetXMLString());
|
||
}
|
||
|
||
void TableCellPropertiesMapping::apppendCellShading (unsigned char* sprmArg, int size, int cellIndex)
|
||
{
|
||
if (sprmArg && cellIndex >= 0)
|
||
{
|
||
//shading descriptor can have 10 bytes (Word 2000) or 2 bytes (Word 97)
|
||
int shdLength = 2;
|
||
|
||
if ( ( size % 10 ) == 0 )
|
||
shdLength = 10;
|
||
|
||
unsigned char* shdBytes = new unsigned char[shdLength];
|
||
|
||
if (shdBytes)
|
||
{
|
||
if ( ( cellIndex * shdLength ) < size )
|
||
{
|
||
memcpy (shdBytes, sprmArg + (cellIndex * shdLength), shdLength);
|
||
|
||
ShadingDescriptor shd (shdBytes, shdLength);
|
||
appendShading (_tcPr, shd);
|
||
}
|
||
|
||
RELEASEARRAYOBJECTS(shdBytes);
|
||
}
|
||
}
|
||
}
|
||
|
||
bool TableCellPropertiesMapping::IsTableBordersDefined (const std::vector<SinglePropertyModifier>* grpprl) const
|
||
{
|
||
if (grpprl)
|
||
{
|
||
std::vector<SinglePropertyModifier>::const_iterator end = grpprl->end();
|
||
for (std::vector<SinglePropertyModifier>::const_iterator iter = grpprl->begin(); iter != end; ++iter)
|
||
{
|
||
if ((iter->OpCode == sprmTTableBorders) || (iter->OpCode == sprmTTableBorders80) || (iter->OpCode == sprmTSetBrc))
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
bool TableCellPropertiesMapping::IsTableCellWidthDefined (const std::vector<SinglePropertyModifier>* grpprl) const
|
||
{
|
||
if (grpprl)
|
||
{
|
||
std::vector<SinglePropertyModifier>::const_iterator end = grpprl->end();
|
||
for (std::vector<SinglePropertyModifier>::const_iterator iter = grpprl->begin(); iter != end; ++iter)
|
||
{
|
||
if ( iter->OpCode == sprmTCellWidth )
|
||
{
|
||
unsigned char first = iter->Arguments[0];
|
||
unsigned char lim = iter->Arguments[1];
|
||
|
||
if ((_cellIndex >= first) && (_cellIndex < lim))
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
}
|