diff options
Diffstat (limited to 'sw/source/core/unocore/unoportenum.cxx')
-rw-r--r-- | sw/source/core/unocore/unoportenum.cxx | 1175 |
1 files changed, 1175 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx new file mode 100644 index 000000000000..04bbd54c893b --- /dev/null +++ b/sw/source/core/unocore/unoportenum.cxx @@ -0,0 +1,1175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <unoport.hxx> +#include <IMark.hxx> +// --> OD 2007-10-23 #i81002# +#include <crossrefbookmark.hxx> +// <-- +#include <doc.hxx> +#include <txatbase.hxx> +#include <txtatr.hxx> +#include <ndhints.hxx> +#include <ndtxt.hxx> +#include <unocrsr.hxx> +#include <docary.hxx> +#include <tox.hxx> +#include <unomid.h> +#include <unoparaframeenum.hxx> +#include <unocrsrhelper.hxx> +#include <unorefmark.hxx> +#include <unobookmark.hxx> +#include <unoredline.hxx> +#include <unofield.hxx> +#include <unometa.hxx> +#include <fmtmeta.hxx> +#include <fmtanchr.hxx> +#include <fmtrfmrk.hxx> +#include <frmfmt.hxx> +#include <unoidx.hxx> +#include <redline.hxx> +#include <crsskip.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> +#include <set> + +#include <boost/shared_ptr.hpp> +#include <boost/bind.hpp> +#include <algorithm> +#include <stack> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using ::rtl::OUString; +using namespace ::std; + +typedef ::std::pair< TextRangeList_t * const, SwTxtAttr const * const > PortionList_t; +typedef ::std::stack< PortionList_t > PortionStack_t; + +static void lcl_CreatePortions( + TextRangeList_t & i_rPortions, + uno::Reference< text::XText > const& i_xParentText, + SwUnoCrsr* pUnoCrsr, + FrameDependSortList_t & i_rFrames, + const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos ); + +namespace +{ + static const sal_uInt8 BKM_TYPE_START = 0; + static const sal_uInt8 BKM_TYPE_END = 1; + static const sal_uInt8 BKM_TYPE_START_END = 2; + + struct SwXBookmarkPortion_Impl + { + Reference<XTextContent> xBookmark; + sal_uInt8 nBkmType; + const SwPosition aPosition; + + SwXBookmarkPortion_Impl(uno::Reference<text::XTextContent> const& xMark, + const sal_uInt8 nType, SwPosition const& rPosition) + : xBookmark ( xMark ) + , nBkmType ( nType ) + , aPosition ( rPosition ) + { + } + sal_uLong getIndex () + { + return aPosition.nContent.GetIndex(); + } + }; + typedef boost::shared_ptr < SwXBookmarkPortion_Impl > SwXBookmarkPortion_ImplSharedPtr; + struct BookmarkCompareStruct + { + bool operator () ( const SwXBookmarkPortion_ImplSharedPtr &r1, + const SwXBookmarkPortion_ImplSharedPtr &r2 ) const + { + // #i16896# for bookmark portions at the same position, the start should + // always precede the end. Hence compare positions, and use bookmark type + // as tie-breaker for same position. + // return ( r1->nIndex == r2->nIndex ) + // ? ( r1->nBkmType < r2->nBkmType ) + // : ( r1->nIndex < r2->nIndex ); + + // MTG: 25/11/05: Note that the above code does not correctly handle + // the case when one bookmark ends, and another begins in the same + // position. When this occurs, the above code will return the + // the start of the 2nd bookmark BEFORE the end of the first bookmark + // See bug #i58438# for more details. The below code is correct and + // fixes both #i58438 and #i16896# + return r1->aPosition < r2->aPosition; + } + }; + typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList; + + + static void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCrsr& rUnoCrsr, SwXBookmarkPortion_ImplList& rBkmArr) + { + IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess(); + if(!pMarkAccess->getBookmarksCount()) + return; + + // no need to consider marks starting after aEndOfPara + SwPosition aEndOfPara(*rUnoCrsr.GetPoint()); + aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTxtNode()->Len(); + const IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound( + pMarkAccess->getBookmarksBegin(), + pMarkAccess->getBookmarksEnd(), + aEndOfPara, + bind(&::sw::mark::IMark::StartsAfter, _2, _1)); // finds the first that starts after + + // search for all bookmarks that start or end in this paragraph + const SwNodeIndex nOwnNode = rUnoCrsr.GetPoint()->nNode; + for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getBookmarksBegin(); + ppMark != pCandidatesEnd; + ++ppMark) + { + ::sw::mark::IMark* const pBkmk = ppMark->get(); + bool hasOther = pBkmk->IsExpanded(); + + const SwPosition& rStartPos = pBkmk->GetMarkStart(); + if(rStartPos.nNode == nOwnNode) + { + const sal_uInt8 nType = hasOther ? BKM_TYPE_START : BKM_TYPE_START_END; + rBkmArr.insert(SwXBookmarkPortion_ImplSharedPtr( + new SwXBookmarkPortion_Impl( + SwXBookmark::CreateXBookmark(rDoc, *pBkmk), + nType, rStartPos))); + } + + const SwPosition& rEndPos = pBkmk->GetMarkEnd(); + if(rEndPos.nNode == nOwnNode) + { + auto_ptr<SwPosition> pCrossRefEndPos; + const SwPosition* pEndPos = NULL; + if(hasOther) + pEndPos = &rEndPos; + else if(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk)) + { + // Crossrefbookmarks only remember the start position but have to span the whole paragraph + pCrossRefEndPos = auto_ptr<SwPosition>(new SwPosition(rEndPos)); + pCrossRefEndPos->nContent = pCrossRefEndPos->nNode.GetNode().GetTxtNode()->Len(); + pEndPos = pCrossRefEndPos.get(); + } + if(pEndPos) + { + rBkmArr.insert(SwXBookmarkPortion_ImplSharedPtr( + new SwXBookmarkPortion_Impl( + SwXBookmark::CreateXBookmark(rDoc, *pBkmk), + BKM_TYPE_END, *pEndPos))); + } + } + } + } +} + +/****************************************************************** + * SwXTextPortionEnumeration + ******************************************************************/ +const uno::Sequence< sal_Int8 > & SwXTextPortionEnumeration::getUnoTunnelId() +{ + static uno::Sequence< sal_Int8 > aSeq = ::CreateUnoTunnelId(); + return aSeq; +} + +sal_Int64 SAL_CALL SwXTextPortionEnumeration::getSomething( + const uno::Sequence< sal_Int8 >& rId ) +throw(uno::RuntimeException) +{ + if( rId.getLength() == 16 + && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), + rId.getConstArray(), 16 ) ) + { + return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ) ); + } + return 0; +} + +OUString SwXTextPortionEnumeration::getImplementationName() +throw( RuntimeException ) +{ + return C2U("SwXTextPortionEnumeration"); +} + +sal_Bool +SwXTextPortionEnumeration::supportsService(const OUString& rServiceName) +throw( RuntimeException ) +{ + return C2U("com.sun.star.text.TextPortionEnumeration") == rServiceName; +} + +Sequence< OUString > SwXTextPortionEnumeration::getSupportedServiceNames() +throw( RuntimeException ) +{ + Sequence< OUString > aRet(1); + OUString* pArray = aRet.getArray(); + pArray[0] = C2U("com.sun.star.text.TextPortionEnumeration"); + return aRet; +} + +SwXTextPortionEnumeration::SwXTextPortionEnumeration( + SwPaM& rParaCrsr, + uno::Reference< XText > const & xParentText, + const sal_Int32 nStart, + const sal_Int32 nEnd ) + : m_Portions() +{ + SwUnoCrsr* pUnoCrsr = + rParaCrsr.GetDoc()->CreateUnoCrsr(*rParaCrsr.GetPoint(), sal_False); + pUnoCrsr->Add(this); + + DBG_ASSERT(nEnd == -1 || (nStart <= nEnd && + nEnd <= pUnoCrsr->Start()->nNode.GetNode().GetTxtNode()->GetTxt().Len()), + "start or end value invalid!"); + + // find all frames, graphics and OLEs that are bound AT character in para + FrameDependSortList_t frames; + ::CollectFrameAtNode(*this, pUnoCrsr->GetPoint()->nNode, frames, true); + lcl_CreatePortions(m_Portions, xParentText, pUnoCrsr, frames, nStart, nEnd); +} + +SwXTextPortionEnumeration::SwXTextPortionEnumeration( + SwPaM& rParaCrsr, + TextRangeList_t const & rPortions ) + : m_Portions( rPortions ) +{ + SwUnoCrsr* const pUnoCrsr = + rParaCrsr.GetDoc()->CreateUnoCrsr(*rParaCrsr.GetPoint(), sal_False); + pUnoCrsr->Add(this); +} + +SwXTextPortionEnumeration::~SwXTextPortionEnumeration() +{ + SolarMutexGuard aGuard; + + SwUnoCrsr* pUnoCrsr = GetCursor(); + delete pUnoCrsr; +} + +sal_Bool SwXTextPortionEnumeration::hasMoreElements() +throw( uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + + return (m_Portions.size() > 0) ? sal_True : sal_False; +} + +uno::Any SwXTextPortionEnumeration::nextElement() +throw( container::NoSuchElementException, lang::WrappedTargetException, + uno::RuntimeException ) +{ + SolarMutexGuard aGuard; + + if (!m_Portions.size()) + throw container::NoSuchElementException(); + + Any any; + any <<= m_Portions.front(); + m_Portions.pop_front(); + return any; +} + +typedef ::std::deque< xub_StrLen > FieldMarks_t; + +static void +lcl_FillFieldMarkArray(FieldMarks_t & rFieldMarks, SwUnoCrsr const & rUnoCrsr, + const sal_Int32 i_nStartPos) +{ + const SwTxtNode * const pTxtNode = + rUnoCrsr.GetPoint()->nNode.GetNode().GetTxtNode(); + if (!pTxtNode) return; + + const sal_Unicode fld[] = { + CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, CH_TXT_ATR_FORMELEMENT, 0 }; + xub_StrLen pos = ::std::max(static_cast<const sal_Int32>(0), i_nStartPos); + while ((pos = pTxtNode->GetTxt().SearchChar(fld, pos)) != STRING_NOTFOUND) + { + rFieldMarks.push_back(pos); + ++pos; + } +} + +static uno::Reference<text::XTextRange> +lcl_ExportFieldMark( + uno::Reference< text::XText > const & i_xParentText, + SwUnoCrsr * const pUnoCrsr, + const SwTxtNode * const pTxtNode ) +{ + uno::Reference<text::XTextRange> xRef; + SwDoc* pDoc = pUnoCrsr->GetDoc(); + //flr: maybe its a good idea to add a special hint to the hints array and rely on the hint segmentation.... + const xub_StrLen start = pUnoCrsr->Start()->nContent.GetIndex(); + OSL_ENSURE(pUnoCrsr->End()->nContent.GetIndex() == start, + "hmm --- why is this different"); + + pUnoCrsr->Right(1, CRSR_SKIP_CHARS, sal_False, sal_False); + if ( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() ) + { + OSL_FAIL("cannot move cursor?"); + return 0; + } + + const sal_Unicode Char = pTxtNode->GetTxt().GetChar(start); + if (CH_TXT_ATR_FIELDSTART == Char) + { + ::sw::mark::IFieldmark* pFieldmark = NULL; + if (pDoc) + { + pFieldmark = pDoc->getIDocumentMarkAccess()-> + getFieldmarkFor(*pUnoCrsr->GetMark()); + } + SwXTextPortion* pPortion = new SwXTextPortion( + pUnoCrsr, i_xParentText, PORTION_FIELD_START); + xRef = pPortion; + if (pPortion && pFieldmark && pDoc) + pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) ); + } + else if (CH_TXT_ATR_FIELDEND == Char) + { + ::sw::mark::IFieldmark* pFieldmark = NULL; + if (pDoc) + { + pFieldmark = pDoc->getIDocumentMarkAccess()-> + getFieldmarkFor(*pUnoCrsr->GetMark()); + } + SwXTextPortion* pPortion = new SwXTextPortion( + pUnoCrsr, i_xParentText, PORTION_FIELD_END); + xRef = pPortion; + if (pPortion && pFieldmark && pDoc) + pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) ); + } + else if (CH_TXT_ATR_FORMELEMENT == Char) + { + ::sw::mark::IFieldmark* pFieldmark = NULL; + if (pDoc) + { + pFieldmark = pDoc->getIDocumentMarkAccess()-> + getFieldmarkFor(*pUnoCrsr->GetMark()); + } + SwXTextPortion* pPortion = new SwXTextPortion( + pUnoCrsr, i_xParentText, PORTION_FIELD_START_END); + xRef = pPortion; + if (pPortion && pFieldmark && pDoc) + pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) ); + } + else + { + OSL_FAIL("no fieldmark found?"); + } + return xRef; +} + +static Reference<XTextRange> +lcl_CreateRefMarkPortion( + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + const SwTxtAttr & rAttr, const bool bEnd) +{ + SwDoc* pDoc = pUnoCrsr->GetDoc(); + const SwFmtRefMark& rRefMark = + static_cast<const SwFmtRefMark&>(rAttr.GetAttr()); + Reference<XTextContent> xContent; + if (!xContent.is()) + { + xContent = new SwXReferenceMark(pDoc, &rRefMark); + } + + SwXTextPortion* pPortion = 0; + if (!bEnd) + { + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_REFMARK_START); + pPortion->SetRefMark(xContent); + pPortion->SetCollapsed(rAttr.GetEnd() ? false : true); + } + else + { + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_REFMARK_END); + pPortion->SetRefMark(xContent); + } + return pPortion; +} + +static void +lcl_InsertRubyPortion( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + const SwTxtAttr & rAttr, const sal_Bool bEnd) +{ + SwXTextPortion* pPortion = new SwXTextPortion(pUnoCrsr, + static_cast<const SwTxtRuby&>(rAttr), xParent, bEnd); + rPortions.push_back(pPortion); + pPortion->SetCollapsed(rAttr.GetEnd() ? false : true); +} + +static Reference<XTextRange> +lcl_CreateTOXMarkPortion( + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + SwTxtAttr & rAttr, const bool bEnd) +{ + SwDoc* pDoc = pUnoCrsr->GetDoc(); + SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr()); + + const Reference<XTextContent> xContent( + SwXDocumentIndexMark::CreateXDocumentIndexMark(*pDoc, + *const_cast<SwTOXType*>(rTOXMark.GetTOXType()), rTOXMark), + uno::UNO_QUERY); + + SwXTextPortion* pPortion = 0; + if (!bEnd) + { + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_TOXMARK_START); + pPortion->SetTOXMark(xContent); + pPortion->SetCollapsed(rAttr.GetEnd() ? false : true); + } + else + { + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_TOXMARK_END); + pPortion->SetTOXMark(xContent); + } + return pPortion; +} + +static uno::Reference<text::XTextRange> +lcl_CreateMetaPortion( + uno::Reference<text::XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + SwTxtAttr & rAttr, ::std::auto_ptr<TextRangeList_t const> & pPortions) +{ + const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta( + *static_cast<SwFmtMeta &>(rAttr.GetAttr()).GetMeta(), + xParent, pPortions)); + SwXTextPortion * pPortion(0); + if (RES_TXTATR_META == rAttr.Which()) + { + const uno::Reference<text::XTextContent> xContent(xMeta, + uno::UNO_QUERY); + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_META); + pPortion->SetMeta(xContent); + } + else + { + const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY); + pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_FIELD); + pPortion->SetTextField(xField); + } + return pPortion; +} + +static void +lcl_ExportBookmark( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + SwXBookmarkPortion_ImplList& rBkmArr, const sal_uLong nIndex) +{ + for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); + aIter != aEnd; ) + { + SwXBookmarkPortion_ImplSharedPtr pPtr = (*aIter); + if ( nIndex > pPtr->getIndex() ) + { + rBkmArr.erase( aIter++ ); + continue; + } + if ( nIndex < pPtr->getIndex() ) + break; + + SwXTextPortion* pPortion = 0; + if ((BKM_TYPE_START == pPtr->nBkmType) || + (BKM_TYPE_START_END == pPtr->nBkmType)) + { + pPortion = + new SwXTextPortion(pUnoCrsr, xParent, PORTION_BOOKMARK_START); + rPortions.push_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + pPortion->SetCollapsed( (BKM_TYPE_START_END == pPtr->nBkmType) + ? true : false); + + } + if (BKM_TYPE_END == pPtr->nBkmType) + { + pPortion = + new SwXTextPortion(pUnoCrsr, xParent, PORTION_BOOKMARK_END); + rPortions.push_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + } + rBkmArr.erase( aIter++ ); + } +} + +static void +lcl_ExportSoftPageBreak( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + SwSoftPageBreakList& rBreakArr, const sal_uLong nIndex) +{ + for ( SwSoftPageBreakList::iterator aIter = rBreakArr.begin(), + aEnd = rBreakArr.end(); + aIter != aEnd; ) + { + if ( nIndex > *aIter ) + { + rBreakArr.erase( aIter++ ); + continue; + } + if ( nIndex < *aIter ) + break; + + rPortions.push_back( + new SwXTextPortion(pUnoCrsr, xParent, PORTION_SOFT_PAGEBREAK) ); + rBreakArr.erase( aIter++ ); + } +} + +#define REDLINE_PORTION_START_REMOVE 0//removed redlines are visible +#define REDLINE_PORTION_END_REMOVE 1//removed redlines are visible +#define REDLINE_PORTION_REMOVE 2//removed redlines are NOT visible +#define REDLINE_PORTION_INSERT_START 3 +#define REDLINE_PORTION_INSERT_END 4 + +struct SwXRedlinePortion_Impl +{ + const SwRedline* m_pRedline; + const bool m_bStart; + + SwXRedlinePortion_Impl ( const SwRedline* pRed, const bool bIsStart ) + : m_pRedline(pRed) + , m_bStart(bIsStart) + { + } + + sal_uLong getRealIndex () + { + return m_bStart ? m_pRedline->Start()->nContent.GetIndex() + : m_pRedline->End() ->nContent.GetIndex(); + } +}; + +typedef boost::shared_ptr < SwXRedlinePortion_Impl > + SwXRedlinePortion_ImplSharedPtr; + +struct RedlineCompareStruct +{ + const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r ) + { + return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End()); + } + + bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1, + const SwXRedlinePortion_ImplSharedPtr &r2 ) + { + return getPosition ( r1 ) < getPosition ( r2 ); + } +}; + +typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct > +SwXRedlinePortion_ImplList; + +static Reference<XTextRange> +lcl_ExportHints( + PortionStack_t & rPortionStack, + const Reference<XText> & xParent, + SwUnoCrsr * const pUnoCrsr, + SwpHints * const pHints, + const sal_Int32 i_nStartPos, + const sal_Int32 i_nEndPos, + const xub_StrLen nCurrentIndex, + const bool bRightMoveForbidden, + bool & o_rbCursorMoved, + sal_Int32 & o_rNextAttrPosition ) +{ + // if the attribute has a dummy character, then xRef is set (except META) + // otherwise, the portion for the attribute is inserted into rPortions! + Reference<XTextRange> xRef; + SwDoc* pDoc = pUnoCrsr->GetDoc(); + //search for special text attributes - first some ends + sal_uInt16 nEndIndex = 0; + sal_uInt16 nNextEnd = 0; + while(nEndIndex < pHints->GetEndCount() && + (!pHints->GetEnd(nEndIndex)->GetEnd() || + nCurrentIndex >= (nNextEnd = (*pHints->GetEnd(nEndIndex)->GetEnd())))) + { + if(pHints->GetEnd(nEndIndex)->GetEnd()) + { + SwTxtAttr * const pAttr = pHints->GetEnd(nEndIndex); + if (nNextEnd == nCurrentIndex) + { + const sal_uInt16 nWhich( pAttr->Which() ); + switch (nWhich) + { + case RES_TXTATR_TOXMARK: + { + Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion( + xParent, pUnoCrsr, *pAttr, true); + rPortionStack.top().first->push_back(xTmp); + } + break; + case RES_TXTATR_REFMARK: + { + Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion( + xParent, pUnoCrsr, *pAttr, true); + rPortionStack.top().first->push_back(xTmp); + } + break; + case RES_TXTATR_CJK_RUBY: + //#i91534# GetEnd() == 0 mixes the order of ruby start/end + if( *pAttr->GetEnd() == *pAttr->GetStart()) + { + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCrsr, *pAttr, sal_False); + } + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCrsr, *pAttr, sal_True); + break; + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + { + OSL_ENSURE(*pAttr->GetStart() != *pAttr->GetEnd(), + "empty meta?"); + if ((i_nStartPos > 0) && + (*pAttr->GetStart() < i_nStartPos)) + { + // force skip pAttr and rest of attribute ends + // at nCurrentIndex + // because they are not contained in the meta pAttr + // and the meta pAttr itself is outside selection! + // (necessary for SwXMeta::createEnumeration) + if (*pAttr->GetStart() + 1 == i_nStartPos) + { + nEndIndex = pHints->GetEndCount() - 1; + } + break; + } + PortionList_t Top = rPortionStack.top(); + if (Top.second != pAttr) + { + OSL_FAIL("ExportHints: stack error" ); + } + else + { + ::std::auto_ptr<const TextRangeList_t> + pCurrentPortions(Top.first); + rPortionStack.pop(); + const uno::Reference<text::XTextRange> xPortion( + lcl_CreateMetaPortion(xParent, pUnoCrsr, + *pAttr, pCurrentPortions)); + rPortionStack.top().first->push_back(xPortion); + } + } + break; + } + } + } + nEndIndex++; + } + + // then some starts + sal_uInt16 nStartIndex = 0; + sal_uInt16 nNextStart = 0; + while(nStartIndex < pHints->GetStartCount() && + nCurrentIndex >= (nNextStart = (*pHints->GetStart(nStartIndex)->GetStart()))) + { + SwTxtAttr * const pAttr = pHints->GetStart(nStartIndex); + sal_uInt16 nAttrWhich = pAttr->Which(); + if (nNextStart == nCurrentIndex) + { + switch( nAttrWhich ) + { + case RES_TXTATR_FIELD: + if(!bRightMoveForbidden) + { + pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False); + if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() ) + break; + SwXTextPortion* pPortion; + xRef = pPortion = new SwXTextPortion( + pUnoCrsr, xParent, PORTION_FIELD); + Reference<XTextField> xField = + SwXTextField::CreateSwXTextField(*pDoc, pAttr->GetFld()); + pPortion->SetTextField(xField); + } + break; + case RES_TXTATR_FLYCNT : + if(!bRightMoveForbidden) + { + pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False); + if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() ) + break; // Robust #i81708 content in covered cells + pUnoCrsr->Exchange(); + xRef = new SwXTextPortion( + pUnoCrsr, xParent, PORTION_FRAME); + } + break; + case RES_TXTATR_FTN : + { + if(!bRightMoveForbidden) + { + pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False); + if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() ) + break; + SwXTextPortion* pPortion; + xRef = pPortion = new SwXTextPortion( + pUnoCrsr, xParent, PORTION_FOOTNOTE); + Reference<XFootnote> xContent = + SwXFootnotes::GetObject(*pDoc, pAttr->GetFtn()); + pPortion->SetFootnote(xContent); + } + } + break; + case RES_TXTATR_TOXMARK: + case RES_TXTATR_REFMARK: + { + bool bIsPoint = !(pAttr->GetEnd()); + if (!bRightMoveForbidden || !bIsPoint) + { + if (bIsPoint) + { + pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False); + } + Reference<XTextRange> xTmp = + (RES_TXTATR_REFMARK == nAttrWhich) + ? lcl_CreateRefMarkPortion( + xParent, pUnoCrsr, *pAttr, false) + : lcl_CreateTOXMarkPortion( + xParent, pUnoCrsr, *pAttr, false); + if (bIsPoint) // consume CH_TXTATR! + { + pUnoCrsr->Normalize(sal_False); + pUnoCrsr->DeleteMark(); + xRef = xTmp; + } + else // just insert it + { + rPortionStack.top().first->push_back(xTmp); + } + } + } + break; + case RES_TXTATR_CJK_RUBY: + //#i91534# GetEnd() == 0 mixes the order of ruby start/end + if(pAttr->GetEnd() && (*pAttr->GetEnd() != *pAttr->GetStart())) + { + lcl_InsertRubyPortion( *rPortionStack.top().first, + xParent, pUnoCrsr, *pAttr, sal_False); + } + break; + case RES_TXTATR_META: + case RES_TXTATR_METAFIELD: + if (*pAttr->GetStart() != *pAttr->GetEnd()) + { + if (!bRightMoveForbidden) + { + pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False); + o_rbCursorMoved = true; + // only if the end is included in selection! + if ((i_nEndPos < 0) || + (*pAttr->GetEnd() <= i_nEndPos)) + { + rPortionStack.push( ::std::make_pair( + new TextRangeList_t, pAttr )); + } + } + } + break; + case RES_TXTATR_AUTOFMT: + case RES_TXTATR_INETFMT: + case RES_TXTATR_CHARFMT: + break; // these are handled as properties of a "Text" portion + default: + OSL_FAIL("unknown attribute"); + break; + } + } + nStartIndex++; + } + + if (xRef.is()) // implies that we have moved the cursor + { + o_rbCursorMoved = true; + } + if (!o_rbCursorMoved) + { + // search for attribute changes behind the current cursor position + // break up at frames, bookmarks, redlines + + nStartIndex = 0; + nNextStart = 0; + while(nStartIndex < pHints->GetStartCount() && + nCurrentIndex >= (nNextStart = (*pHints->GetStart(nStartIndex)->GetStart()))) + nStartIndex++; + + nEndIndex = 0; + nNextEnd = 0; + while(nEndIndex < pHints->GetEndCount() && + nCurrentIndex >= (nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd()))) + nEndIndex++; + + sal_Int32 nNextPos = + ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd)) + ? nNextStart : nNextEnd; + if (nNextPos > nCurrentIndex) + { + o_rNextAttrPosition = nNextPos; + } + } + return xRef; +} + +void lcl_MoveCursor( SwUnoCrsr * const pUnoCrsr, + const xub_StrLen nCurrentIndex, + const sal_Int32 nNextFrameIndex, const sal_Int32 nNextPortionIndex, + const sal_Int32 nNextAttrIndex, const sal_Int32 nNextFieldMarkIndex, + const sal_Int32 nEndPos ) +{ + sal_Int32 nMovePos = pUnoCrsr->GetCntntNode()->Len(); + + if ((nEndPos >= 0) && (nEndPos < nMovePos)) + { + nMovePos = nEndPos; + } + + if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos)) + { + nMovePos = nNextFrameIndex; + } + + if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos)) + { + nMovePos = nNextPortionIndex; + } + + if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos)) + { + nMovePos = nNextAttrIndex; + } + + if ((nNextFieldMarkIndex >= 0) && (nNextFieldMarkIndex < nMovePos)) + { + nMovePos = nNextFieldMarkIndex; + } + + if (nMovePos > nCurrentIndex) + { +// pUnoCrsr->Right(nMovePos - nCurrentIndex); + pUnoCrsr->GetPoint()->nContent = static_cast<sal_uInt16>(nMovePos); + } +} + +static void +lcl_FillRedlineArray(SwDoc const & rDoc, SwUnoCrsr const & rUnoCrsr, + SwXRedlinePortion_ImplList& rRedArr ) +{ + const SwRedlineTbl& rRedTbl = rDoc.GetRedlineTbl(); + sal_uInt16 nRedTblCount = rRedTbl.Count(); + + if ( nRedTblCount > 0 ) + { + const SwPosition* pStart = rUnoCrsr.GetPoint(); + const SwNodeIndex nOwnNode = pStart->nNode; + + for(sal_uInt16 nRed = 0; nRed < nRedTblCount; nRed++) + { + const SwRedline* pRedline = rRedTbl[nRed]; + const SwPosition* pRedStart = pRedline->Start(); + const SwNodeIndex nRedNode = pRedStart->nNode; + if ( nOwnNode == nRedNode ) + rRedArr.insert( SwXRedlinePortion_ImplSharedPtr ( + new SwXRedlinePortion_Impl ( pRedline, true ) ) ); + if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode ) + rRedArr.insert( SwXRedlinePortion_ImplSharedPtr ( + new SwXRedlinePortion_Impl ( pRedline, false) ) ); + } + } +} + +static void +lcl_FillSoftPageBreakArray( + SwUnoCrsr const & rUnoCrsr, SwSoftPageBreakList& rBreakArr ) +{ + const SwTxtNode *pTxtNode = + rUnoCrsr.GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTxtNode ) + pTxtNode->fillSoftPageBreakList( rBreakArr ); +} + +static void +lcl_ExportRedline( + TextRangeList_t & rPortions, + Reference<XText> const& xParent, + const SwUnoCrsr * const pUnoCrsr, + SwXRedlinePortion_ImplList& rRedlineArr, const sal_uLong nIndex) +{ + + // MTG: 23/11/05: We want this loop to iterate over all red lines in this + // array. We will only insert the ones with index matches + for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end(); + aIter != aEnd; ) + { + SwXRedlinePortion_ImplSharedPtr pPtr = (*aIter ); + sal_uLong nRealIndex = pPtr->getRealIndex(); + // MTG: 23/11/05: If there are elements before nIndex, remove them + if ( nIndex > nRealIndex ) + rRedlineArr.erase ( aIter++ ); + // MTG: 23/11/05: If the elements match, and them to the list + else if ( nIndex == nRealIndex ) + { + rPortions.push_back( new SwXRedlinePortion( + pPtr->m_pRedline, pUnoCrsr, xParent, pPtr->m_bStart) ); + rRedlineArr.erase ( aIter++ ); + } + // MTG: 23/11/05: If we've iterated past nIndex, exit the loop + else + break; + } +} + +static void +lcl_ExportBkmAndRedline( + TextRangeList_t & rPortions, + Reference<XText> const & xParent, + const SwUnoCrsr * const pUnoCrsr, + SwXBookmarkPortion_ImplList& rBkmArr, + SwXRedlinePortion_ImplList& rRedlineArr, + SwSoftPageBreakList& rBreakArr, + const sal_uLong nIndex) +{ + if (rBkmArr.size()) + lcl_ExportBookmark(rPortions, xParent, pUnoCrsr, rBkmArr, nIndex); + + if (rRedlineArr.size()) + lcl_ExportRedline(rPortions, xParent, pUnoCrsr, rRedlineArr, nIndex); + + if (rBreakArr.size()) + lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCrsr, rBreakArr, nIndex); +} + +static sal_Int32 +lcl_ExportFrames( + TextRangeList_t & rPortions, + Reference<XText> const & i_xParent, + SwUnoCrsr * const i_pUnoCrsr, + FrameDependSortList_t & i_rFrames, + xub_StrLen const i_nCurrentIndex) +{ + // find first Frame in (sorted) i_rFrames at current position + while (i_rFrames.size() && (i_rFrames.front().nIndex == i_nCurrentIndex)) + // do not check for i_nEnd here; this is done implicity by lcl_MoveCursor + { + const SwModify * const pFrame = + i_rFrames.front().pFrameDepend->GetRegisteredIn(); + if (pFrame) // Frame could be disposed + { + SwXTextPortion* pPortion = new SwXTextPortion(i_pUnoCrsr, i_xParent, + *static_cast<SwFrmFmt*>( const_cast<SwModify*>( pFrame ) ) ); + rPortions.push_back(pPortion); + } + i_rFrames.pop_front(); + } + + return i_rFrames.size() ? i_rFrames.front().nIndex : -1; +} + +static sal_Int32 +lcl_GetNextIndex( + SwXBookmarkPortion_ImplList const & rBkmArr, + SwXRedlinePortion_ImplList const & rRedlineArr, + SwSoftPageBreakList const & rBreakArr ) +{ + sal_Int32 nRet = -1; + if(rBkmArr.size()) + { + SwXBookmarkPortion_ImplSharedPtr pPtr = (*rBkmArr.begin()); + nRet = pPtr->getIndex(); + } + if(rRedlineArr.size()) + { + SwXRedlinePortion_ImplSharedPtr pPtr = (*rRedlineArr.begin()); + sal_Int32 nTmp = pPtr->getRealIndex(); + if(nRet < 0 || nTmp < nRet) + nRet = nTmp; + } + if(rBreakArr.size()) + { + if(nRet < 0 || *rBreakArr.begin() < static_cast<sal_uInt32>(nRet)) + nRet = *rBreakArr.begin(); + } + return nRet; +}; + +static void +lcl_CreatePortions( + TextRangeList_t & i_rPortions, + uno::Reference< text::XText > const & i_xParentText, + SwUnoCrsr * const pUnoCrsr, + FrameDependSortList_t & i_rFrames, + const sal_Int32 i_nStartPos, + const sal_Int32 i_nEndPos ) +{ + if (!pUnoCrsr) + return; + + // set the start if a selection should be exported + if ((i_nStartPos > 0) && + (pUnoCrsr->Start()->nContent.GetIndex() != i_nStartPos)) + { + pUnoCrsr->DeleteMark(); + DBG_ASSERT(pUnoCrsr->Start()->nNode.GetNode().GetTxtNode() && + (i_nStartPos <= pUnoCrsr->Start()->nNode.GetNode().GetTxtNode()-> + GetTxt().Len()), "Incorrect start position" ); + // ??? should this be i_nStartPos - current position ? + pUnoCrsr->Right(static_cast<xub_StrLen>(i_nStartPos), + CRSR_SKIP_CHARS, sal_False, sal_False); + } + + FieldMarks_t FieldMarks; + SwXBookmarkPortion_ImplList Bookmarks; + SwXRedlinePortion_ImplList Redlines; + SwSoftPageBreakList SoftPageBreaks; + + SwDoc * const pDoc = pUnoCrsr->GetDoc(); + lcl_FillFieldMarkArray(FieldMarks, *pUnoCrsr, i_nStartPos); + lcl_FillBookmarkArray(*pDoc, *pUnoCrsr, Bookmarks); + lcl_FillRedlineArray(*pDoc, *pUnoCrsr, Redlines); + lcl_FillSoftPageBreakArray(*pUnoCrsr, SoftPageBreaks); + + PortionStack_t PortionStack; + PortionStack.push( PortionList_t(&i_rPortions, 0) ); + + bool bAtEnd( false ); + while (!bAtEnd) // every iteration consumes at least current character! + { + if (pUnoCrsr->HasMark()) + { + pUnoCrsr->Normalize(sal_False); + pUnoCrsr->DeleteMark(); + } + + SwTxtNode * const pTxtNode = pUnoCrsr->GetNode()->GetTxtNode(); + if (!pTxtNode) + { + OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?"); + return; + } + + SwpHints * const pHints = pTxtNode->GetpSwpHints(); + const xub_StrLen nCurrentIndex = + pUnoCrsr->GetPoint()->nContent.GetIndex(); + // this contains the portion which consumes the character in the + // text at nCurrentIndex; i.e. it must be set _once_ per iteration + uno::Reference< XTextRange > xRef; + + SwUnoCursorHelper::SelectPam(*pUnoCrsr, true); // set mark + + const sal_Int32 nFirstFrameIndex = + lcl_ExportFrames( *PortionStack.top().first, + i_xParentText, pUnoCrsr, i_rFrames, nCurrentIndex); + + lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, + pUnoCrsr, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex ); + + bool bCursorMoved( false ); + sal_Int32 nNextAttrIndex = -1; + // #111716# the cursor must not move right at the + // end position of a selection! + bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos)) + || (nCurrentIndex >= pTxtNode->Len()); + if (pHints) + { + // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor + xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCrsr, + pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd, + bCursorMoved, nNextAttrIndex); + if (PortionStack.empty()) + { + OSL_FAIL("CreatePortions: stack underflow"); + return; + } + } + + if (!xRef.is() && !bCursorMoved) + { + if (!bAtEnd && + FieldMarks.size() && (FieldMarks.front() == nCurrentIndex)) + { + // moves cursor + xRef = lcl_ExportFieldMark(i_xParentText, pUnoCrsr, pTxtNode); + FieldMarks.pop_front(); + } + } + else + { + OSL_ENSURE(!FieldMarks.size() || + (FieldMarks.front() != nCurrentIndex), + "fieldmark and hint with CH_TXTATR at same pos?"); + } + + if (!bAtEnd && !xRef.is() && !bCursorMoved) + { + const sal_Int32 nNextPortionIndex = + lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks); + const sal_Int32 nNextFieldMarkIndex( + FieldMarks.size() ? FieldMarks.front() : -1); + + lcl_MoveCursor(pUnoCrsr, nCurrentIndex, + nFirstFrameIndex, nNextPortionIndex, nNextAttrIndex, + nNextFieldMarkIndex, + i_nEndPos); + + xRef = new SwXTextPortion(pUnoCrsr, i_xParentText, PORTION_TEXT); + } + else if (bAtEnd && !xRef.is() && !pTxtNode->Len()) + { + // special case: for an empty paragraph, we better put out a + // text portion because there may be a hyperlink attribute + xRef = new SwXTextPortion(pUnoCrsr, i_xParentText, PORTION_TEXT); + } + + if (xRef.is()) + { + PortionStack.top().first->push_back(xRef); + } + } + + OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second, + "CreatePortions: stack error" ); +} + +void SwXTextPortionEnumeration::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) +{ + ClientModify(this, pOld, pNew); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |