Files
core/MsBinaryFile/PptFile/Reader/Slide.cpp
2022-11-28 18:49:17 +03:00

502 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Slide.h"
CSlide::CSlide() : CElementsContainer(),
m_arTextPlaceHolders(), m_mapTextStyles()
{
m_eSlideType = stNone;
m_dReadDuration = -1.0;
m_parEmptyPictures = NULL;
}
void CSlide::SetUpTextStyle(IElement *pElem)
{
// сначала проверяем на shape
// затем применяем все настройки по-очереди
// 1) master + TextMasterStyles
// 2) persist + TextMasterStyles
// 3) свои настройки + TextMasterStyles
// причем "свои настройки" - это чисто "продвинутые настройки"
// потому что все общие ( через проперти ) - уже установлены
// тут важно выставить правильный порядок.
// словом - важная очень функция для текста,
// и, чтобы убрать всякие лишние .cpp файлы - здесь же будем учитывать
// настройки слайда (т.е. структуры не будут работать со слайдами)
if (NULL == pElem)
return;
if (etShape != pElem->m_etType)
return;
CShapeElement* pShape = dynamic_cast<CShapeElement*>(pElem);
if (NULL == pShape)
return;
// а вот надо читать, потому что текст может быть еще не выставлен
//if (_T("") == pShape->m_oShape.m_oText.m_sText) // текста нету - так чего тогда тут читать??
// return;
CTextAttributesEx* pTextSettings = &(pShape->m_oShape.m_oText);
// сначала применим ссылки на masterstyle (для шаблонного элемента)
// как узнать - просто есть ли массивы (т.к. они могли появиться пока только оттуда)
// - теперь этого делать не нужно - т.к. в мастере тоже вызывается эта функция -
// и там все это должно уже примениться
BOOL bIsPersistPresentSettings = FALSE;
BOOL bIsOwnPresentSettings = FALSE;
NSOfficePPT::TextType eTypeMaster = (NSOfficePPT::TextType)pTextSettings->m_lMasterTextType;
NSOfficePPT::TextType eTypePersist = NSOfficePPT::NoPresent;
NSOfficePPT::TextType eTypeOwn = (NSOfficePPT::TextType)pTextSettings->m_lTextType;
// persist ----------------------------------------------------------------------
LONG lCountPersistObjects = (LONG)m_arTextPlaceHolders.GetCount();
LONG lPersistIndex = pShape->m_lPersistIndex;
if ((lPersistIndex >= 0) && (lPersistIndex < lCountPersistObjects))
{
eTypePersist = (NSOfficePPT::TextType)m_arTextPlaceHolders[lPersistIndex].m_nTextType;
m_arTextPlaceHolders[lPersistIndex].ApplyProperties(pTextSettings);
bIsPersistPresentSettings = ((NULL != m_arTextPlaceHolders[lPersistIndex].m_pTextStyleProp) &&
(0 < m_arTextPlaceHolders[lPersistIndex].m_pTextStyleProp->m_lCount));
}
// ------------------------------------------------------------------------------
// own properties ---------------------------------------------------------------
if (NULL != pShape->m_pStream)
{
// теперь нужно загрузить продвинутые настройки текста из стрима.
LONG lPosition = 0; StreamUtils::StreamPosition(lPosition, pShape->m_pStream);
if (-1 != pShape->m_lOffsetTextStyle)
{
StreamUtils::StreamSeek(pShape->m_lOffsetTextStyle - 8, pShape->m_pStream);
SRecordHeader oHeader;
pShape->m_pStream->Read(&oHeader, sizeof(oHeader), NULL);
if (RECORD_TYPE_STYLE_TEXTPROP_ATOM == oHeader.RecType)
{
CRecordStyleTextPropAtom* pStyle = new CRecordStyleTextPropAtom();
pStyle->m_lCount = pShape->m_oShape.m_oText.m_sText.GetLength();
pStyle->ReadFromStream(oHeader, pShape->m_pStream);
pStyle->ApplyProperties(&(pShape->m_oShape.m_oText));
bIsOwnPresentSettings = (0 < pStyle->m_lCount);
RELEASEOBJECT(pStyle);
}
}
if (-1 != pShape->m_lOffsetTextProp)
{
StreamUtils::StreamSeek(pShape->m_lOffsetTextProp - 8, pShape->m_pStream);
SRecordHeader oHeader;
pShape->m_pStream->Read(&oHeader, sizeof(oHeader), NULL);
if (RECORD_TYPE_TEXTSPECINFO_ATOM == oHeader.RecType)
{
CRecordTextSpecInfoAtom* pSpecInfo = new CRecordTextSpecInfoAtom();
pSpecInfo->m_lCount = pShape->m_oShape.m_oText.m_sText.GetLength();
pSpecInfo->ReadFromStream(oHeader, pShape->m_pStream);
pSpecInfo->ApplyProperties(&(pShape->m_oShape.m_oText));
RELEASEOBJECT(pSpecInfo);
}
}
StreamUtils::StreamSeek(lPosition, pShape->m_pStream);
}
// ------------------------------------------------------------------------------
SetUpAllTextType(pTextSettings, eTypeMaster, eTypePersist, bIsPersistPresentSettings, eTypeOwn, bIsOwnPresentSettings);
// теперь проверим - если нету вообще разбиения на параграфы и символы -
// вставим по умолчанию для такого типа текста
// по идее нужно еще дефолт применить
if (0 == pShape->m_oShape.m_oText.m_arPFs.GetCount())
{
CTextMasterStyle* pStyle = this->m_mapTextStyles.Lookup(pShape->m_oShape.m_oText.m_lTextType);
if (NULL != pStyle)
{
if (0 < pStyle->m_lLevels)
{
pShape->m_oShape.m_oText.m_arPFs.Add(pStyle->m_arrLevels[0].oPFRun);
pShape->m_oShape.m_oText.m_arPFs[0].lCount = pShape->m_oShape.m_oText.m_sText.GetLength();
}
}
}
if (0 == pShape->m_oShape.m_oText.m_arCFs.GetCount())
{
CTextMasterStyle* pStyle = this->m_mapTextStyles.Lookup(pShape->m_oShape.m_oText.m_lTextType);
if (NULL != pStyle)
{
if (0 < pStyle->m_lLevels)
{
pShape->m_oShape.m_oText.m_arCFs.Add(pStyle->m_arrLevels[0].oCFRun);
pShape->m_oShape.m_oText.m_arCFs[0].lCount = pShape->m_oShape.m_oText.m_sText.GetLength();
}
}
}
// теперь нужно посмотреть, является ли шейп placeholder'ом
// если да, то применить его настройки ДО всех остальных
LONG lPlaceholderIndex = pShape->m_lPlaceholderPosition;
if (-1 != lPlaceholderIndex)
{
CTextMasterStyle* pStyle = this->m_mapTextStyles.Lookup(lPlaceholderIndex);
if (NULL != pStyle)
{
LONG lCountPF = (LONG)pShape->m_oShape.m_oText.m_arPFs.GetCount();
LONG lCountCF = (LONG)pShape->m_oShape.m_oText.m_arCFs.GetCount();
LONG lLevels = (LONG)pStyle->m_arrLevels.GetCount();
if (0 != lLevels)
{
for (LONG lIndexPF = 0; lIndexPF < lCountPF; ++lIndexPF)
{
LONG lIndentLevel = pTextSettings->m_arPFs[lIndexPF].lIndentLevel;
if (lIndentLevel >= 0 && lIndentLevel < lLevels)
{
pTextSettings->m_arPFs[lIndexPF].ApplyBefore(pStyle->m_arrLevels[lIndentLevel].oPFRun);
}
}
for (LONG lIndexCF = 0; lIndexCF < lCountCF; ++lIndexCF)
{
pTextSettings->m_arCFs[lIndexCF].ApplyBefore(pStyle->m_arrLevels[0].oCFRun);
}
}
}
}
// теперь нужно пересчитать все настройки в зависимости от схем слайда (только для слайда!!!)
if (stSlide == m_eSlideType)
{
pShape->m_oShape.m_oText.ApplyProperties(this);
}
if ((pShape->m_arrActions[0].m_bPresent) && (7 < m_arColorScheme.GetSize()))
{
ApplyHyperlink(pShape, m_arColorScheme[6]);
}
CPPTShape* pPPTShape = dynamic_cast<CPPTShape*>(pShape->m_oShape.m_pShape);
if (NULL != pPPTShape)
{
// теперь смотрим - что за фигура создана
switch (pPPTShape->m_eType)
{
case sptTextPlainText:
case sptTextStop:
case sptTextTriangle:
case sptTextTriangleInverted:
case sptTextChevron:
case sptTextChevronInverted:
case sptTextRingInside:
case sptTextRingOutside:
case sptTextArchUpCurve:
case sptTextArchDownCurve:
case sptTextCircleCurve:
case sptTextButtonCurve:
case sptTextArchUpPour:
case sptTextArchDownPour:
case sptTextCirclePour:
case sptTextButtonPour:
case sptTextCurveUp:
case sptTextCurveDown:
case sptTextCascadeUp:
case sptTextCascadeDown:
case sptTextWave1:
case sptTextWave2:
case sptTextWave3:
case sptTextWave4:
case sptTextInflate:
case sptTextDeflate:
case sptTextInflateBottom:
case sptTextDeflateBottom:
case sptTextInflateTop:
case sptTextDeflateTop:
case sptTextDeflateInflate:
case sptTextDeflateInflateDeflate:
case sptTextFadeRight:
case sptTextFadeLeft:
case sptTextFadeUp:
case sptTextFadeDown:
case sptTextSlantUp:
case sptTextSlantDown:
case sptTextCanUp:
case sptTextCanDown:
{
pShape->m_oShape.m_oText.m_arCFs.RemoveAll();
pShape->m_oShape.m_oText.m_arPFs.RemoveAll();
pShape->m_oShape.m_oText.m_oAttributes.m_oTextBrush = pShape->m_oShape.m_oBrush;
pShape->m_oShape.m_oText.m_oAttributes.m_nTextAlignHorizontal = 1;
pShape->m_oShape.m_oText.m_oAttributes.m_nTextAlignVertical = 1;
pShape->m_oShape.m_lDrawType = c_ShapeDrawType_Text;
break;
}
default:
break;
};
}
}
void CSlide::SetUpTextTypeStyle(CTextAttributesEx *pTextAttributes, NSOfficePPT::TextType eApplyType, LONG lApplyMode)
{
if ((NULL == pTextAttributes) || (NSOfficePPT::NoPresent == eApplyType) || (2 <= lApplyMode))
return;
CTextMasterStyle* pStyle = this->m_mapTextStyles.Lookup(eApplyType);
if (NULL == pStyle)
return;
for (size_t nIndex = 0; nIndex < pTextAttributes->m_arPFs.GetCount(); ++nIndex)
{
LONG lIndentLevel = pTextAttributes->m_arPFs[nIndex].lIndentLevel;
if (NULL != pStyle)
{
if (lIndentLevel < pStyle->m_lLevels)
{
switch (lApplyMode)
{
case 0:
{
pTextAttributes->m_arPFs[nIndex].ApplyBefore(pStyle->m_arrLevels[lIndentLevel].oPFRun);
break;
}
case 1:
{
pTextAttributes->m_arPFs[nIndex].ApplyAfter(pStyle->m_arrLevels[lIndentLevel].oPFRun);
break;
}
default:
break;
};
}
}
}
for (size_t nIndex = 0; nIndex < pTextAttributes->m_arCFs.GetCount(); ++nIndex)
{
if (NULL != pStyle)
{
LONG lIndentIndex = pTextAttributes->GetIndentLevelCF(nIndex);
if (lIndentIndex < pStyle->m_lLevels)
{
// вот непонятно какой левел нужно брать. будем нулевой пока
switch (lApplyMode)
{
case 0:
{
pTextAttributes->m_arCFs[nIndex].ApplyBefore(pStyle->m_arrLevels[lIndentIndex].oCFRun);
break;
}
case 1:
{
pTextAttributes->m_arCFs[nIndex].ApplyAfter(pStyle->m_arrLevels[lIndentIndex].oCFRun);
break;
}
default:
break;
};
}
}
}
}
void CSlide::SetUpAllTextType(CTextAttributesEx *pTextAttributes, NSOfficePPT::TextType eTypeMaster, NSOfficePPT::TextType eTypePersist, BOOL bPersistPresent, NSOfficePPT::TextType eTypeOwn, BOOL bOwnPresent)
{
if (bOwnPresent)
{
if (eTypeOwn != eTypePersist)
{
SetUpTextTypeStyle(pTextAttributes, eTypeOwn, 0);
}
if (eTypePersist != eTypeOwn)
{
SetUpTextTypeStyle(pTextAttributes, eTypePersist, 0);
}
if ((eTypeMaster != eTypePersist) && (eTypeMaster != eTypeOwn))
{
SetUpTextTypeStyle(pTextAttributes, eTypeMaster, 0);
}
}
else if (bPersistPresent)
{
SetUpTextTypeStyle(pTextAttributes, eTypePersist, 0);
if (eTypePersist != eTypeMaster)
{
SetUpTextTypeStyle(pTextAttributes, eTypeMaster, 0);
}
if (NSOfficePPT::NoPresent != eTypeOwn)
{
SetUpTextTypeStyle(pTextAttributes, eTypeOwn, 1);
}
}
else
{
SetUpTextTypeStyle(pTextAttributes, eTypeMaster, 0);
if (eTypePersist != eTypeMaster)
{
SetUpTextTypeStyle(pTextAttributes, eTypePersist, 1);
}
if (eTypeOwn != eTypePersist && ((NSOfficePPT::NoPresent != eTypePersist) || (eTypeMaster != eTypeOwn)))
{
SetUpTextTypeStyle(pTextAttributes, eTypeOwn, 1);
}
}
}
void CSlide::ApplyHyperlink(CShapeElement *pShape, SColorAtom &oColor)
{
CAtlArray<CInteractiveInfo::CTextRange>* pRanges = &pShape->m_arrActions[0].m_arRanges;
CTextAttributesEx* pTextAttributes = &pShape->m_oShape.m_oText;
LONG lCountHyper = (LONG)pRanges->GetCount();
LONG lCountCFs = (LONG)pTextAttributes->m_arCFs.GetCount();
if (0 == lCountHyper)
return;
CAtlArray<LONG> arStart;
CAtlArray<LONG> arEnd;
LONG lStartCur = 0;
LONG lEndCur = 0;
for (LONG iCF = 0; iCF < lCountCFs; ++iCF)
{
lEndCur = lStartCur + pTextAttributes->m_arCFs[iCF].lCount - 1;
arStart.Add(lStartCur);
arEnd.Add(lEndCur);
lStartCur = lEndCur + 1;
}
// сначала нормализуем Ranges
for (LONG iR = 0; iR < lCountHyper; ++iR)
{
LONG lStart = ((*pRanges)[iR]).m_lStart;
LONG lEnd = ((*pRanges)[iR]).m_lEnd;
if (lStart > lEnd)
continue;
LONG lStartFound = -1;
LONG lEndFound = -1;
lCountCFs = (LONG)pTextAttributes->m_arCFs.GetCount();
for (LONG iCF = 0; iCF < lCountCFs; ++iCF)
{
BOOL bStart = ((lStart >= arStart[iCF]) && (lStart <= arEnd[iCF]));
BOOL bEnd = ((lEnd >= arStart[iCF]) && (lEnd <= arEnd[iCF]));
if (-1 == lStartFound && bStart)
lStartFound = iCF;
if (-1 == lEndFound && bEnd)
lEndFound = iCF;
}
// найдены индексы ранов, в которых надо резать
if (-1 == lStartFound || -1 == lEndFound)
continue;
if (lStartFound == lEndFound)
{
InsertCF(lStart, lEnd, pTextAttributes->m_arCFs, arStart, arEnd, lStartFound, oColor);
}
else if (lEndFound > lStartFound)
{
// по идее другого быть не могло
// здесь последовательный вызов инсерта
InsertCF(lStart, arEnd[lStartFound], pTextAttributes->m_arCFs, arStart, arEnd, lStartFound, oColor);
LONG lPlus = (LONG)pTextAttributes->m_arCFs.GetCount() - lCountCFs;
lCountCFs += lPlus;
InsertCF(arStart[lEndFound + lPlus], lEnd, pTextAttributes->m_arCFs, arStart, arEnd, lEndFound + lPlus, oColor);
}
}
// старая версия...
/*for (size_t i = 0; i < pTextAttributes->m_arCFs.GetCount(); ++i)
{
pTextAttributes->m_arCFs[i].hasColor = true;
pTextAttributes->m_arCFs[i].oColor = oColor;
}*/
}
void CSlide::InsertCF(LONG lStartH, LONG lEndH, CAtlArray<STextCFRun> &oArrayCF, CAtlArray<LONG> &arStart, CAtlArray<LONG> &arEnd, LONG lIndexFound, SColorAtom &oColor)
{
STextCFRun oRunOld = oArrayCF[lIndexFound];
STextCFRun oRunNew = oRunOld;
oRunNew.oColor = oColor;
oRunNew.fontStyle |= 0x04;
oRunNew.hasUnderline = true;
LONG lSize1 = lStartH - arStart[lIndexFound];
LONG lSize2 = lEndH - lStartH + 1;
LONG lSize3 = arEnd[lIndexFound] - lEndH;
if (lSize1 > 0 && lSize3 > 0)
{
oArrayCF[lIndexFound].lCount = lSize1;
arEnd[lIndexFound] = arStart[lIndexFound] + lSize1 - 1;
oRunNew.lCount = lSize2;
oArrayCF.InsertAt(lIndexFound + 1, oRunNew);
arStart.InsertAt(lIndexFound + 1, arEnd[lIndexFound] + 1);
arEnd.InsertAt(lIndexFound + 1, arStart[lIndexFound + 1] + lSize2 - 1);
oRunOld.lCount = lSize3;
oArrayCF.InsertAt(lIndexFound + 2, oRunOld);
arStart.InsertAt(lIndexFound + 2, arEnd[lIndexFound + 1] + 1);
arEnd.InsertAt(lIndexFound + 2, arStart[lIndexFound + 2] + lSize3 - 1);
}
else if (lSize1 > 0)
{
oArrayCF[lIndexFound].lCount = lSize1;
arEnd[lIndexFound] = arStart[lIndexFound] + lSize1 - 1;
oRunNew.lCount = lSize2;
oArrayCF.InsertAt(lIndexFound + 1, oRunNew);
arStart.InsertAt(lIndexFound + 1, arEnd[lIndexFound] + 1);
arEnd.InsertAt(lIndexFound + 1, arStart[lIndexFound + 1] + lSize2 - 1);
}
else if (lSize3 > 0)
{
oArrayCF[lIndexFound] = oRunNew;
oArrayCF[lIndexFound].lCount = lSize2;
arEnd[lIndexFound] = arStart[lIndexFound] + lSize2 - 1;
oRunOld.lCount = lSize3;
oArrayCF.InsertAt(lIndexFound + 1, oRunOld);
arStart.InsertAt(lIndexFound + 1, arEnd[lIndexFound] + 1);
arEnd.InsertAt(lIndexFound + 1, arStart[lIndexFound + 1] + lSize3 - 1);
}
else
{
oArrayCF[lIndexFound] = oRunNew;
}
}