summaryrefslogtreecommitdiff
path: root/vcl/source/edit/textdoc.cxx
diff options
context:
space:
mode:
authorZolnai Tamás <zolniatamas@caesar.elte.hu>2012-08-06 20:52:37 +0200
committerMiklos Vajna <vmiklos@suse.cz>2012-08-07 10:50:23 +0200
commit2854d8b17cb873a5d61e06f9570ac344f054d666 (patch)
tree2d48cc3b620c25c4d894716d4470b4eefc8a86dd /vcl/source/edit/textdoc.cxx
parent13b9c0513319623fd56a5a0ead5bdddecf90a10f (diff)
fdo#46193 MessBox was made copyable
Part of MultiLineEdit was moved down from stvools to vcl with name VCLMultiLineEdit. MessBox uses it to display the message in read-only mode. Some of svtools' classes - which are necessary to implement VCLMultiLineEdit - were moved to vcl as a whole, and their includes are rewrite. Note: ExtTextView and ExtTextEngine classes would be leaved in svtools if VCLMultiLineEdit is a template class, but two macros: IMPL_LINK end IMPL_LINK_NOARG make it impossible to use template syntax. Change-Id: I26543868d8081c225c7125404d23369de3c3afcd
Diffstat (limited to 'vcl/source/edit/textdoc.cxx')
-rw-r--r--vcl/source/edit/textdoc.cxx636
1 files changed, 636 insertions, 0 deletions
diff --git a/vcl/source/edit/textdoc.cxx b/vcl/source/edit/textdoc.cxx
new file mode 100644
index 000000000000..a8062ecefbf3
--- /dev/null
+++ b/vcl/source/edit/textdoc.cxx
@@ -0,0 +1,636 @@
+/* -*- 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.
+ *
+ ************************************************************************/
+
+#include <textdoc.hxx>
+
+#include <stdlib.h>
+
+
+
+// Vergleichmethode wird von QuickSort gerufen...
+
+static bool CompareStart( const TextCharAttrib* pFirst, const TextCharAttrib* pSecond )
+{
+ return pFirst->GetStart() < pSecond->GetStart();
+}
+
+// -------------------------------------------------------------------------
+// (+) class TextCharAttrib
+// -------------------------------------------------------------------------
+TextCharAttrib::TextCharAttrib( const TextAttrib& rAttr, sal_uInt16 nStart, sal_uInt16 nEnd )
+{
+ mpAttr = rAttr.Clone();
+ mnStart = nStart,
+ mnEnd = nEnd;
+}
+
+TextCharAttrib::TextCharAttrib( const TextCharAttrib& rTextCharAttrib )
+{
+ mpAttr = rTextCharAttrib.GetAttr().Clone();
+ mnStart = rTextCharAttrib.mnStart;
+ mnEnd = rTextCharAttrib.mnEnd;
+}
+
+TextCharAttrib::~TextCharAttrib()
+{
+ delete mpAttr;
+}
+
+// -------------------------------------------------------------------------
+// (+) class TextCharAttribList
+// -------------------------------------------------------------------------
+
+TextCharAttribList::TextCharAttribList()
+{
+ mbHasEmptyAttribs = sal_False;
+}
+
+TextCharAttribList::~TextCharAttribList()
+{
+ // PTRARR_DEL
+}
+
+void TextCharAttribList::Clear( sal_Bool bDestroyAttribs )
+{
+ if ( bDestroyAttribs )
+ for(iterator it = begin(); it != end(); ++it)
+ delete *it;
+ TextCharAttribs::clear();
+}
+
+
+void TextCharAttribList::InsertAttrib( TextCharAttrib* pAttrib )
+{
+ if ( pAttrib->IsEmpty() )
+ mbHasEmptyAttribs = sal_True;
+
+ const sal_uInt16 nCount = size();
+ const sal_uInt16 nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt.
+ sal_Bool bInserted = sal_False;
+ for ( sal_uInt16 x = 0; x < nCount; x++ )
+ {
+ TextCharAttrib* pCurAttrib = GetAttrib( x );
+ if ( pCurAttrib->GetStart() > nStart )
+ {
+ insert( begin() + x, pAttrib );
+ bInserted = sal_True;
+ break;
+ }
+ }
+ if ( !bInserted )
+ push_back( pAttrib );
+}
+
+void TextCharAttribList::ResortAttribs()
+{
+ if ( !empty() )
+ std::sort( begin(), end(), CompareStart );
+}
+
+TextCharAttrib* TextCharAttribList::FindAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
+{
+ // Rueckwaerts, falls eins dort endet, das naechste startet.
+ // => Das startende gilt...
+
+ for ( sal_uInt16 nAttr = size(); nAttr; )
+ {
+ TextCharAttrib* pAttr = GetAttrib( --nAttr );
+
+ if ( pAttr->GetEnd() < nPos )
+ return 0;
+
+ if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) )
+ return pAttr;
+ }
+ return NULL;
+}
+
+TextCharAttrib* TextCharAttribList::FindNextAttrib( sal_uInt16 nWhich, sal_uInt16 nFromPos, sal_uInt16 nMaxPos ) const
+{
+ DBG_ASSERT( nWhich, "FindNextAttrib: Which?" );
+ const sal_uInt16 nAttribs = size();
+ for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetAttrib( nAttr );
+ if ( ( pAttr->GetStart() >= nFromPos ) &&
+ ( pAttr->GetEnd() <= nMaxPos ) &&
+ ( pAttr->Which() == nWhich ) )
+ return pAttr;
+ }
+ return NULL;
+}
+
+sal_Bool TextCharAttribList::HasAttrib( sal_uInt16 nWhich ) const
+{
+ for ( sal_uInt16 nAttr = size(); nAttr; )
+ {
+ const TextCharAttrib* pAttr = GetAttrib( --nAttr );
+ if ( pAttr->Which() == nWhich )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+sal_Bool TextCharAttribList::HasBoundingAttrib( sal_uInt16 nBound )
+{
+ // Rueckwaerts, falls eins dort endet, das naechste startet.
+ // => Das startende gilt...
+ for ( sal_uInt16 nAttr = size(); nAttr; )
+ {
+ TextCharAttrib* pAttr = GetAttrib( --nAttr );
+
+ if ( pAttr->GetEnd() < nBound )
+ return sal_False;
+
+ if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) )
+ return sal_True;
+ }
+ return sal_False;
+}
+
+TextCharAttrib* TextCharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_uInt16 nPos )
+{
+ if ( !mbHasEmptyAttribs )
+ return 0;
+
+ const sal_uInt16 nAttribs = size();
+ for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetAttrib( nAttr );
+ if ( pAttr->GetStart() > nPos )
+ return 0;
+
+ if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) )
+ return pAttr;
+ }
+ return 0;
+}
+
+void TextCharAttribList::DeleteEmptyAttribs()
+{
+ for ( sal_uInt16 nAttr = 0; nAttr < size(); nAttr++ )
+ {
+ TextCharAttrib* pAttr = GetAttrib( nAttr );
+ if ( pAttr->IsEmpty() )
+ {
+ erase( begin() + nAttr );
+ delete pAttr;
+ nAttr--;
+ }
+ }
+ mbHasEmptyAttribs = sal_False;
+}
+
+// -------------------------------------------------------------------------
+// (+) class TextNode
+// -------------------------------------------------------------------------
+
+TextNode::TextNode( const String& rText ) :
+ maText( rText )
+{
+}
+
+void TextNode::ExpandAttribs( sal_uInt16 nIndex, sal_uInt16 nNew )
+{
+ if ( !nNew )
+ return;
+
+ sal_Bool bResort = sal_False;
+ sal_uInt16 nAttribs = maCharAttribs.Count();
+ for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ if ( pAttrib->GetEnd() >= nIndex )
+ {
+ // Alle Attribute hinter der Einfuegeposition verschieben...
+ if ( pAttrib->GetStart() > nIndex )
+ {
+ pAttrib->MoveForward( nNew );
+ }
+ // 0: Leeres Attribut expandieren, wenn an Einfuegestelle
+ else if ( pAttrib->IsEmpty() )
+ {
+ // Index nicht pruefen, leeres durfte nur dort liegen.
+ // Wenn spaeter doch Ueberpruefung:
+ // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch!
+ // Start <= nIndex, End >= nIndex => Start=End=nIndex!
+// if ( pAttrib->GetStart() == nIndex )
+ pAttrib->Expand( nNew );
+ }
+ // 1: Attribut startet davor, geht bis Index...
+ else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen
+ {
+ // Nur expandieren, wenn kein Feature,
+ // und wenn nicht in ExcludeListe!
+ // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren
+ if ( !maCharAttribs.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
+ {
+ pAttrib->Expand( nNew );
+ }
+ else
+ bResort = sal_True;
+ }
+ // 2: Attribut startet davor, geht hinter Index...
+ else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
+ {
+ pAttrib->Expand( nNew );
+ }
+ // 3: Attribut startet auf Index...
+ else if ( pAttrib->GetStart() == nIndex )
+ {
+ if ( nIndex == 0 )
+ {
+ pAttrib->Expand( nNew );
+// bResort = sal_True; // es gibt ja keine Features mehr...
+ }
+ else
+ pAttrib->MoveForward( nNew );
+ }
+ }
+
+ DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" );
+ DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len() ), "Expand: Attrib groesser als Absatz!" );
+ DBG_ASSERT( !pAttrib->IsEmpty(), "Leeres Attribut nach ExpandAttribs?" );
+ }
+
+ if ( bResort )
+ maCharAttribs.ResortAttribs();
+}
+
+void TextNode::CollapsAttribs( sal_uInt16 nIndex, sal_uInt16 nDeleted )
+{
+ if ( !nDeleted )
+ return;
+
+ sal_Bool bResort = sal_False;
+ sal_uInt16 nEndChanges = nIndex+nDeleted;
+
+ for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ sal_Bool bDelAttr = sal_False;
+ if ( pAttrib->GetEnd() >= nIndex )
+ {
+ // Alles Attribute hinter der Einfuegeposition verschieben...
+ if ( pAttrib->GetStart() >= nEndChanges )
+ {
+ pAttrib->MoveBackward( nDeleted );
+ }
+ // 1. Innenliegende Attribute loeschen...
+ else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) )
+ {
+ // Spezialfall: Attrubt deckt genau den Bereich ab
+ // => als leeres Attribut behalten.
+ if ( ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) )
+ pAttrib->GetEnd() = nIndex; // leer
+ else
+ bDelAttr = sal_True;
+ }
+ // 2. Attribut beginnt davor, endet drinnen oder dahinter...
+ else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) )
+ {
+ if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen
+ pAttrib->GetEnd() = nIndex;
+ else
+ pAttrib->Collaps( nDeleted ); // endet dahinter
+ }
+ // 3. Attribut beginnt drinnen, endet dahinter...
+ else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) )
+ {
+ // Features duerfen nicht expandieren!
+ pAttrib->GetStart() = nEndChanges;
+ pAttrib->MoveBackward( nDeleted );
+ }
+ }
+
+ DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" );
+ DBG_ASSERT( ( pAttrib->GetEnd() <= maText.Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" );
+ if ( bDelAttr /* || pAttrib->IsEmpty() */ )
+ {
+ bResort = sal_True;
+ maCharAttribs.RemoveAttrib( nAttr );
+ delete pAttrib;
+ nAttr--;
+ }
+ else if ( pAttrib->IsEmpty() )
+ maCharAttribs.HasEmptyAttribs() = sal_True;
+ }
+
+ if ( bResort )
+ maCharAttribs.ResortAttribs();
+}
+
+void TextNode::InsertText( sal_uInt16 nPos, const String& rText )
+{
+ maText.Insert( rText, nPos );
+ ExpandAttribs( nPos, rText.Len() );
+}
+
+void TextNode::InsertText( sal_uInt16 nPos, sal_Unicode c )
+{
+ maText.Insert( c, nPos );
+ ExpandAttribs( nPos, 1 );
+}
+
+void TextNode::RemoveText( sal_uInt16 nPos, sal_uInt16 nChars )
+{
+ maText.Erase( nPos, nChars );
+ CollapsAttribs( nPos, nChars );
+}
+
+TextNode* TextNode::Split( sal_uInt16 nPos, sal_Bool bKeepEndingAttribs )
+{
+ String aNewText;
+ if ( nPos < maText.Len() )
+ {
+ aNewText = maText.Copy( nPos );
+ maText.Erase( nPos );
+ }
+ TextNode* pNew = new TextNode( aNewText );
+
+ for ( sal_uInt16 nAttr = 0; nAttr < maCharAttribs.Count(); nAttr++ )
+ {
+ TextCharAttrib* pAttrib = maCharAttribs.GetAttrib( nAttr );
+ if ( pAttrib->GetEnd() < nPos )
+ {
+ // bleiben unveraendert....
+ ;
+ }
+ else if ( pAttrib->GetEnd() == nPos )
+ {
+ // muessen als leeres Attribut kopiert werden.
+ // !FindAttrib nur sinnvoll, wenn Rueckwaerts durch Liste!
+ if ( bKeepEndingAttribs && !pNew->maCharAttribs.FindAttrib( pAttrib->Which(), 0 ) )
+ {
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = 0;
+ pNewAttrib->GetEnd() = 0;
+ pNew->maCharAttribs.InsertAttrib( pNewAttrib );
+ }
+ }
+ else if ( pAttrib->IsInside( nPos ) || ( !nPos && !pAttrib->GetStart() ) )
+ {
+ // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben!
+ // muessen kopiert und geaendert werden
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = 0;
+ pNewAttrib->GetEnd() = pAttrib->GetEnd()-nPos;
+ pNew->maCharAttribs.InsertAttrib( pNewAttrib );
+ // stutzen:
+ pAttrib->GetEnd() = nPos;
+ }
+ else
+ {
+ DBG_ASSERT( pAttrib->GetStart() >= nPos, "Start < nPos!" );
+ DBG_ASSERT( pAttrib->GetEnd() >= nPos, "End < nPos!" );
+ // alle dahinter verschieben in den neuen Node (this)
+ maCharAttribs.RemoveAttrib( nAttr );
+ pNew->maCharAttribs.InsertAttrib( pAttrib );
+ pAttrib->GetStart() = pAttrib->GetStart() - nPos;
+ pAttrib->GetEnd() = pAttrib->GetEnd() - nPos;
+ nAttr--;
+ }
+ }
+ return pNew;
+}
+
+void TextNode::Append( const TextNode& rNode )
+{
+ sal_uInt16 nOldLen = maText.Len();
+
+ maText += rNode.GetText();
+
+ const sal_uInt16 nAttribs = rNode.GetCharAttribs().Count();
+ for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
+ {
+ TextCharAttrib* pAttrib = rNode.GetCharAttribs().GetAttrib( nAttr );
+ sal_Bool bMelted = sal_False;
+ if ( pAttrib->GetStart() == 0 )
+ {
+ // Evtl koennen Attribute zusammengefasst werden:
+ sal_uInt16 nTmpAttribs = maCharAttribs.Count();
+ for ( sal_uInt16 nTmpAttr = 0; nTmpAttr < nTmpAttribs; nTmpAttr++ )
+ {
+ TextCharAttrib* pTmpAttrib = maCharAttribs.GetAttrib( nTmpAttr );
+
+ if ( pTmpAttrib->GetEnd() == nOldLen )
+ {
+ if ( ( pTmpAttrib->Which() == pAttrib->Which() ) &&
+ ( pTmpAttrib->GetAttr() == pAttrib->GetAttr() ) )
+ {
+ pTmpAttrib->GetEnd() =
+ pTmpAttrib->GetEnd() + pAttrib->GetLen();
+ bMelted = sal_True;
+ break; // es kann nur eins von der Sorte an der Stelle geben
+ }
+ }
+ }
+ }
+
+ if ( !bMelted )
+ {
+ TextCharAttrib* pNewAttrib = new TextCharAttrib( *pAttrib );
+ pNewAttrib->GetStart() = pNewAttrib->GetStart() + nOldLen;
+ pNewAttrib->GetEnd() = pNewAttrib->GetEnd() + nOldLen;
+ maCharAttribs.InsertAttrib( pNewAttrib );
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+// (+) class TextDoc
+// -------------------------------------------------------------------------
+
+TextDoc::TextDoc()
+{
+ mnLeftMargin = 0;
+};
+
+TextDoc::~TextDoc()
+{
+ DestroyTextNodes();
+}
+
+void TextDoc::Clear()
+{
+ DestroyTextNodes();
+}
+
+void TextDoc::DestroyTextNodes()
+{
+ for ( sal_uLong nNode = 0; nNode < maTextNodes.Count(); nNode++ )
+ delete maTextNodes.GetObject( nNode );
+ maTextNodes.clear();
+}
+
+String TextDoc::GetText( const sal_Unicode* pSep ) const
+{
+ sal_uLong nLen = GetTextLen( pSep );
+ sal_uLong nNodes = maTextNodes.Count();
+
+ if ( nLen > STRING_MAXLEN )
+ {
+ OSL_FAIL( "Text zu gross fuer String" );
+ return String();
+ }
+
+ String aASCIIText;
+ sal_uLong nLastNode = nNodes-1;
+ for ( sal_uLong nNode = 0; nNode < nNodes; nNode++ )
+ {
+ TextNode* pNode = maTextNodes.GetObject( nNode );
+ String aTmp( pNode->GetText() );
+ aASCIIText += aTmp;
+ if ( pSep && ( nNode != nLastNode ) )
+ aASCIIText += pSep;
+ }
+
+ return aASCIIText;
+}
+
+XubString TextDoc::GetText( sal_uLong nPara ) const
+{
+ XubString aText;
+ TextNode* pNode = ( nPara < maTextNodes.Count() ) ? maTextNodes.GetObject( nPara ) : 0;
+ if ( pNode )
+ aText = pNode->GetText();
+
+ return aText;
+}
+
+
+sal_uLong TextDoc::GetTextLen( const xub_Unicode* pSep, const TextSelection* pSel ) const
+{
+ sal_uLong nLen = 0;
+ sal_uLong nNodes = maTextNodes.Count();
+ if ( nNodes )
+ {
+ sal_uLong nStartNode = 0;
+ sal_uLong nEndNode = nNodes-1;
+ if ( pSel )
+ {
+ nStartNode = pSel->GetStart().GetPara();
+ nEndNode = pSel->GetEnd().GetPara();
+ }
+
+ for ( sal_uLong nNode = nStartNode; nNode <= nEndNode; nNode++ )
+ {
+ TextNode* pNode = maTextNodes.GetObject( nNode );
+
+ sal_uInt16 nS = 0;
+ sal_uLong nE = pNode->GetText().Len();
+ if ( pSel && ( nNode == pSel->GetStart().GetPara() ) )
+ nS = pSel->GetStart().GetIndex();
+ if ( pSel && ( nNode == pSel->GetEnd().GetPara() ) )
+ nE = pSel->GetEnd().GetIndex();
+
+ nLen += ( nE - nS );
+ }
+
+ if ( pSep )
+ nLen += (nEndNode-nStartNode) * rtl_ustr_getLength(pSep);
+ }
+
+ return nLen;
+}
+
+TextPaM TextDoc::InsertText( const TextPaM& rPaM, xub_Unicode c )
+{
+ DBG_ASSERT( c != 0x0A, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+ DBG_ASSERT( c != 0x0D, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->InsertText( rPaM.GetIndex(), c );
+
+ TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+1 );
+ return aPaM;
+}
+
+TextPaM TextDoc::InsertText( const TextPaM& rPaM, const XubString& rStr )
+{
+ DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+ DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "TextDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" );
+
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->InsertText( rPaM.GetIndex(), rStr );
+
+ TextPaM aPaM( rPaM.GetPara(), rPaM.GetIndex()+rStr.Len() );
+ return aPaM;
+}
+
+TextPaM TextDoc::InsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs )
+{
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ TextNode* pNew = pNode->Split( rPaM.GetIndex(), bKeepEndingAttribs );
+
+ maTextNodes.Insert( pNew, rPaM.GetPara()+1 );
+
+ TextPaM aPaM( rPaM.GetPara()+1, 0 );
+ return aPaM;
+}
+
+TextPaM TextDoc::ConnectParagraphs( TextNode* pLeft, TextNode* pRight )
+{
+ sal_uInt16 nPrevLen = pLeft->GetText().Len();
+ pLeft->Append( *pRight );
+
+ // der rechte verschwindet.
+ sal_uLong nRight = maTextNodes.GetPos( pRight );
+ maTextNodes.Remove( nRight );
+ delete pRight;
+
+ sal_uLong nLeft = maTextNodes.GetPos( pLeft );
+ TextPaM aPaM( nLeft, nPrevLen );
+ return aPaM;
+}
+
+TextPaM TextDoc::RemoveChars( const TextPaM& rPaM, sal_uInt16 nChars )
+{
+ TextNode* pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ pNode->RemoveText( rPaM.GetIndex(), nChars );
+
+ return rPaM;
+}
+
+sal_Bool TextDoc::IsValidPaM( const TextPaM& rPaM )
+{
+ if ( rPaM.GetPara() >= maTextNodes.Count() )
+ {
+ OSL_FAIL( "PaM: Para out of range" );
+ return sal_False;
+ }
+ TextNode * pNode = maTextNodes.GetObject( rPaM.GetPara() );
+ if ( rPaM.GetIndex() > pNode->GetText().Len() )
+ {
+ OSL_FAIL( "PaM: Index out of range" );
+ return sal_False;
+ }
+ return sal_True;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */