/* AbiWord * Copyright (C) 2005 Dom Lachowicz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include "ie_TOC.h" #include "pd_Document.h" #include "ut_string.h" #include "ut_misc.h" #include "px_ChangeRecord.h" #include "px_CR_Object.h" #include "px_CR_Span.h" #include "px_CR_Strux.h" #include "pp_AttrProp.h" #include "pd_Style.h" #include "ut_assert.h" #include "ut_debugmsg.h" /*******************************************************************************/ /*******************************************************************************/ class TOC_Listener : public PL_Listener { public: TOC_Listener(PD_Document * pDocument, IE_TOCHelper * toc); virtual ~TOC_Listener(); virtual bool populate(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool populateStrux(PL_StruxDocHandle sdh, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh); virtual bool change(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool insertStrux(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr, PL_StruxDocHandle sdh, PL_ListenerId lid, void (* pfnBindHandles)(PL_StruxDocHandle sdhNew, PL_ListenerId lid, PL_StruxFmtHandle sfhNew)); virtual bool signal(UT_uint32 iSignal); private: void _saveTOCData(const UT_UCSChar * data, UT_uint32 length); void _commitTOCData(); bool mInHeading; UT_UTF8String mHeadingText; int mHeadingLevel; PD_Document * mDocument; IE_TOCHelper * mTOC; }; /*******************************************************************************/ /*******************************************************************************/ void TOC_Listener::_saveTOCData(const UT_UCSChar * data, UT_uint32 length) { const UT_UCSChar * pData; UT_return_if_fail(sizeof(UT_Byte) == sizeof(char)); for (pData=data; (pData_defineTOC(mHeadingText, mHeadingLevel); } mInHeading = false; mHeadingText.clear(); mHeadingLevel = 0; } TOC_Listener::TOC_Listener(PD_Document * pDocument, IE_TOCHelper * toc) : mInHeading(0), mHeadingText(""), mHeadingLevel(0), mDocument(pDocument), mTOC(toc) { } TOC_Listener::~TOC_Listener() { } bool TOC_Listener::populate(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * pcr) { switch (pcr->getType()) { case PX_ChangeRecord::PXT_InsertSpan: { if (mInHeading) { const PX_ChangeRecord_Span * pcrs = static_cast (pcr); PT_BufIndex bi = pcrs->getBufIndex(); _saveTOCData(mDocument->getPointer(bi),pcrs->getLength()); } return true; } default: return true; } } bool TOC_Listener::populateStrux(PL_StruxDocHandle /*sdh*/, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh) { UT_return_val_if_fail(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux, false); const PX_ChangeRecord_Strux * pcrx = static_cast (pcr); *psfh = 0; // resets all TOC foo _commitTOCData(); switch (pcrx->getStruxType()) { case PTX_Block: { const PP_AttrProp * pAP = NULL; bool bHaveProp = mDocument->getAttrProp (pcr->getIndexAP(), &pAP); if (bHaveProp) { const XML_Char * szValue = 0; bool bHaveStyle = pAP->getAttribute (PT_STYLE_ATTRIBUTE_NAME, szValue); if (bHaveStyle) { if (mTOC->isTOCStyle (szValue, &mHeadingLevel)) { mInHeading = true; } } } return true; } default: return true; } } bool TOC_Listener::change(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/) { UT_ASSERT_NOT_REACHED(); return false; } bool TOC_Listener::insertStrux(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/, PL_StruxDocHandle /*sdh*/, PL_ListenerId /* lid */, void (* /*pfnBindHandles*/)(PL_StruxDocHandle /* sdhNew */, PL_ListenerId /* lid */, PL_StruxFmtHandle /* sfhNew */)) { UT_ASSERT_NOT_REACHED(); // this function is not used. return false; } bool TOC_Listener::signal(UT_uint32 /* iSignal */) { UT_ASSERT_NOT_REACHED(); return false; } /*******************************************************************************/ /*******************************************************************************/ IE_TOCHelper::IE_TOCHelper(PD_Document * pDoc) : mHasTOC(false), mDoc(pDoc) { TOC_Listener listener(pDoc,this); pDoc->tellListener(&listener); } IE_TOCHelper::~IE_TOCHelper() { UT_VECTOR_PURGEALL(UT_UTF8String *, mTOCStrings); } bool IE_TOCHelper::hasTOC() const { return mHasTOC; } bool IE_TOCHelper::_tocNameLevelHelper(const UT_UTF8String & styleName, const char * sLStyle) const { UT_UTF8String sTmpStyle = styleName; if(UT_stricmp(sLStyle,sTmpStyle.utf8_str()) == 0) { return true; } PD_Style * pStyle = NULL; mDoc->getStyle(sTmpStyle.utf8_str(), &pStyle); if(pStyle != NULL) { UT_sint32 iLoop = 0; while((pStyle->getBasedOn()) != NULL && (iLoop < 10)) { pStyle = pStyle->getBasedOn(); iLoop++; sTmpStyle = pStyle->getName(); if(UT_stricmp(sLStyle,sTmpStyle.utf8_str()) == 0) { return true; } } } return false; } bool IE_TOCHelper::isTOCStyle(const UT_UTF8String & styleName, int * out_level) const { // TODO: support user-defined toc-styles... // !pSectionAP->getProperty("toc-source-style1",pszTOCSRC)) if (_tocNameLevelHelper (styleName, "Heading 1")) { if (out_level) *out_level = 1; return true; } else if (_tocNameLevelHelper (styleName, "Heading 2")) { if (out_level) *out_level = 2; return true; } else if (_tocNameLevelHelper (styleName, "Heading 3")) { if (out_level) *out_level = 3; return true; } else if (_tocNameLevelHelper (styleName, "Heading 4")) { if (out_level) *out_level = 4; return true; } return false; } bool IE_TOCHelper::isTOCStyle(const XML_Char * styleName, int * out_level) const { return isTOCStyle(UT_UTF8String(styleName), out_level); } int IE_TOCHelper::getNumTOCEntries() const { return mTOCStrings.size (); } UT_UTF8String IE_TOCHelper::getNthTOCEntry(int nth, int * out_level) const { UT_return_val_if_fail(nth < getNumTOCEntries(), ""); if (out_level != NULL) *out_level = mTOCLevels[nth]; return *mTOCStrings.getNthItem(nth); } void IE_TOCHelper::_defineTOC(const UT_UTF8String & toc_text, int level) { mHasTOC = true; mTOCStrings.push_back(new UT_UTF8String(toc_text)); mTOCLevels.push_back(level); UT_DEBUGMSG(("Defining TOC: %s => %d\n", toc_text.utf8_str(), level)); }