Files
libreoffice/sw/source/core/doc/docedt.cxx
Kurt Zenker b01573861c CWS-TOOLING: integrate CWS odfmetadata3
2009-09-11 Michael Stahl merge DEV300_m58
2009-09-07 Michael Stahl SwFmtFld::Modify(): do nothing on RES_OBJECTDYING
2009-08-27 Michael Stahl #i91565#, #i91566#: TextPortionEnumerationTest.java: add test document
2009-08-27 Michael Stahl #i91565#, #i91566#: add complex test: TextPortionEnumerationTest.java
2009-08-27 Michael Stahl CLiteral::initialize(): zero-length literals probably not an error
2009-08-27 Michael Stahl #i91565#, #i91566#: offapi: new InContentMetadata and MetadataField services
 adapt TextPortion for InContentMetadata
2009-08-27 Michael Stahl #i91564#: xmloff: load/store xml:id and RDFa for text:bookmark(-start).
2009-08-27 Michael Stahl #i91564#: sw core: add support for xml:id at bookmarks:
 sw::mark::Bookmark: derive from Metadatable.
 SwHistoryBookmark, SaveBookmark: store a MetadatableUndo.
 ndcopy.cxx: lcl_CopyBookmarks(): copy the xml:id.
 SwXBookmark: derive from MetadatableMixin.
2009-08-27 Michael Stahl #i91565#, #i91566#: xmloff: refactor ruby import so nested meta(-field) works:
 remove XMLRubyHint_Impl.
 XMLImpRubyContext_Impl::~XMLImpRubyContext_Impl(): insert ruby directly.
2009-08-27 Michael Stahl #i91565#, #i91566#: xmloff: fix text:meta(-field) import/export:
 new XMLTextParagraphExport::exportTextField() overload for XTextField.
 CreateAndInsertMark(): set xml:id after insertion.
 fix meta(-field) service names, bugs etc.
2009-08-27 Michael Stahl #i91565#, #i91566#: sw text formatting: paint background of meta(-field) body:
 SwFont: add member m_nMetaCount.
 txttypes.hxx: add POR_META.
 atrstck.cxx: handle RES_TXTATR_META(FIELD).
 itrform2.cxx: SwTxtFormatter::WhichTxtPor(): create new class SwMetaPortion.
2009-08-27 Michael Stahl #i91566#: sw text formatting: display meta-field prefix and suffix:
 SwAttrIter::GetAttr(): replace with call to GetTxtAttrForCharAt().
 SwTxtFormatter::NewExtraPortion(): handle meta-field prefix.
 SwTxtFormatter: new member m_nHintEndIndex.
 SwTxtFormatter::WhichFirstPortion(): call TryNewNoLengthPortion().
 SwTxtFormatter::TryNewNoLengthPortion(): new; handle suffix of meta-field.
 SwTxtFormatter::UnderFlow(): UGLY HACK: decrement m_nHintEndIndex.
 SwFldPortion: add flag m_bNoLength: portion has zero length (for suffix).
2009-08-27 Michael Stahl #i91565#, #i91566#: extend text:meta(-field) uno wrapper with XText interface:
 unoobj.hxx: new CursorType CURSOR_META.
 unoobj2.cxx: refactor SwXText implementation to ensure that when the SwXText
  belongs to a SwXMeta, content is always inserted inside the meta(-field).
 unoobj.cxx: new SwXTextCursor::ForceIntoMeta(): cursor stays in meta(-field).
 unometa.hxx: SwXMeta implements XText, forwarding to a member SwXMetaText.
 DocInsertStringSplitCR(), SwX*::attachToRange(), SwX*::DeleteAndInsert():
  use FORCEHINTEXPAND hack to ensure insert into the meta(-field) at the end.
2009-08-27 Michael Stahl #i91565#, #i91566#: add text:meta(-field) uno wrapper to sw:
 fmtmeta.hxx, fmtatr2.cxx: new class sw::MetaField, new sw::MetaFieldManager.
 doc.hxx, docnew.cxx: new SwDoc::GetMetaFieldManager().
 unocoll.hxx,.cxx: new SW_SERVICE_FIELDTYPE_METAFIELD, SW_SERVICE_TYPE_META.
 unomap.hxx,.cxx: new PROPERTY_MAP_METAFIELD.
 unoprnms.hxx: new UNO_NAME_META.
 unoport.hxx: new PORTION_META; add "InContentMetadata" prop to SwXTextPortion.
 new unometa.hxx: new class SwXMeta and SwXMetaField.
 unofield.cxx: SwXFieldEnumeration: include meta-fields.
 unoportenum.cxx: handle RES_TXTATR_META(FIELD) by using a portion list stack.
 unotext.cxx: SwXText::insertTextContent(): handle meta(-field) as attribute.
2009-08-27 Michael Stahl #i91565#, #i91566#: ndhints.cxx: remove sort number from SwTxtAttrNesting
2009-08-27 Michael Stahl #i91565#, #i91566#: add support for hints with end and CH_TXTATR to sw core:
 doc.hxx, docedt.cxx: replace SwDoc::Delete(), DeleteAndJoin(), ReplaceRange()
  with wrappers that split at left-overlapped end+CH_TXTATR hints.
 txatbase.hxx: new member SwTxtAttr::m_bHasDummyChar.
 ndtxt.hxx: rename SwTxtNode::GetTxtAttr() to GetTxtAttrForCharAt().
 ndtxt.cxx: SwTxtNode::CopyText(): copy end+CH_TXTATR hints iff copy CH_TXTATR.
 txtatr2.cxx, thints.cxx: SwTxtMeta gets a CH_TXTATR.
2009-08-27 Michael Stahl #i91565#, #i91566#: add text:meta(-field) to sw core:
 txatbase.hxx: new member SwTxtAttr::m_bNesting.
 hintids.hxx: new ids RES_TXTATR_META, RES_TXTATR_METAFIELD.
 txtatr.hxx: new base class SwTxtAttrNesting.
  new hint SwTxtMeta.
  SwTxtRuby derives from SwTxtAttrNesting.
 txtinet.hxx: SwTxtINetFmt derives from SwTxtAttrNesting.
 new header fmtmeta.hxx: new pool item SwFmtMeta. new class sw::Meta.
 ndhints.hxx, thints.cxx: new method SwpHints::TryInsertNesting().
 thints.cxx: refactoring: BuildPortions() no longer handles Ruby/Hyperlink,
  but TryInsertNesting(), which also handles meta(-field).
 SwTxtNode::InsertItem(): check if the hint is actually inserted.
 ndhints.cxx: sort nesting hints based on sort number.
 ndtxt.cxx: lcl_CopyHint(): handle copy of meta/meta-field.
2009-08-27 Michael Stahl enable expanding hints with m_bLockExpandFlag set:
 add new InsertFlag: INS_FORCEHINTEXPAND.
 add new SetAttrMode: SETATTR_FORCEHINTEXPAND.
 rename SwEditShell::Insert() to Insert2() because changed signature fails
  to compile when SwWrtShell tries to overwrite these non-virtual members...
 SwWrtShell::Insert() sets FOCEHINTEXPAND if range was selected/deleted.
 adapt SwUndoInsert to store flags.
2009-08-27 Michael Stahl change formal parameters of item insertion methods to type SetAttrMode
2009-08-27 Michael Stahl fix incorrect resetting of text attributes in SwUndoInsSection, SwUndoInserts
2009-08-27 Michael Stahl clean up SwTxtNode::CutImpl() and lcl_CopyHint()
2009-08-27 Michael Stahl rename SwDoc::Copy() to CopyRange(), and _Copy() to CopyImpl()
2009-08-27 Michael Stahl rename SwNodes::Move() to MoveRange(), and remove unused parameter
2009-08-27 Michael Stahl rename SwDoc::Move() to MoveRange()/MoveNodeRange()
2009-08-27 Michael Stahl rename SwDoc::Insert() to InsertString(), and remove sal_Unicode variant
2009-08-27 Michael Stahl rename SwDoc::Insert() to InsertPoolItem()/InsertItemSet()/InsertSwSection()
2009-08-27 Michael Stahl rename SwDoc::Replace() to ReplaceRange()
2009-08-27 Michael Stahl remove SwDoc::Overwrite() sal_Unicode variant
2009-08-27 Michael Stahl split up SwDoc::DeleteAndJoin(): factor out DeleteAndJoinWithRedline()
2009-08-27 Michael Stahl rename overloaded SwDoc::Delete() to DeleteRange()/DeleteTOXMark()
2009-08-27 Michael Stahl rename SwTxtNode::Copy() to CopyText()
2009-08-27 Michael Stahl rename SwTxtNode::Cut() to CutText(), and _Cut() to CutImpl()
2009-08-27 Michael Stahl rename SwTxtNode::Delete() to DeleteAttribute()/DeleteAttributes()
2009-08-27 Michael Stahl rename SwTxtNode::Replace() to ReplaceText(), and remove the xub_Unicode variant
2009-08-27 Michael Stahl rename SwTxtNode::Erase() to EraseText()
2009-08-27 Michael Stahl rename SwTxtNode::Insert() to InsertText(), and remove the xub_Unicode variant
2009-08-27 Michael Stahl clean up SwTxtNode::Update()
2009-08-27 Michael Stahl remove SwTxtAttr::RemoveFromPool() and make destructor non-public,
 to be invoked by new method SwTxtAttr::Destroy()
2009-08-27 Michael Stahl ensure that SwDoc::Insert() for item (set) returns success indicator:
 replace SwRegHistory constructor with method InsertItems(), returning bool.
 refactor InsAttr() so that it checks if InsertItems() succeeds.
2009-08-27 Michael Stahl move SwXTextPortionEnumeration from unoobj.hxx to unoport.hxx
2009-08-27 Michael Stahl add missing SolarMutex in SwXTextPortion methods
2009-08-27 Michael Stahl SwXTextPortion: new member m_xTextField (so the TextField property need not
  be returned indirectly via SwUnoCursorHelper).
 factor out function CreateSwXTextField().
2009-08-27 Michael Stahl SwXTextPortion: remove PORTION_CONTROL_CHAR and implementation of XTextField
2009-08-27 Michael Stahl remove obsolete hint SwTxtHardBlank and formats SwFmtHardBlank/SwFmtSoftHyph
2009-08-27 Michael Stahl clean up SwTxtAttr and friends:
 remove many accessor methods for obsolete (due to autofmt) char format items.
 remove unused flag SwTxtAttr::m_bDontMergeAttr.
 MakeRedlineTxtAttr() now dedicated function, no longer calls MakeTxtAttr().
2009-08-27 Michael Stahl remove obsolete attribute SwTxt2Lines
2009-08-27 Michael Stahl SwXTextPortionEnumeration: finish refactoring CreatePortions
 change ExportHints so it always returns a text portion for hint w/ CH_TXTATR.
 remove special case for handling end of paragraph.
 unfortunately had to refactor the fieldmarks export as well (got in the way).
2009-08-27 Michael Stahl SwXTextPortionEnumeration: refactor CreatePortions: frames export
 extract function ExportFrames() from CreatePortions().
 remove (un)dead code that calls evil MovePara(fnParaCurr, fnParaEnd)
2009-08-27 Michael Stahl clean up SwXParaFrameEnumeration
2009-08-27 Michael Stahl CollectFrameAtNode: replace SwDependArr with STL based FrameDependList_t
2009-08-27 Michael Stahl SwXTextPortionEnumeration: tweak refmark/toxmark export
 so ExportHints returns the portion for point marks
2009-08-27 Michael Stahl clean up SwXTextPortionEnumeration:
 prefix members, remove casts, replace SvWeirdArray with STL, etc.
 make CreatePortions() method a function, and remove lots of members.
 extract fieldmarks function from CreatePortions.
2009-08-27 Michael Stahl remove FOREACHUNOPAM_START/END macros
2009-08-27 Michael Stahl clean up SwXTextPortion:
 prefix members, remove casts, etc.
 remove SwXRubyPortion: replace it with another SwXTextPortion constructor
2009-08-27 Michael Stahl #i102541# SwXReferenceMark::InsertRefMark(): use flag SETATTR_DONTEXPAND
2009-08-27 Michael Stahl rename SwTxtNode::Insert to SwTxtNode::InsertHint, and
fix constness in SwTxtNode::InsertItem
2009-08-27 Michael Stahl turn SwTxtNode::MakeTxtAttr() methods into global functions in ndhints.hxx
2009-08-27 Michael Stahl remove obsolete sw/inc/bookmrk.hxx
2009-08-27 Michael Stahl pam.cxx: fix ComparePosition functions (returned wrong result in one case)
2009-08-27 Michael Stahl #i103613# only import RDF metadata on normal open of a document
2009-09-11 kz CWS-TOOLING: integrate CWS impress176
2009-09-08 20:18:24 +0200 sj  r275957 : fixed warning (shadowed variable)
2009-09-08 18:02:05 +0200 cl  r275948 : #i104315# added missing tab pages
2009-09-08 17:35:18 +0200 cl  r275947 : #i104866# fixed angle import
2009-09-08 17:32:53 +0200 cl  r275946 : #i104841# fixed angle import
2009-09-08 17:01:25 +0200 cl  r275943 : #i103935# fixed the SID_EVENTCONFIG mess
2009-09-08 14:32:57 +0200 sj  r275928 : #i104685# only comments
2009-09-07 12:37:36 +0200 sj  r275886 : #i104683# fixed import of bold/italic attributes for normal text shapes
2009-09-04 15:07:46 +0200 sj  r275808 : #104689# fixed bullet color problem
2009-09-03 15:25:07 +0200 sj  r275753 : #160200# added vertical alignment of table cells
2009-09-11 kz CWS-TOOLING: integrate CWS dv14
2009-09-10 15:16:32 +0200 sg  r276035 : #160513# updated wfs scheme to accept ports
2009-09-10 07:41:47 +0200 dv  r276019 : #i104942# Better renaming algorithmen
2009-08-31 13:41:11 +0200 dv  r275604 : #160505# Setting APP1PRODUCTNAME must not overwrite APP1PRODUCTDEF
2009-09-11 kz CWS-TOOLING: integrate CWS jl131
2009-09-02 16:42:40 +0200 jl  r275720 : #i97896#
2009-08-31 13:01:53 +0200 jl  r275599 : CWS-TOOLING: rebase CWS jl131 to trunk@275331 (milestone: DEV300:m56)
2009-07-31 14:35:30 +0200 jl  r274531 : CWS-TOOLING: rebase CWS jl131 to trunk@274203 (milestone: DEV300:m53)
2009-07-23 14:20:32 +0200 jl  r274272 : #i79839# better error text when trying to modify shared layer without having write permission, eg. unopkg add --shared, unopkg remove --shared, unopkg reinstall --shared
2009-07-22 16:38:02 +0200 jl  r274252 : #i97896# localize error message for lock file
2009-07-22 16:37:22 +0200 jl  r274251 : #i80462# unprecise wording in updatedialog
2009-07-22 16:36:06 +0200 jl  r274250 : #i97896# localize error message for lock file
2009-07-22 16:35:20 +0200 jl  r274249 : #i97896# localize error message for lock file
2009-07-22 15:07:30 +0200 jl  r274242 : #i98873# minimum java version is 1.5 since OOo 3.0
2009-09-11 kz CWS-TOOLING: integrate CWS changehc
2009-08-31 19:38:50 +0200 pl  r275633 : remove dbug printf
2009-08-31 17:41:50 +0200 pl  r275623 : CWS-TOOLING: rebase CWS changehc to trunk@275331 (milestone: DEV300:m56)
2009-07-15 19:45:46 +0200 pl  r274028 : #i35482# use HC flag to decide high contrast mode
2009-07-15 17:40:52 +0200 pl  r274020 : #i35482# use HC flag to decide high contrast mode
2009-07-15 17:39:50 +0200 pl  r274019 : #i35482# update autohc correctly in MergeSystemSettings
2009-07-15 17:38:57 +0200 pl  r274018 : #i35482# update autohc correctly in MergeSystemSettings
2009-09-11 kz CWS-TOOLING: integrate CWS notes10
2009-08-24 07:25:57 +0200 mod  r275287 : 2009-07-26 02:38:32 +0200 mod  r274343 : #i#i103645#
2009-07-26 02:01:53 +0200 mod  r274342 : #i103645#
2009-07-26 01:52:42 +0200 mod  r274341 : #i103490#
2009-07-22 08:31:48 +0200 mod  r274215 : #i103373#
2009-07-15 00:55:11 +0200 mod  r273987 : #i101419#
2009-07-14 07:07:55 +0200 mod  r273956 : #i101419#
2009-07-14 07:07:43 +0200 mod  r273955 : #i101419#
2009-07-14 07:02:10 +0200 mod  r273954 : changes from notes9
2009-07-14 06:14:25 +0200 mod  r273953 : #i103476#
2009-09-11 kz CWS-TOOLING: integrate CWS ab70
2009-09-10 15:12:54 +0200 jsk  r276034 : #i85434# - mandatory automatic update test
2009-09-10 15:11:06 +0200 jsk  r276033 : #i85434# - mandatory automatic update test
2009-09-02 09:49:24 +0200 ab  r275698 : #i85434# Dialog Import
2009-09-11 kz CWS-TOOLING: integrate CWS hb32bugs02
2009-09-02 Henning Brinkmann #i102420# revert changes
2009-08-26 Henning Brinkmann merged DEV300_m56
2009-08-19 Henning Brinkmann merged DEV300_m55
2009-08-14 Henning Brinkmann merged changes from wntmsci12
2009-08-12 Henning Brinkmann Implemented NoSpaceEdit constructor and destructor in .cxx to allow compile with debug on wntmsci12.
2009-08-12 Henning Brinkmann Added some SW_DLLPUBLIC to make compilable on wntmsci12.
2009-08-11 Henning Brinkmann #i102420# dbg_out: surround output for SwNodes with <nodes-array>.
2009-08-10 Henning Brinkmann #i102420# rewritten debug output for SwNodes.
2009-08-07 Henning Brinkmann #i102420# debug _MoveNodes: output the destination, too. Break after two iterations.
2009-08-07 Henning Brinkmann #i102420# _MoveNodes: Additionally check if destination index is inside source => false
Check if current range was already handled => loop
Debug output current range
2009-08-06 Henning Brinkmann merged DEV300_m54
2009-08-06 Henning Brinkmann added master fix
2009-08-06 Henning Brinkmann debug output for SwNodeRange
2009-08-04 Henning Brinkmann #i102844# robustness: check for NULL pointer to prevent crash
2009-08-03 Henning Brinkmann #i103475# applied patch and verified
2009-08-03 Henning Brinkmann Removed code preventing build of sw with DEBUG.
2009-09-11 convert-repo update tags
2009-09-10 kz CWS-TOOLING: integrate CWS os2port06dev300
2009-09-05 22:49:00 +0200 ydario  r275858 : #i99588# applied os2port06 diff to DEV300 tree.
2009-09-10 kz CWS-TOOLING: integrate CWS mingwport23
2009-08-29 07:07:53 +0200 tono  r275555 : i#104522: mingw port graphite
2009-08-29 07:07:26 +0200 tono  r275554 : i#104522: mingw port printf format fix
2009-09-10 kz CWS-TOOLING: integrate CWS mh232
2009-08-26 03:52:57 +0200 mh  r275385 : #i102182# FreeBSD patch
2009-08-26 03:43:20 +0200 mh  r275384 : #i101333# patch for FreeBSD
2009-08-26 03:11:20 +0200 mh  r275383 : #i39230
2009-08-26 03:07:51 +0200 mh  r275382 : #i39230# more space for initials field
2009-08-26 02:41:19 +0200 mh  r275380 : #i39230# use vos::osecurity for reading the user name
2009-08-18 22:06:00 +0200 mh  r275130 : #i104243#, line ending problem with newer perl
2009-08-18 21:53:21 +0200 mh  r275129 : #i39230# read initials via getpwnam
2009-08-18 21:34:05 +0200 mh  r275128 : enable CAIROCANVAS for Linux and Mac, #i88613#
2009-08-17 18:02:59 +0200 mh  r275067 : #i95498# make compile with gcc3
2009-09-10 kz CWS-TOOLING: integrate CWS tkr24
2009-09-07 14:31:06 +0200 is  r275898 : #160081# adding NO_LICENSE_INTO_COPYRIGHT
2009-09-10 releng #i10000# change KeyMapping to SingletonRef<framework::KeyMapping>
2009-09-11 convert-repo update tags
2009-09-10 kz CWS-TOOLING: integrate CWS os2port06dev300
2009-09-05 22:49:00 +0200 ydario  r275858 : #i99588# applied os2port06 diff to DEV300 tree.
2009-09-10 kz CWS-TOOLING: integrate CWS mingwport23
2009-08-29 07:07:53 +0200 tono  r275555 : i#104522: mingw port graphite
2009-08-29 07:07:26 +0200 tono  r275554 : i#104522: mingw port printf format fix
2009-09-10 kz CWS-TOOLING: integrate CWS mh232
2009-08-26 03:52:57 +0200 mh  r275385 : #i102182# FreeBSD patch
2009-08-26 03:43:20 +0200 mh  r275384 : #i101333# patch for FreeBSD
2009-08-26 03:11:20 +0200 mh  r275383 : #i39230
2009-08-26 03:07:51 +0200 mh  r275382 : #i39230# more space for initials field
2009-08-26 02:41:19 +0200 mh  r275380 : #i39230# use vos::osecurity for reading the user name
2009-08-18 22:06:00 +0200 mh  r275130 : #i104243#, line ending problem with newer perl
2009-08-18 21:53:21 +0200 mh  r275129 : #i39230# read initials via getpwnam
2009-08-18 21:34:05 +0200 mh  r275128 : enable CAIROCANVAS for Linux and Mac, #i88613#
2009-08-17 18:02:59 +0200 mh  r275067 : #i95498# make compile with gcc3
2009-09-10 kz CWS-TOOLING: integrate CWS tkr24
2009-09-07 14:31:06 +0200 is  r275898 : #160081# adding NO_LICENSE_INTO_COPYRIGHT
2009-09-10 releng #i10000# change KeyMapping to SingletonRef<framework::KeyMapping>
2009-09-11 14:29:45 +00:00

2807 lines
100 KiB
C++

/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2008 by Sun Microsystems, Inc.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: docedt.cxx,v $
* $Revision: 1.48 $
*
* 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 <string.h> // fuer strchr()
#include <hintids.hxx>
#include <vcl/sound.hxx>
#include <svx/cscoitem.hxx>
#include <svx/brkitem.hxx>
#include <linguistic/lngprops.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/i18n/WordType.hdl>
#include <unotools/charclass.hxx>
#include <fmtanchr.hxx>
#include <fmtcntnt.hxx>
#include <fmtpdsc.hxx>
#include <txtftn.hxx>
#include <acorrect.hxx> // Autokorrektur
#include <IMark.hxx> // fuer SwBookmark
#include <cntfrm.hxx> // fuers Spell
#include <crsrsh.hxx>
#include <doc.hxx>
#include <docsh.hxx>
#include <docary.hxx>
#include <doctxm.hxx> // beim Move: Verzeichnisse korrigieren
#include <ftnidx.hxx>
#include <ftninfo.hxx>
#include <mdiexp.hxx> // Statusanzeige
#include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
#include <ndtxt.hxx>
#include <pam.hxx>
#include <redline.hxx>
#include <rootfrm.hxx> // fuers UpdateFtn
#include <splargs.hxx> // fuer Spell
#include <swtable.hxx>
#include <swundo.hxx> // fuer die UndoIds
#include <txtfrm.hxx>
#include <undobj.hxx>
#include <breakit.hxx>
#include <hhcwrp.hxx>
#include <breakit.hxx>
#include <vcl/msgbox.hxx>
#include "comcore.hrc"
#include "editsh.hxx"
#include <unoflatpara.hxx>
#include <SwGrammarMarkUp.hxx>
using ::rtl::OUString;
using namespace ::com::sun::star;
using namespace ::com::sun::star::linguistic2;
using namespace ::com::sun::star::i18n;
//using namespace ::utl;
#ifndef S2U
#define S2U(rString) OUString::createFromAscii(rString)
#endif
struct _SaveRedline
{
SwRedline* pRedl;
sal_uInt32 nStt, nEnd;
xub_StrLen nSttCnt, nEndCnt;
_SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx )
: pRedl( pR )
{
const SwPosition* pStt = pR->Start(),
* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
sal_uInt32 nSttIdx = rSttIdx.GetIndex();
nStt = pStt->nNode.GetIndex() - nSttIdx;
nSttCnt = pStt->nContent.GetIndex();
if( pR->HasMark() )
{
nEnd = pEnd->nNode.GetIndex() - nSttIdx;
nEndCnt = pEnd->nContent.GetIndex();
}
pRedl->GetPoint()->nNode = 0;
pRedl->GetPoint()->nContent.Assign( 0, 0 );
pRedl->GetMark()->nNode = 0;
pRedl->GetMark()->nContent.Assign( 0, 0 );
}
_SaveRedline( SwRedline* pR, const SwPosition& rPos )
: pRedl( pR )
{
const SwPosition* pStt = pR->Start(),
* pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
nStt = pStt->nNode.GetIndex() - nSttIdx;
nSttCnt = pStt->nContent.GetIndex();
if( nStt == 0 )
nSttCnt = nSttCnt - rPos.nContent.GetIndex();
if( pR->HasMark() )
{
nEnd = pEnd->nNode.GetIndex() - nSttIdx;
nEndCnt = pEnd->nContent.GetIndex();
if( nEnd == 0 )
nEndCnt = nEndCnt - rPos.nContent.GetIndex();
}
pRedl->GetPoint()->nNode = 0;
pRedl->GetPoint()->nContent.Assign( 0, 0 );
pRedl->GetMark()->nNode = 0;
pRedl->GetMark()->nContent.Assign( 0, 0 );
}
void SetPos( sal_uInt32 nInsPos )
{
pRedl->GetPoint()->nNode = nInsPos + nStt;
pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
if( pRedl->HasMark() )
{
pRedl->GetMark()->nNode = nInsPos + nEnd;
pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt );
}
}
void SetPos( const SwPosition& aPos )
{
pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
if( pRedl->HasMark() )
{
pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
}
}
};
SV_DECL_PTRARR_DEL( _SaveRedlines, _SaveRedline*, 0, 4 )
SV_IMPL_VARARR( _SaveFlyArr, _SaveFly )
SV_IMPL_PTRARR( _SaveRedlines, _SaveRedline* )
bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos )
{
sal_Unicode cChr = pNode->GetTxt().GetChar( nPos );
return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) &&
(0 != pNode->GetTxtAttrForCharAt( nPos ) ) );
}
void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart )
{
if( !lcl_MayOverwrite( pNode, rStart ) )
{
// ueberspringe alle SonderAttribute
do {
// "Beep" bei jedem ausgelassenen
Sound::Beep(SOUND_ERROR);
rIdx++;
} while( (rStart = rIdx.GetIndex()) < pNode->GetTxt().Len()
&& !lcl_MayOverwrite(pNode, rStart) );
}
}
// -----------------------------------------------------------------
void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
const SwNodeIndex* pInsertPos )
{
SwPosition aPos( rSttIdx );
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
// neuen Anker anlegen
_SaveFly& rSave = rArr[n];
SwFrmFmt* pFmt = rSave.pFrmFmt;
if( rSave.bInsertPosition )
{
if( pInsertPos != NULL )
aPos.nNode = *pInsertPos;
else
aPos.nNode = rSttIdx.GetIndex();
}
else
aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
aPos.nContent.Assign( 0, 0 );
SwFmtAnchor aAnchor( pFmt->GetAnchor() );
aAnchor.SetAnchor( &aPos );
pFmt->GetDoc()->GetSpzFrmFmts()->Insert(
pFmt, pFmt->GetDoc()->GetSpzFrmFmts()->Count() );
pFmt->SetFmtAttr( aAnchor );
SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
if( pCNd && pCNd->GetFrm( 0, 0, sal_False ) )
pFmt->MakeFrms();
}
}
void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
{
SwFrmFmt* pFmt;
const SwFmtAnchor* pAnchor;
const SwPosition* pAPos;
SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
{
pFmt = (SwFrmFmt*)rFmts[n];
pAnchor = &pFmt->GetAnchor();
if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
{
_SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
pFmt, sal_False );
rArr.Insert( aSave, rArr.Count());
pFmt->DelFrms();
rFmts.Remove( n--, 1 );
}
}
}
void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
_SaveFlyArr& rArr, bool bMoveAllFlys )
{
SwSpzFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
SwFrmFmt* pFmt;
const SwFmtAnchor* pAnchor;
const SwPosition* pPos = rPam.Start();
const SwNodeIndex& rSttNdIdx = pPos->nNode;
short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
pPos->nContent.GetIndex()) ? 1 : 0;
pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
const SwNodeIndex& rEndNdIdx = pPos->nNode;
short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
? 0 : 1;
const SwPosition* pAPos;
const SwNodeIndex* pCntntIdx;
for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
{
sal_Bool bInsPos = sal_False;
pFmt = (SwFrmFmt*)rFmts[n];
pAnchor = &pFmt->GetAnchor();
if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
// nicht verschieben, wenn die InsPos im CntntBereich vom Fly ist
( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
!( *pCntntIdx < rInsPos &&
rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
{
if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
{
// wenn nur teil vom EndNode oder der EndNode und SttNode
// identisch sind, chaos::Anchor nicht anfassen
if( rSttNdIdx != pAPos->nNode )
{
// Anker nur an Anfang/Ende haengen
SwPosition aPos( rSttNdIdx );
SwFmtAnchor aAnchor( *pAnchor );
aAnchor.SetAnchor( &aPos );
pFmt->SetFmtAttr( aAnchor );
// ((SwFmtAnchor*)pAnchor)->SetAnchor( &aPos );
}
}
else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
&& pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
0 != ( bInsPos = rInsPos == pAPos->nNode ))
{
_SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
pFmt, bInsPos );
rArr.Insert( aSave, rArr.Count());
pFmt->DelFrms();
rFmts.Remove( n--, 1 );
}
}
}
}
// -----------------------------------------------------------------
// loesche und verschiebe alle "Fly's am Absatz", die in der SSelection
// liegen. Steht am SPoint ein Fly, wird dieser auf den Mark verschoben.
void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
const SwNodeIndex& rPtNdIdx )
{
const sal_Bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
SwSpzFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
const SwPosition* pAPos;
for ( sal_uInt16 i = rTbl.Count(); i; )
{
SwFrmFmt *pFmt = rTbl[--i];
const SwFmtAnchor &rAnch = pFmt->GetAnchor();
if( ( rAnch.GetAnchorId() == FLY_AT_CNTNT ||
rAnch.GetAnchorId() == FLY_AUTO_CNTNT ) &&
0 != ( pAPos = rAnch.GetCntntAnchor() ) &&
( bDelFwrd
? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
: rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
{
// nur den Anker verschieben ??
if( rPtNdIdx == pAPos->nNode )
{
SwFmtAnchor aAnch( pFmt->GetAnchor() );
SwPosition aPos( rMkNdIdx );
aAnch.SetAnchor( &aPos );
pFmt->SetFmtAttr( aAnch );
}
else
{
// wird der Fly geloescht muss auch im seinem Inhalt alle
// Flys geloescht werden !!
const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
if( rCntnt.GetCntntIdx() )
{
DelFlyInRange( *rCntnt.GetCntntIdx(),
SwNodeIndex( *rCntnt.GetCntntIdx()->
GetNode().EndOfSectionNode() ));
// Position kann sich verschoben haben !
if( i > rTbl.Count() )
i = rTbl.Count();
else if( pFmt != rTbl[i] )
i = rTbl.GetPos( pFmt );
}
pDoc->DelLayoutFmt( pFmt );
// --> FME 2004-10-06 #117913# DelLayoutFmt can also
// trigger the deletion of objects.
if( i > rTbl.Count() )
i = rTbl.Count();
// <--
}
}
}
}
bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
const SwNodeIndex& rInsPos,
SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
{
bool bUpdateFtn = sal_False;
const SwNodes& rNds = rInsPos.GetNodes();
const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
const bool bSaveFtn = !bDelFtn &&
rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
if( rFtnArr.Count() )
{
sal_uInt16 nPos;
rFtnArr.SeekEntry( rSttNd, &nPos );
SwTxtFtn* pSrch;
const SwNode* pFtnNd;
// loesche/sicher erstmal alle, die dahinter stehen
while( nPos < rFtnArr.Count() && ( pFtnNd =
&( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
<= rEndNd.GetIndex() )
{
xub_StrLen nFtnSttIdx = *pSrch->GetStart();
if( ( pEndCnt && pSttCnt )
? (( &rSttNd.GetNode() == pFtnNd &&
pSttCnt->GetIndex() > nFtnSttIdx) ||
( &rEndNd.GetNode() == pFtnNd &&
nFtnSttIdx >= pEndCnt->GetIndex() ))
: ( &rEndNd.GetNode() == pFtnNd ))
{
++nPos; // weiter suchen
}
else
{
// dann weg damit
if( bDelFtn )
{
SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
SwIndex aIdx( &rTxtNd, nFtnSttIdx );
rTxtNd.EraseText( aIdx, 1 );
}
else
{
pSrch->DelFrms();
rFtnArr.Remove( nPos );
if( bSaveFtn )
rSaveArr.Insert( pSrch );
}
bUpdateFtn = sal_True;
}
}
while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
{
xub_StrLen nFtnSttIdx = *pSrch->GetStart();
if( !pEndCnt || !pSttCnt ||
!( (( &rSttNd.GetNode() == pFtnNd &&
pSttCnt->GetIndex() > nFtnSttIdx ) ||
( &rEndNd.GetNode() == pFtnNd &&
nFtnSttIdx >= pEndCnt->GetIndex() )) ))
{
if( bDelFtn )
{
// dann weg damit
SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
SwIndex aIdx( &rTxtNd, nFtnSttIdx );
rTxtNd.EraseText( aIdx, 1 );
}
else
{
pSrch->DelFrms();
rFtnArr.Remove( nPos );
if( bSaveFtn )
rSaveArr.Insert( pSrch );
}
bUpdateFtn = sal_True;
}
}
}
// When moving from redline section into document content section, e.g.
// after loading a document with (delete-)redlines, the footnote array
// has to be adjusted... (#i70572)
if( bSaveFtn )
{
SwNodeIndex aIdx( rSttNd );
while( aIdx < rEndNd ) // Check the moved section
{
SwNode* pNode = &aIdx.GetNode();
if( pNode->IsTxtNode() ) // Looking for text nodes...
{
SwpHints *pHints =
static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
if( pHints && pHints->HasFtn() ) //...with footnotes
{
bUpdateFtn = sal_True; // Heureka
USHORT nCount = pHints->Count();
for( USHORT i = 0; i < nCount; ++i )
{
SwTxtAttr *pAttr = pHints->GetTextHint( i );
if ( pAttr->Which() == RES_TXTATR_FTN )
{
rSaveArr.Insert( static_cast<SwTxtFtn*>(pAttr) );
}
}
}
}
++aIdx;
}
}
return bUpdateFtn;
}
void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
{
SwDoc* pDoc = aPam.GetNode()->GetDoc();
const SwPosition* pStart = aPam.Start();
const SwPosition* pEnd = aPam.End();
// get first relevant redline
sal_uInt16 nCurrentRedline;
pDoc->GetRedline( *pStart, &nCurrentRedline );
if( nCurrentRedline > 0)
nCurrentRedline--;
// redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
// iterate over relevant redlines and decide for each whether it should
// be saved, or split + saved
SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
for( ; nCurrentRedline < rRedlineTable.Count(); nCurrentRedline++ )
{
SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
SwComparePosition eCompare =
ComparePosition( *pCurrent->Start(), *pCurrent->End(),
*pStart, *pEnd);
// we must save this redline if it overlaps aPam
// (we may have to split it, too)
if( eCompare == POS_OVERLAP_BEHIND ||
eCompare == POS_OVERLAP_BEFORE ||
eCompare == POS_OUTSIDE ||
eCompare == POS_INSIDE ||
eCompare == POS_EQUAL )
{
rRedlineTable.Remove( nCurrentRedline-- );
// split beginning, if necessary
if( eCompare == POS_OVERLAP_BEFORE ||
eCompare == POS_OUTSIDE )
{
SwRedline* pNewRedline = new SwRedline( *pCurrent );
*pNewRedline->End() = *pStart;
*pCurrent->Start() = *pStart;
pDoc->AppendRedline( pNewRedline, true );
}
// split end, if necessary
if( eCompare == POS_OVERLAP_BEHIND ||
eCompare == POS_OUTSIDE )
{
SwRedline* pNewRedline = new SwRedline( *pCurrent );
*pNewRedline->Start() = *pEnd;
*pCurrent->End() = *pEnd;
pDoc->AppendRedline( pNewRedline, true );
}
// save the current redline
_SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
}
}
// restore old redline mode
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
{
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
_SaveRedline* pSave = rArr[ n ];
pSave->SetPos( rPos );
pDoc->AppendRedline( pSave->pRedl, true );
}
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
{
SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
sal_uInt16 nRedlPos;
SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
--nRedlPos;
else if( nRedlPos >= pDoc->GetRedlineTbl().Count() )
return ;
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
do {
SwRedline* pTmp = rRedlTbl[ nRedlPos ];
const SwPosition* pRStt = pTmp->Start(),
* pREnd = pTmp->GetMark() == pRStt
? pTmp->GetPoint() : pTmp->GetMark();
if( pRStt->nNode < rRg.aStart )
{
if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
{
// Kopie erzeugen und Ende vom Original ans Ende des
// MoveBereiches setzen. Die Kopie wird mit verschoben
SwRedline* pNewRedl = new SwRedline( *pTmp );
SwPosition* pTmpPos = pNewRedl->Start();
pTmpPos->nNode = rRg.aStart;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
pTmpPos = pTmp->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
}
else if( pREnd->nNode == rRg.aStart )
{
SwPosition* pTmpPos = pTmp->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
}
}
else if( pRStt->nNode < rRg.aEnd )
{
rRedlTbl.Remove( nRedlPos-- );
if( pREnd->nNode < rRg.aEnd ||
( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
{
// gesamt verschieben
_SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
}
else
{
// aufsplitten
SwRedline* pNewRedl = new SwRedline( *pTmp );
SwPosition* pTmpPos = pNewRedl->End();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
_SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
// rArr.Insert( pSave, rArr.Count() );
rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
pTmpPos = pTmp->Start();
pTmpPos->nNode = rRg.aEnd;
pTmpPos->nContent.Assign(
pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
pDoc->AppendRedline( pTmp, true );
}
}
else
break;
} while( ++nRedlPos < pDoc->GetRedlineTbl().Count() );
pDoc->SetRedlineMode_intern( eOld );
}
void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
{
RedlineMode_t eOld = pDoc->GetRedlineMode();
pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
{
_SaveRedline* pSave = rArr[ n ];
pSave->SetPos( nInsPos );
pDoc->AppendRedline( pSave->pRedl, true );
}
pDoc->SetRedlineMode_intern( eOld );
}
// ------------------------------------------------------------------------
// #i59534: Redo of insertion of multiple text nodes runs into trouble
// because of unnecessary expanded redlines
// From now on this class saves the redline positions of all redlines which ends exact at the
// insert position (node _and_ content index)
_SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt )
: pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
{
SwNode& rNd = rInsIdx.GetNode();
SwDoc* pDest = rNd.GetDoc();
if( pDest->GetRedlineTbl().Count() )
{
sal_uInt16 nFndPos;
const SwPosition* pEnd;
SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos );
while( nFndPos-- && *( pEnd = ( pRedl =
pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos && *pRedl->Start() < aSrcPos )
{
if( !pSavArr )
{
pSavArr = new SvPtrarr( 2, 2 );
pSavIdx = new SwNodeIndex( rInsIdx, -1 );
}
void* p = (void*)pEnd;
pSavArr->Insert( p, pSavArr->Count() );
}
}
}
_SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
{
if( pSavArr )
{
delete pSavArr;
delete pSavIdx;
}
}
void _SaveRedlEndPosForRestore::_Restore()
{
(*pSavIdx)++;
SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
// If there's no content node at the remembered position, we will not restore the old position
// This may happen if a table (or section?) will be inserted.
if( pNode )
{
SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
for( sal_uInt16 n = pSavArr->Count(); n; )
*((SwPosition*)pSavArr->GetObject( --n )) = aPos;
}
}
// ------------------------------------------------------------------------
// Loeschen einer vollstaendigen Section des NodesArray.
// Der uebergebene Node steht irgendwo in der gewuenschten Section
void SwDoc::DeleteSection( SwNode *pNode )
{
ASSERT( pNode, "Kein Node uebergeben." );
SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
: pNode->StartOfSectionNode();
SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
// dann loesche mal alle Fly's, text::Bookmarks, ...
DelFlyInRange( aSttIdx, aEndIdx );
DeleteRedline( *pSttNd, true, USHRT_MAX );
_DelBookmarks(aSttIdx, aEndIdx);
{
// alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
SwNodeIndex aMvStt( aSttIdx, 1 );
CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
}
GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
}
void SwDoc::SetModified(SwPaM &rPaM)
{
SwDataChanged aTmp( rPaM, 0 );
SetModified();
}
/*************************************************************************
* SwDoc::Overwrite()
************************************************************************/
bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr )
{
SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
if( pACEWord ) // Aufnahme in die Autokorrektur
{
if( 1 == rStr.Len() )
pACEWord->CheckChar( rPt, rStr.GetChar( 0 ) );
delete pACEWord, pACEWord = 0;
}
SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
if(!pNode)
return sal_False;
if( DoesUndo() )
ClearRedo();
sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
? pNode->GetpSwpHints()->Count() : 0;
SwDataChanged aTmp( rRg, 0 );
SwIndex& rIdx = rPt.nContent;
xub_StrLen nStart = 0;
sal_uInt16 nUndoSize = pUndos->Count();
SwUndo * pUndo;
sal_Unicode c;
String aStr;
BOOL bOldExpFlg = pNode->IsIgnoreDontExpand();
pNode->SetIgnoreDontExpand( TRUE );
for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt )
{
// hinter das Zeichen (zum aufspannen der Attribute !!)
nStart = rIdx.GetIndex();
if ( nStart < pNode->GetTxt().Len() )
{
lcl_SkipAttr( pNode, rIdx, nStart );
}
c = rStr.GetChar( nCnt );
if( DoesUndo() )
{
if( DoesGroupUndo() && nUndoSize &&
UNDO_OVERWRITE == ( pUndo = (*pUndos)[ nUndoSize-1 ])->GetId() &&
((SwUndoOverwrite*)pUndo)->CanGrouping( this, rPt, c ))
;// wenn CanGrouping() sal_True returnt, ist schon alles erledigt
else
{
AppendUndo( new SwUndoOverwrite( this, rPt, c ));
nUndoSize = pUndos->Count();
}
}
else
{
// hinter das Zeichen (zum Aufspannen der Attribute !!)
if( nStart < pNode->GetTxt().Len() )
rIdx++;
pNode->InsertText( c, rIdx, INS_EMPTYEXPAND );
if( nStart+1 < rIdx.GetIndex() )
{
rIdx = nStart;
pNode->EraseText( rIdx, 1 );
rIdx++;
}
}
}
pNode->SetIgnoreDontExpand( bOldExpFlg );
sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
? pNode->GetpSwpHints()->Count() : 0;
if( nOldAttrCnt != nNewAttrCnt )
{
SwUpdateAttr aHint( 0, 0, 0 );
SwClientIter aIter( *pNode );
SwClient* pGTO = aIter.First(TYPE( SwCrsrShell ));
while( pGTO )
{
pGTO->Modify( 0, &aHint );
pGTO = aIter.Next();
}
}
if( !DoesUndo() && !IsIgnoreRedline() && GetRedlineTbl().Count() )
{
SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
DeleteRedline( aPam, true, USHRT_MAX );
}
else if( IsRedlineOn() )
{
// FIXME: this redline is WRONG: there is no DELETE, and the skipped
// characters are also included in aPam
SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
}
SetModified();
return sal_True;
}
bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
{
SwNodeIndex aIdx( rPaM.Start()->nNode );
sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
aIdx--; // vor den Move Bereich !!
bool bRet = MoveRange( rPaM, rPos, eMvFlags );
if( bRet && !bOneNode )
{
if( bJoinTxt )
aIdx++;
SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
SwNodeIndex aNxtIdx( aIdx );
if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
{
{ // Block wegen SwIndex in den Node !!
CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex( pTxtNd,
pTxtNd->GetTxt().Len() ) ), 0, sal_True );
}
pTxtNd->JoinNext();
}
}
return bRet;
}
// mst: it seems that this is mostly used by SwDoc internals; the only
// way to call this from the outside seems to be the special case in
// SwDoc::CopyRange (but i have not managed to actually hit that case)
bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
{
// keine Moves-Abfangen
const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
return false;
// sicher die absatzgebundenen Flys, damit sie verschoben werden koennen.
_SaveFlyArr aSaveFlyArr;
_SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
// save redlines (if DOC_MOVEREDLINES is used)
_SaveRedlines aSaveRedl( 0, 4 );
if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
{
lcl_SaveRedlines( rPaM, aSaveRedl );
// #i17764# unfortunately, code below relies on undos being
// in a particular order, and presence of bookmarks
// will change this order. Hence, we delete bookmarks
// here without undo.
BOOL bDoesUndo = DoesUndo();
DoUndo( FALSE );
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
NULL,
&pStt->nContent,
&pEnd->nContent);
DoUndo( bDoesUndo );
}
int bUpdateFtn = sal_False;
SwFtnIdxs aTmpFntIdx;
// falls Undo eingeschaltet, erzeuge das UndoMove-Objekt
SwUndoMove * pUndoMove = 0;
if( DoesUndo() )
{
ClearRedo();
pUndoMove = new SwUndoMove( rPaM, rPos );
pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
}
else
{
bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
GetFtnIdxs(), aTmpFntIdx,
&pStt->nContent, &pEnd->nContent );
}
sal_Bool bSplit = sal_False;
SwPaM aSavePam( rPos, rPos );
// stelle den SPoint an den Anfang vom Bereich (Definition)
if( rPaM.GetPoint() == pEnd )
rPaM.Exchange();
// in der EditShell wird nach dem Move ein JoinNext erzeugt, wenn
// vor und nach dem Move ein Text-Node steht.
SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
// werden ein oder mehr TextNodes bewegt, so wird
// im SwNodes::Move ein SplitNode erzeugt. Dieser Updated aber nicht
// den Cursor. Um das zu verhindern, wird hier ein TextNode angelegt,
// um die Updaterei der Indizies zu erhalten. Nach dem Move wird
// evt. der Node geloescht.
SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
{
bSplit = sal_True;
xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
SvULongs aBkmkArr( 15, 15 );
_SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
aBkmkArr, SAVEFLY_SPLIT );
pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
if( aBkmkArr.Count() )
_RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True );
// jetzt noch den Pam berichtigen !!
if( rPos.nNode == rPaM.GetMark()->nNode )
{
rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
}
}
// setze den Pam um einen "Inhalt" zurueck; dadurch steht er immer
// ausserhalb des manipulierten Bereiches. Falls kein Inhalt mehr vor-
// handen, dann auf den StartNode (es ist immer einer vorhanden !!!)
sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
if( bNullCntnt )
{
aSavePam.GetPoint()->nNode--;
}
// kopiere alle Bookmarks, die im Move Bereich stehen in ein
// Array, das alle Angaben auf die Position als Offset speichert.
// Die neue Zuordung erfolgt nach dem Moven.
::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
&aSaveBkmks,
&pStt->nContent,
&pEnd->nContent);
// falls durch die vorherigen Loeschungen (z.B. der Fussnoten) kein
// Bereich mehr existiert, ist das immernoch ein gueltiger Move!
if( *rPaM.GetPoint() != *rPaM.GetMark() )
{
// now do the actual move
GetNodes().MoveRange( rPaM, rPos, GetNodes() );
// after a MoveRange() the Mark is deleted
if ( rPaM.HasMark() ) // => no Move occurred!
{
delete pUndoMove;
return false;
}
}
else
rPaM.DeleteMark();
ASSERT( *aSavePam.GetMark() == rPos ||
( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
"PaM wurde nicht verschoben, am Anfang/Ende keine ContentNodes?" );
*aSavePam.GetMark() = rPos;
rPaM.SetMark(); // um den neuen Bereich eine Sel. aufspannen
pTNd = aSavePam.GetNode()->GetTxtNode();
if( DoesUndo() )
{
// korrigiere erstmal den Content vom SavePam
if( bNullCntnt )
{
aSavePam.GetPoint()->nContent = 0;
}
// die Methode SwEditShell::Move() fuegt nach dem Move den Text-Node
// zusammen, in dem der rPaM steht. Wurde der Inhalt nach hinten
// geschoben und liegt der SPoint vom SavePam im naechsten Node, so
// muss beim Speichern vom Undo-Object das beachtet werden !!
SwTxtNode * pPamTxtNd = 0;
// wird ans SwUndoMove weitergegeben, das dann beim Undo JoinNext
// aufruft. (falls es hier nicht moeglich ist).
sal_Bool bJoin = bSplit && pTNd;
bCorrSavePam = bCorrSavePam &&
0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
&& pPamTxtNd->CanJoinNext()
&& (*rPaM.GetPoint() <= *aSavePam.GetPoint());
// muessen am SavePam 2 Nodes zusammengefasst werden ??
if( bJoin && pTNd->CanJoinNext() )
{
pTNd->JoinNext();
// kein temp. sdbcx::Index bei &&
// es sollten wohl nur die Indexwerte verglichen werden.
if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
aSavePam.GetPoint()->nNode.GetIndex() )
{
aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
}
bJoin = sal_False;
}
// else if( !bCorrSavePam && !pSavePam->Move( fnMoveForward, fnGoCntnt ))
else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
{
aSavePam.GetPoint()->nNode++;
}
// zwischen SPoint und GetMark steht jetzt der neu eingefuegte Bereich
pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
bJoin, bCorrSavePam );
AppendUndo( pUndoMove );
}
else
{
bool bRemove = true;
// muessen am SavePam 2 Nodes zusammengefasst werden ??
if( bSplit && pTNd )
{
if( pTNd->CanJoinNext())
{
// --> OD 2009-08-20 #i100466#
// Always join next, because <pTNd> has to stay as it is.
// A join previous from its next would more or less delete <pTNd>
pTNd->JoinNext();
// <--
bRemove = false;
}
}
if( bNullCntnt )
{
aSavePam.GetPoint()->nNode++;
aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
}
else if( bRemove ) // No move forward after joining with next paragraph
{
aSavePam.Move( fnMoveForward, fnGoCntnt );
}
}
// setze jetzt wieder die text::Bookmarks in das Dokument
*rPaM.GetMark() = *aSavePam.Start();
for(
::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
pBkmk != aSaveBkmks.end();
++pBkmk)
pBkmk->SetInDoc(
this,
rPaM.GetMark()->nNode,
&rPaM.GetMark()->nContent);
*rPaM.GetPoint() = *aSavePam.End();
// verschiebe die Flys an die neue Position
_RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
// restore redlines (if DOC_MOVEREDLINES is used)
if( aSaveRedl.Count() )
{
lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
}
if( bUpdateFtn )
{
if( aTmpFntIdx.Count() )
{
GetFtnIdxs().Insert( &aTmpFntIdx );
aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
}
GetFtnIdxs().UpdateAllFtn();
}
SetModified();
return true;
}
bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
SwMoveFlags eMvFlags )
{
// bewegt alle Nodes an die neue Position. Dabei werden die
// text::Bookmarks mit verschoben !! (zur Zeit ohne Undo)
// falls durchs Move Fussnoten in den Sonderbereich kommen sollten,
// dann entferne sie jetzt.
//JP 13.07.95:
// ansonsten bei allen Fussnoten, die verschoben werden, die Frames
// loeschen und nach dem Move wieder aufbauen lassen (Fussnoten koennen
// die Seite wechseln). Zusaetzlich muss natuerlich die Sortierung
// der FtnIdx-Array wieder korrigiert werden.
int bUpdateFtn = sal_False;
SwFtnIdxs aTmpFntIdx;
SwUndoMove* pUndo = 0;
if( (DOC_CREATEUNDOOBJ & eMvFlags ) && DoesUndo() )
pUndo = new SwUndoMove( this, rRange, rPos );
else
bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
GetFtnIdxs(), aTmpFntIdx );
_SaveRedlines aSaveRedl( 0, 4 );
SvPtrarr aSavRedlInsPosArr( 0, 4 );
if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
{
lcl_SaveRedlines( rRange, aSaveRedl );
// suche alle Redlines, die an der InsPos aufhoeren. Diese muessen
// nach dem Move wieder an die "alte" Position verschoben werden
sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
if( USHRT_MAX != nRedlPos )
{
const SwPosition *pRStt, *pREnd;
do {
SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
pRStt = pTmp->Start();
pREnd = pTmp->End();
if( pREnd->nNode == rPos && pRStt->nNode < rPos )
{
void* p = pTmp;
aSavRedlInsPosArr.Insert( p, aSavRedlInsPosArr.Count() );
}
} while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().Count());
}
}
// kopiere alle Bookmarks, die im Move Bereich stehen in ein
// Array, das alle Angaben auf die Position als Offset speichert.
// Die neue Zuordung erfolgt nach dem Moven.
::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
_DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
// sicher die absatzgebundenen Flys, damit verschoben werden koennen.
_SaveFlyArr aSaveFlyArr;
if( GetSpzFrmFmts()->Count() )
_SaveFlyInRange( rRange, aSaveFlyArr );
// vor die Position setzen, damit er nicht weitergeschoben wird
SwNodeIndex aIdx( rPos, -1 );
SwNodeIndex* pSaveInsPos = 0;
if( pUndo )
pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
// verschiebe die Nodes
BOOL bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
{
aIdx++; // wieder auf alte Position
if( pSaveInsPos )
(*pSaveInsPos)++;
}
else
{
aIdx = rRange.aStart;
delete pUndo, pUndo = 0;
}
// verschiebe die Flys an die neue Position
if( aSaveFlyArr.Count() )
_RestFlyInRange( aSaveFlyArr, aIdx, NULL );
// setze jetzt wieder die text::Bookmarks in das Dokument
for(
::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
pBkmk != aSaveBkmks.end();
++pBkmk)
pBkmk->SetInDoc(this, aIdx);
if( aSavRedlInsPosArr.Count() )
{
SwNode* pNewNd = &aIdx.GetNode();
for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.Count(); ++n )
{
SwRedline* pTmp = (SwRedline*)aSavRedlInsPosArr[ n ];
if( USHRT_MAX != GetRedlineTbl().GetPos( pTmp ) )
{
SwPosition* pEnd = pTmp->End();
pEnd->nNode = aIdx;
pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
}
}
}
if( aSaveRedl.Count() )
lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
if( pUndo )
{
ClearRedo();
pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
AppendUndo( pUndo );
}
if( pSaveInsPos )
delete pSaveInsPos;
if( bUpdateFtn )
{
if( aTmpFntIdx.Count() )
{
GetFtnIdxs().Insert( &aTmpFntIdx );
aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
}
GetFtnIdxs().UpdateAllFtn();
}
SetModified();
return sal_True;
}
/* #107318# Convert list of ranges of whichIds to a corresponding list
of whichIds*/
SvUShorts * lcl_RangesToUShorts(USHORT * pRanges)
{
SvUShorts * pResult = new SvUShorts();
int i = 0;
while (pRanges[i] != 0)
{
ASSERT(pRanges[i+1] != 0, "malformed ranges");
for (USHORT j = pRanges[i]; j < pRanges[i+1]; j++)
pResult->Insert(j, pResult->Count());
i += 2;
}
return pResult;
}
bool lcl_StrLenOverFlow( const SwPaM& rPam )
{
// If we try to merge two paragraph we have to test if afterwards
// the string doesn't exceed the allowed string length
bool bRet = false;
if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
{
const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
{
sal_uInt64 nSum = pStt->nContent.GetIndex() +
pEndNd->GetTxt().Len() - pEnd->nContent.GetIndex();
if( nSum > STRING_LEN )
bRet = true;
}
}
return bRet;
}
void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
{
rJoinTxt = sal_False;
rJoinPrev = sal_False;
if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
{
const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
if( pSttNd )
{
SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
rJoinTxt = 0 != pEndNd;
if( rJoinTxt )
{
bool bExchange = pStt == rPam.GetPoint();
if( !pStt->nContent.GetIndex() &&
pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() )
bExchange = !bExchange;
if( bExchange )
rPam.Exchange();
rJoinPrev = rPam.GetPoint() == pStt;
ASSERT( !pStt->nContent.GetIndex() &&
pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex()
? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
: rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
"lcl_GetJoinFlags");
}
}
}
}
void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
{
SwNodeIndex aIdx( rPam.GetPoint()->nNode );
SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
SwNodeIndex aOldIdx( aIdx );
SwTxtNode *pOldTxtNd = pTxtNd;
if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
{
SwDoc* pDoc = rPam.GetDoc();
if( bJoinPrev )
{
// N.B.: we do not need to handle xmlids in this case, because
// it is only invoked if one paragraph is completely empty
// (see lcl_GetJoinFlags)
{
// falls PageBreaks geloescht / gesetzt werden, darf das
// nicht in die Undo-History aufgenommen werden !!
// (das loeschen vom Node geht auch am Undo vorbei !!!)
sal_Bool bDoUndo = pDoc->DoesUndo();
pDoc->DoUndo( sal_False );
/* PageBreaks, PageDesc, ColumnBreaks */
// Sollte an der Logik zum Kopieren der PageBreak's ...
// etwas geaendert werden, muss es auch im SwUndoDelete
// geandert werden. Dort wird sich das AUTO-PageBreak
// aus dem GetMarkNode kopiert.!!!
/* Der GetMarkNode */
if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
{
const SfxPoolItem* pItem;
if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
RES_BREAK, sal_False, &pItem ) )
pTxtNd->ResetAttr( RES_BREAK );
if( pTxtNd->HasSwAttrSet() &&
SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
RES_PAGEDESC, sal_False, &pItem ) )
pTxtNd->ResetAttr( RES_PAGEDESC );
}
/* Der PointNode */
if( pOldTxtNd->HasSwAttrSet() )
{
const SfxPoolItem* pItem;
SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
sal_False, &pItem ) )
aSet.Put( *pItem );
if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
aSet.Put( *pItem );
if( aSet.Count() )
pTxtNd->SetAttr( aSet );
}
pOldTxtNd->FmtToTxtAttr( pTxtNd );
SvULongs aBkmkArr( 15, 15 );
::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
pOldTxtNd->Len(), aBkmkArr );
SwIndex aAlphaIdx(pTxtNd);
pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
pOldTxtNd->Len() );
SwPosition aAlphaPos( aIdx, aAlphaIdx );
pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
// verschiebe noch alle Bookmarks/TOXMarks
if( aBkmkArr.Count() )
::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
pDoc->DoUndo( bDoUndo );
// falls der uebergebene PaM nicht im Crsr-Ring steht,
// gesondert behandeln (z.B. Aufruf aus dem Auto-Format)
if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
rPam.GetBound( sal_True ) = aAlphaPos;
if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
rPam.GetBound( sal_False ) = aAlphaPos;
}
// jetzt nur noch den Node loeschen
pDoc->GetNodes().Delete( aOldIdx, 1 );
}
else
{
SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
if( pTxtNd->Len() )
pDelNd->FmtToTxtAttr( pTxtNd );
else
{
/* #107318# This case was missed:
<something></something> <-- pTxtNd
<other>ccc</other> <-- pDelNd
<something> and <other> are paragraph
attributes. The attribute <something> stayed if not
overwritten by an attribute in "ccc". Fixed by
first resetting all character attributes in first
paragraph (pTxtNd).
*/
SvUShorts * pShorts =
lcl_RangesToUShorts(aCharFmtSetRange);
pTxtNd->ResetAttr(*pShorts);
delete pShorts;
if( pDelNd->HasSwAttrSet() )
{
// nur die Zeichenattribute kopieren
SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
pTxtNd->SetAttr( aTmpSet );
}
}
pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
// --> OD 2009-08-20 #i100466#
// adjust given <rPam>, if it does not belong to the cursors
if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
{
rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
}
if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
{
rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
}
// <--
pTxtNd->JoinNext();
}
}
}
static void
lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam )
{
SwTxtNode const * const pTxtNode(
rPam.End()->nNode.GetNode().GetTxtNode() );
if (!pTxtNode)
return; // left-overlap only possible at end of selection...
const xub_StrLen nStart(rPam.Start()->nContent.GetIndex());
const xub_StrLen nEnd (rPam.End ()->nContent.GetIndex());
if (nEnd == pTxtNode->Len())
return; // paragraph selected until the end
for (xub_StrLen i = nStart; i < nEnd; ++i)
{
const sal_Unicode c(pTxtNode->GetTxt().GetChar(i));
if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
{
SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
if (pAttr && pAttr->GetEnd() && (*pAttr->GetEnd() > nEnd))
{
ASSERT(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
rBreaks.push_back(i);
}
}
}
}
bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
{
::std::vector<xub_StrLen> Breaks;
lcl_CalcBreaks(Breaks, rPam);
if (!Breaks.size())
{
return (rDoc.*pFunc)(rPam, bForceJoinNext);
}
// N.B.: deletion must be split into several parts if the text node
// contains a text attribute with end and with dummy character
// and the selection does not contain the text attribute completely,
// but overlaps its start (left), where the dummy character is.
SwPosition const & rSelectionEnd( *rPam.End() );
bool bRet( true );
// iterate from end to start, to avoid invalidating the offsets!
::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
SwPosition & rEnd( *aPam.End() );
SwPosition & rStart( *aPam.Start() );
while (iter != Breaks.rend())
{
rStart.nContent = *iter + 1;
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
}
rEnd.nContent = *iter;
++iter;
}
rStart = *rPam.Start(); // set to original start
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
}
return bRet;
}
bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
{
ASSERT( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
{
sal_uInt16 nUndoSize = 0;
SwUndoRedlineDelete* pUndo = 0;
RedlineMode_t eOld = GetRedlineMode();
checkRedlining(eOld);
if( DoesUndo() )
{
ClearRedo();
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode(
(RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
nUndoSize = pUndos->Count();
StartUndo(UNDO_EMPTY, NULL);
AppendUndo( pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE ));
}
if( *rPam.GetPoint() != *rPam.GetMark() )
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true);
SetModified();
if( pUndo )
{
EndUndo(UNDO_EMPTY, NULL);
SwUndo* pPrevUndo;
if( nUndoSize && DoesGroupUndo() &&
nUndoSize + 1 == pUndos->Count() &&
UNDO_REDLINE == ( pPrevUndo = (*pUndos)[ nUndoSize-1 ])->GetId() &&
UNDO_DELETE == ((SwUndoRedline*)pPrevUndo)->GetUserId() &&
((SwUndoRedlineDelete*)pPrevUndo)->CanGrouping( *pUndo ))
{
DoUndo( sal_False );
pUndos->DeleteAndDestroy( nUndoSize, 1 );
--nUndoPos, --nUndoCnt;
DoUndo( sal_True );
}
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( eOld );
}
return true;
}
}
bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
const bool bForceJoinNext )
{
sal_Bool bJoinTxt, bJoinPrev;
lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
// --> OD 2009-08-20 #i100466#
if ( bForceJoinNext )
{
bJoinPrev = sal_False;
}
// <--
{
// dann eine Kopie vom Cursor erzeugen um alle Pams aus den
// anderen Sichten aus dem Loeschbereich zu verschieben
// ABER NICHT SICH SELBST !!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
const bool bSuccess( DeleteRangeImpl( aDelPam ) );
if (!bSuccess)
return false;
*rPam.GetPoint() = *aDelPam.GetPoint();
}
if( bJoinTxt )
{
lcl_JoinText( rPam, bJoinPrev );
}
return true;
}
bool SwDoc::DeleteRangeImpl( SwPaM & rPam, const bool )
{
SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
if( !rPam.HasMark() || *pStt >= *pEnd )
return false;
if( pACEWord )
{
// ggfs. das gesicherte Word fuer die Ausnahme
if( pACEWord->IsDeleted() || pStt->nNode != pEnd->nNode ||
pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
!pACEWord->CheckDelChar( *pStt ))
delete pACEWord, pACEWord = 0;
}
{
// loesche alle leeren TextHints an der Mark-Position
SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
SwpHints* pHts;
if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
{
const xub_StrLen *pEndIdx;
xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex();
for( sal_uInt16 n = pHts->Count(); n; )
{
const SwTxtAttr* pAttr = (*pHts)[ --n ];
if( nMkCntPos > *pAttr->GetStart() )
break;
if( nMkCntPos == *pAttr->GetStart() &&
0 != (pEndIdx = pAttr->GetEnd()) &&
*pEndIdx == *pAttr->GetStart() )
pTxtNd->DestroyAttr( pHts->Cut( n ) );
}
}
}
{
// Bug 26675: DataChanged vorm loeschen verschicken, dann bekommt
// man noch mit, welche Objecte sich im Bereich befinden.
// Danach koennen sie vor/hinter der Position befinden.
SwDataChanged aTmp( rPam, 0 );
}
if( DoesUndo() )
{
ClearRedo();
sal_uInt16 nUndoSize = pUndos->Count();
SwUndo * pUndo;
if( DoesGroupUndo() && nUndoSize-- &&
UNDO_DELETE == ( pUndo = (*pUndos)[ nUndoSize ])->GetId() &&
((SwUndoDelete*)pUndo)->CanGrouping( this, rPam ))
;// wenn CanGrouping() sal_True returnt, ist schon alles erledigt
else
AppendUndo( new SwUndoDelete( rPam ) );
SetModified();
return true;
}
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
DeleteRedline( rPam, true, USHRT_MAX );
// loesche und verschiebe erstmal alle "Fly's am Absatz", die in der
// Selection liegen
DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
_DelBookmarks(
pStt->nNode,
pEnd->nNode,
NULL,
&pStt->nContent,
&pEnd->nContent);
SwNodeIndex aSttIdx( pStt->nNode );
SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
do { // middle checked loop!
if( pCNd )
{
SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
if ( pStartTxtNode )
{
// verschiebe jetzt noch den Inhalt in den neuen Node
sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex()
: pCNd->Len() )
- pStt->nContent.GetIndex();
// falls schon leer, dann nicht noch aufrufen
if( nLen )
{
pStartTxtNode->EraseText( pStt->nContent, nLen );
if( !pStartTxtNode->Len() )
{
// METADATA: remove reference if empty (consider node deleted)
pStartTxtNode->RemoveMetadataReference();
}
}
if( bOneNd ) // das wars schon
break;
aSttIdx++;
}
else
{
// damit beim loeschen keine Indizies mehr angemeldet sind,
// wird hier der SwPaM aus dem Content entfernt !!
pStt->nContent.Assign( 0, 0 );
}
}
pCNd = pEnd->nNode.GetNode().GetCntntNode();
if( pCNd )
{
SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
if( pEndTxtNode )
{
// falls schon leer, dann nicht noch aufrufen
if( pEnd->nContent.GetIndex() )
{
SwIndex aIdx( pCNd, 0 );
pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
if( !pEndTxtNode->Len() )
{
// METADATA: remove reference if empty (consider node deleted)
pEndTxtNode->RemoveMetadataReference();
}
}
}
else
{
// damit beim Loeschen keine Indizies mehr angemeldet sind,
// wird hier der SwPaM aus dem Content entfernt !!
pEnd->nContent.Assign( 0, 0 );
}
}
// if the end is not a content node, delete it as well
sal_uInt32 nEnde = pEnd->nNode.GetIndex();
if( pCNd == NULL )
nEnde++;
if( aSttIdx != nEnde )
{
// loesche jetzt die Nodes in das NodesArary
GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
}
// falls der Node geloescht wurde, in dem der Cursor stand, so
// muss der Content im akt. Content angemeldet werden !!!
pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
pStt->nContent.GetIndex() );
// der PaM wird korrigiert, denn falls ueber Nodegrenzen geloescht
// wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
// wird aufgehoben !
*pEnd = *pStt;
rPam.DeleteMark();
} while( sal_False );
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
CompressRedlines();
SetModified();
return true;
}
// OD 2009-08-20 #i100466#
// Add handling of new optional parameter <bForceJoinNext>
bool SwDoc::DeleteAndJoin( SwPaM & rPam,
const bool bForceJoinNext )
{
if ( lcl_StrLenOverFlow( rPam ) )
return false;
return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
? &SwDoc::DeleteAndJoinWithRedlineImpl
: &SwDoc::DeleteAndJoinImpl,
bForceJoinNext );
}
bool SwDoc::DeleteRange( SwPaM & rPam )
{
return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
}
void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper::ConversionMap* pConversionMap )
{
if( rTxtNode.IsGrammarCheckDirty() )
return;
SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
USHORT i, j = 0;
if( pWrong )
{
for( i = 0; i < rResult.aErrors.getLength(); ++i )
{
const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
xub_StrLen nStart = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos;
xub_StrLen nEnd = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos;
if( i != j )
pArray[j] = pArray[i];
if( pWrong->LookForEntry( nStart, nEnd ) )
++j;
}
}
if( rResult.aErrors.getLength() > j )
rResult.aErrors.realloc( j );
}
uno::Any SwDoc::Spell( SwPaM& rPaM,
uno::Reference< XSpellChecker1 > &xSpeller,
sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
bool bGrammarCheck,
SwConversionArgs *pConvArgs ) const
{
SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
SwSpellArgs *pSpellArgs = 0;
//SwConversionArgs *pConvArgs = 0;
if (pConvArgs)
{
pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
}
else
pSpellArgs = new SwSpellArgs( xSpeller,
pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
bGrammarCheck );
ULONG nCurrNd = pSttPos->nNode.GetIndex();
ULONG nEndNd = pEndPos->nNode.GetIndex();
uno::Any aRet;
if( nCurrNd <= nEndNd )
{
SwCntntFrm* pCntFrm;
sal_Bool bGoOn = sal_True;
while( bGoOn )
{
SwNode* pNd = GetNodes()[ nCurrNd ];
switch( pNd->GetNodeType() )
{
case ND_TEXTNODE:
if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->GetFrm()) )
{
// geschutze Cellen/Flys ueberspringen, ausgeblendete
//ebenfalls
if( pCntFrm->IsProtected() )
{
nCurrNd = pNd->EndOfSectionIndex();
}
else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
{
if( pPageCnt && *pPageCnt && pPageSt )
{
sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
if( !*pPageSt )
{
*pPageSt = nPageNr;
if( *pPageCnt < *pPageSt )
*pPageCnt = *pPageSt;
}
long nStat;
if( nPageNr >= *pPageSt )
nStat = nPageNr - *pPageSt + 1;
else
nStat = nPageNr + *pPageCnt - *pPageSt + 1;
::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
}
//Spell() changes the pSpellArgs in case an error is found
xub_StrLen nBeginGrammarCheck = 0;
xub_StrLen nEndGrammarCheck = 0;
if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
{
nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
// if grammar checking starts inside of a sentence the start position has to be adjusted
if( nBeginGrammarCheck )
{
SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
SwPosition aStart( *pNd, aStartIndex );
SwCursor aCrsr(aStart, 0, false);
SwPosition aOrigPos = *aCrsr.GetPoint();
aCrsr.GoSentence( SwCursor::START_SENT );
if( aOrigPos != *aCrsr.GetPoint() )
{
nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
}
}
nEndGrammarCheck = pSpellArgs->pEndNode == pNd ? pSpellArgs->pEndIdx->GetIndex() : ((SwTxtNode*)pNd)->GetTxt().Len();
}
xub_StrLen nSpellErrorPosition = ((SwTxtNode*)pNd)->GetTxt().Len();
if( (!pConvArgs &&
((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
( pConvArgs &&
((SwTxtNode*)pNd)->Convert( *pConvArgs )))
{
// Abbrechen und Position merken
pSttPos->nNode = nCurrNd;
pEndPos->nNode = nCurrNd;
nCurrNd = nEndNd;
if( pSpellArgs )
nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
pSpellArgs->pEndIdx->GetIndex() :
pSpellArgs->pStartIdx->GetIndex();
}
if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
{
uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
if (xGCIterator.is())
{
String aText( ((SwTxtNode*)pNd)->GetTxt().Copy( nBeginGrammarCheck, nEndGrammarCheck - nBeginGrammarCheck ) );
uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
// Expand the string:
rtl::OUString aExpandText;
const ModelToViewHelper::ConversionMap* pConversionMap =
((SwTxtNode*)pNd)->BuildConversionMap( aExpandText );
// get XFlatParagraph to use...
uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, pConversionMap );
// get error position of cursor in XFlatParagraph
sal_Int32 nGrammarErrorPosInText;
linguistic2::ProofreadingResult aResult;
sal_Int32 nGrammarErrors;
do
{
nGrammarErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBeginGrammarCheck );
aResult = xGCIterator->checkSentenceAtPosition(
xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, pConversionMap );
// get suggestions to use for the specific error position
nGrammarErrors = aResult.aErrors.getLength();
// if grammar checking doesn't have any progress then quit
if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
break;
// prepare next iteration
nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition;
}
while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
{
aRet <<= aResult;
//put the cursor to the current error
const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
nCurrNd = pNd->GetIndex();
pSttPos->nNode = nCurrNd;
pEndPos->nNode = nCurrNd;
pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos );
pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos );
nCurrNd = nEndNd;
}
}
}
}
}
break;
case ND_SECTIONNODE:
if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
nCurrNd = pNd->EndOfSectionIndex();
break;
case ND_ENDNODE:
{
break;
}
}
bGoOn = nCurrNd < nEndNd;
++nCurrNd;
}
}
if( !aRet.hasValue() )
{
if (pConvArgs)
aRet <<= pConvArgs->aConvText;
else
aRet <<= pSpellArgs->xSpellAlt;
}
delete pSpellArgs;
return aRet;
}
class SwHyphArgs : public SwInterHyphInfo
{
const SwNode *pStart;
const SwNode *pEnd;
SwNode *pNode;
sal_uInt16 *pPageCnt;
sal_uInt16 *pPageSt;
sal_uInt32 nNode;
xub_StrLen nPamStart;
xub_StrLen nPamLen;
public:
SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
sal_uInt16* pPageCount, sal_uInt16* pPageStart );
void SetPam( SwPaM *pPam ) const;
inline void SetNode( SwNode *pNew ) { pNode = pNew; }
inline const SwNode *GetNode() const { return pNode; }
inline void SetRange( const SwNode *pNew );
inline void NextNode() { ++nNode; }
inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
inline sal_uInt16 *GetPageSt() { return pPageSt; }
};
SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
sal_uInt16* pPageCount, sal_uInt16* pPageStart )
: SwInterHyphInfo( rCrsrPos ), pNode(0),
pPageCnt( pPageCount ), pPageSt( pPageStart )
{
// Folgende Bedingungen muessen eingehalten werden:
// 1) es gibt mindestens eine Selektion
// 2) SPoint() == Start()
ASSERT( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
ASSERT( *pPam->GetPoint() <= *pPam->GetMark(),
"SwDoc::Hyphenate: New York, New York");
const SwPosition *pPoint = pPam->GetPoint();
nNode = pPoint->nNode.GetIndex();
// Start einstellen
pStart = pPoint->nNode.GetNode().GetTxtNode();
nPamStart = pPoint->nContent.GetIndex();
// Ende und Laenge einstellen.
const SwPosition *pMark = pPam->GetMark();
pEnd = pMark->nNode.GetNode().GetTxtNode();
nPamLen = pMark->nContent.GetIndex();
if( pPoint->nNode == pMark->nNode )
nPamLen = nPamLen - pPoint->nContent.GetIndex();
}
inline void SwHyphArgs::SetRange( const SwNode *pNew )
{
nStart = pStart == pNew ? nPamStart : 0;
nLen = pEnd == pNew ? nPamLen : STRING_NOTFOUND;
}
void SwHyphArgs::SetPam( SwPaM *pPam ) const
{
if( !pNode )
*pPam->GetPoint() = *pPam->GetMark();
else
{
pPam->GetPoint()->nNode = nNode;
pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
pPam->GetMark()->nNode = nNode;
pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
nWordStart + nWordLen );
ASSERT( nNode == pNode->GetIndex(),
"SwHyphArgs::SetPam: Pam desaster" );
}
}
// liefert sal_True zurueck, wenn es weitergehen soll.
sal_Bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
{
// Hyphenate liefert sal_True zurueck, wenn eine Trennstelle anliegt
// und stellt pPam ein.
SwTxtNode *pNode = rpNd->GetTxtNode();
SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
if( pNode )
{
SwCntntFrm* pCntFrm = pNode->GetFrm();
if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
{
sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
if( pPageCnt && *pPageCnt && pPageSt )
{
sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
if( !*pPageSt )
{
*pPageSt = nPageNr;
if( *pPageCnt < *pPageSt )
*pPageCnt = *pPageSt;
}
long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
: nPageNr + *pPageCnt - *pPageSt + 1;
::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
}
pHyphArgs->SetRange( rpNd );
if( pNode->Hyphenate( *pHyphArgs ) )
{
pHyphArgs->SetNode( rpNd );
return sal_False;
}
}
}
pHyphArgs->NextNode();
return sal_True;
}
uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
SwPaM *pPam, const Point &rCrsrPos,
sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
{
ASSERT(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
if( *pPam->GetPoint() > *pPam->GetMark() )
pPam->Exchange();
SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
lcl_HyphenateNode, &aHyphArg );
aHyphArg.SetPam( pPam );
return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
}
sal_Bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, sal_Bool bRegExpRplc )
{
sal_Bool bRet = sal_False;
if( bRegExpRplc )
{
xub_StrLen nPos = 0;
String sPara( String::CreateFromAscii(
RTL_CONSTASCII_STRINGPARAM( "\\n" )));
while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) )
{
// wurde das escaped?
if( nPos && '\\' == rStr.GetChar( nPos-1 ))
{
if( ++nPos >= rStr.Len() )
break;
}
else
{
rRet = rStr.Copy( 0, nPos );
rStr.Erase( 0, nPos + sPara.Len() );
bRet = sal_True;
break;
}
}
}
if( !bRet )
{
rRet = rStr;
rStr.Erase();
}
return bRet;
}
bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr,
const bool bRegExReplace )
{
// unfortunately replace works slightly differently from delete,
// so we cannot use lcl_DoWithBreaks here...
::std::vector<xub_StrLen> Breaks;
SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
aPam.Normalize(FALSE);
if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
{
aPam.Move(fnMoveBackward);
}
ASSERT((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
lcl_CalcBreaks(Breaks, aPam);
while (!Breaks.empty() // skip over prefix of dummy chars
&& (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
{
// skip!
++aPam.GetMark()->nContent; // always in bounds if Breaks valid
Breaks.erase(Breaks.begin());
}
*rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
if (!Breaks.size())
{
return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
}
// N.B.: deletion must be split into several parts if the text node
// contains a text attribute with end and with dummy character
// and the selection does not contain the text attribute completely,
// but overlaps its start (left), where the dummy character is.
bool bRet( true );
// iterate from end to start, to avoid invalidating the offsets!
::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
ASSERT(aPam.GetPoint() == aPam.End(), "wrong!");
SwPosition & rEnd( *aPam.End() );
SwPosition & rStart( *aPam.Start() );
// set end of temp pam to original end (undo Move backward above)
rEnd = *rPam.End();
// after first deletion, rEnd will point into the original text node again!
while (iter != Breaks.rend())
{
rStart.nContent = *iter + 1;
if (rEnd.nContent != rStart.nContent) // check if part is empty
{
bRet &= (IsRedlineOn())
? DeleteAndJoinWithRedlineImpl(aPam)
: DeleteAndJoinImpl(aPam, false);
}
rEnd.nContent = *iter;
++iter;
}
rStart = *rPam.Start(); // set to original start
ASSERT(rEnd.nContent > rStart.nContent, "replace part empty!");
if (rEnd.nContent > rStart.nContent) // check if part is empty
{
bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
}
rPam = aPam; // update original pam (is this required?)
return bRet;
}
// N.B.: it is possible to call Replace with a PaM that spans 2 paragraphs:
// search with regex for "$", then replace _all_
bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr,
const bool bRegExReplace )
{
if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
return false;
sal_Bool bJoinTxt, bJoinPrev;
lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
{
// dann eine Kopie vom Cursor erzeugen um alle Pams aus den
// anderen Sichten aus dem Loeschbereich zu verschieben
// ABER NICHT SICH SELBST !!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
SwPosition *pStt = (SwPosition*)aDelPam.Start(),
*pEnd = (SwPosition*)aDelPam.End();
ASSERT( pStt->nNode == pEnd->nNode ||
( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
!pEnd->nContent.GetIndex() ),
"invalid range: Point and Mark on different nodes" );
sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
// eigenes Undo ????
String sRepl( rStr );
SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
xub_StrLen nStt = pStt->nContent.GetIndex(),
nEnd = bOneNode ? pEnd->nContent.GetIndex()
: pTxtNd->GetTxt().Len();
SwDataChanged aTmp( aDelPam, 0 );
if( IsRedlineOn() )
{
RedlineMode_t eOld = GetRedlineMode();
checkRedlining(eOld);
if( DoesUndo() )
{
StartUndo(UNDO_EMPTY, NULL);
// Bug 68584 - if any Redline will change (split!) the node
const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode(
(RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
*aDelPam.GetPoint() = pBkmk->GetMarkPos();
if(pBkmk->IsExpanded())
*aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
getIDocumentMarkAccess()->deleteMark(pBkmk);
pStt = aDelPam.Start();
pTxtNd = pStt->nNode.GetNode().GetTxtNode();
nStt = pStt->nContent.GetIndex();
}
if( sRepl.Len() )
{
// Attribute des 1. Zeichens ueber den ReplaceText setzen
SfxItemSet aSet( GetAttrPool(),
RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
0 );
pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
aSet.ClearItem( RES_TXTATR_REFMARK );
aSet.ClearItem( RES_TXTATR_TOXMARK );
aSet.ClearItem( RES_TXTATR_CJK_RUBY );
aSet.ClearItem( RES_TXTATR_INETFMT );
aSet.ClearItem( RES_TXTATR_META );
aSet.ClearItem( RES_TXTATR_METAFIELD );
if( aDelPam.GetPoint() != aDelPam.End() )
aDelPam.Exchange();
// das Ende merken
SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
sal_Bool bFirst = sal_True;
String sIns;
while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
{
InsertString( aDelPam, sIns );
if( bFirst )
{
SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
SplitNode( *aDelPam.GetPoint(), false );
aMkNd++;
aDelPam.GetMark()->nNode = aMkNd;
aDelPam.GetMark()->nContent.Assign(
aMkNd.GetNode().GetCntntNode(), nMkCnt );
bFirst = sal_False;
}
else
SplitNode( *aDelPam.GetPoint(), false );
}
if( sIns.Len() )
{
InsertString( aDelPam, sIns );
}
SwPaM aTmpRange( *aDelPam.GetPoint() );
aTmpRange.SetMark();
aPtNd++;
aDelPam.GetPoint()->nNode = aPtNd;
aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
nPtCnt);
*aTmpRange.GetMark() = *aDelPam.GetPoint();
RstTxtAttrs( aTmpRange );
InsertItemSet( aTmpRange, aSet, 0 );
}
if( DoesUndo() )
AppendUndo( new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE ));
AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
*rPam.GetMark() = *aDelPam.GetMark();
if( DoesUndo() )
{
*aDelPam.GetPoint() = *rPam.GetPoint();
EndUndo(UNDO_EMPTY, NULL);
// Bug 68584 - if any Redline will change (split!) the node
const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
SwIndex& rIdx = aDelPam.GetPoint()->nContent;
rIdx.Assign( 0, 0 );
aDelPam.GetMark()->nContent = rIdx;
rPam.GetPoint()->nNode = 0;
rPam.GetPoint()->nContent = rIdx;
*rPam.GetMark() = *rPam.GetPoint();
//JP 06.01.98: MUSS noch optimiert werden!!!
SetRedlineMode( eOld );
*rPam.GetPoint() = pBkmk->GetMarkPos();
if(pBkmk->IsExpanded())
*rPam.GetMark() = pBkmk->GetOtherMarkPos();
getIDocumentMarkAccess()->deleteMark(pBkmk);
}
bJoinTxt = sal_False;
}
else
{
if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
DeleteRedline( aDelPam, true, USHRT_MAX );
SwUndoReplace* pUndoRpl = 0;
if( DoesUndo() )
{
ClearRedo();
SwUndo* pU;
if( !pUndos->Count() ||
UNDO_REPLACE != ( pU = (*pUndos)[ pUndos->Count()-1 ])->GetId() ||
( pUndoRpl = (SwUndoReplace*)pU )->IsFull() )
{
pUndoRpl = new SwUndoReplace();
AppendUndo( pUndoRpl );
}
pUndoRpl->AddEntry( aDelPam, sRepl, bRegExReplace );
DoUndo( sal_False );
}
if( aDelPam.GetPoint() != pStt )
aDelPam.Exchange();
SwNodeIndex aPtNd( pStt->nNode, -1 );
xub_StrLen nPtCnt = pStt->nContent.GetIndex();
// die Werte nochmal setzen, falls schohn Rahmen oder Fussnoten
// auf dem Text entfernt wurden!
nStt = nPtCnt;
nEnd = bOneNode ? pEnd->nContent.GetIndex()
: pTxtNd->GetTxt().Len();
sal_Bool bFirst = sal_True;
String sIns;
while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
{
if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
{
InsertString( aDelPam, sIns );
}
else if( nStt < nEnd || sIns.Len() )
{
pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
}
SplitNode( *pStt, false);
bFirst = sal_False;
}
if( bFirst || sIns.Len() )
{
if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
{
InsertString( aDelPam, sIns );
}
else if( nStt < nEnd || sIns.Len() )
{
pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
}
}
*rPam.GetMark() = *aDelPam.GetMark();
aPtNd++;
rPam.GetMark()->nNode = aPtNd;
rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
nPtCnt );
if( bJoinTxt )
rPam.Move( fnMoveBackward );
if( pUndoRpl )
{
pUndoRpl->SetEntryEnd( rPam );
DoUndo( sal_True );
}
}
}
if( bJoinTxt )
lcl_JoinText( rPam, bJoinPrev );
SetModified();
return true;
}
// speicher die akt. Werte fuer die automatische Aufnahme von Ausnahmen
// in die Autokorrektur
void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
{
if( pACEWord && pNew != pACEWord )
delete pACEWord;
pACEWord = pNew;
}
bool SwDoc::DelFullPara( SwPaM& rPam )
{
const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
const SwNode* pNd = &rStt.nNode.GetNode();
sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
pNd->StartOfSectionIndex();
sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
/* #i9185# Prevent getting the node after the end node (see below) */
rEnd.nNode.GetIndex() + 1 == aNodes.Count() )
return sal_False;
// harte SeitenUmbrueche am nachfolgenden Node verschieben
sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
/* #i9185# This whould lead to a segmentation fault if not catched
above. */
ULONG nNextNd = rEnd.nNode.GetIndex() + 1;
SwTableNode* pTblNd = aNodes[ nNextNd ]->GetTableNode();
if( pTblNd && pNd->IsCntntNode() )
{
SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
//JP 24.08.98: will man wirklich den PageDesc/Break vom
// nachfolgen Absatz ueberbuegeln?
// const SwAttrSet& rAttrSet = pTableFmt->GetAttrSet();
// if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
// SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
{
const SfxPoolItem *pItem;
const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
sal_False, &pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
bSavePageDesc = sal_True;
}
if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
sal_False, &pItem ) )
{
pTableFmt->SetFmtAttr( *pItem );
bSavePageBreak = sal_True;
}
}
}
sal_Bool bDoesUndo = DoesUndo();
if( bDoesUndo )
{
if( !rPam.HasMark() )
rPam.SetMark();
else if( rPam.GetPoint() == &rStt )
rPam.Exchange();
rPam.GetPoint()->nNode++;
SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
bool bGoNext = (0 == pTmpNode);
pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
ClearRedo();
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
{
SwPosition aTmpPos( *aDelPam.GetPoint() );
if( bGoNext )
{
pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
aTmpPos.nContent.Assign( pTmpNode, 0 );
}
::PaMCorrAbs( aDelPam, aTmpPos );
}
SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
*rPam.GetPoint() = *aDelPam.GetPoint();
pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
AppendUndo( pUndo );
}
else
{
SwNodeRange aRg( rStt.nNode, rEnd.nNode );
if( rPam.GetPoint() != &rEnd )
rPam.Exchange();
// versuche hinters Ende zu verschieben
if( !rPam.Move( fnMoveForward, fnGoNode ) )
{
// na gut, dann an den Anfang
rPam.Exchange();
if( !rPam.Move( fnMoveBackward, fnGoNode ))
{
ASSERT( sal_False, "kein Node mehr vorhanden" );
return sal_False;
}
}
// text::Bookmarks usw. verschieben
CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
// was ist mit Fly's ??
{
// stehen noch FlyFrames rum, loesche auch diese
const SwPosition* pAPos;
for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n )
{
SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
{
DelLayoutFmt( pFly );
--n;
}
}
}
SwCntntNode *pTmpNode = rPam.GetBound( TRUE ).nNode.GetNode().GetCntntNode();
rPam.GetBound( TRUE ).nContent.Assign( pTmpNode, 0 );
pTmpNode = rPam.GetBound( FALSE ).nNode.GetNode().GetCntntNode();
rPam.GetBound( FALSE ).nContent.Assign( pTmpNode, 0 );
GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
}
rPam.DeleteMark();
SetModified();
return sal_True;
}
void SwDoc::TransliterateText( const SwPaM& rPaM,
utl::TransliterationWrapper& rTrans )
{
SwUndoTransliterate* pUndo;
if( DoesUndo() )
pUndo = new SwUndoTransliterate( rPaM, rTrans );
else
pUndo = 0;
const SwPosition* pStt = rPaM.Start(),
* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
: rPaM.GetPoint();
ULONG nSttNd = pStt->nNode.GetIndex(), nEndNd = pEnd->nNode.GetIndex();
xub_StrLen nSttCnt = pStt->nContent.GetIndex(),
nEndCnt = pEnd->nContent.GetIndex();
SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
if( pStt == pEnd && pTNd ) // no region ?
{
Boundary aBndry;
if( pBreakIt->GetBreakIter().is() )
aBndry = pBreakIt->GetBreakIter()->getWordBoundary(
pTNd->GetTxt(), nSttCnt,
pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
TRUE );
if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
{
nSttCnt = (xub_StrLen)aBndry.startPos;
nEndCnt = (xub_StrLen)aBndry.endPos;
}
}
if( nSttNd != nEndNd )
{
SwNodeIndex aIdx( pStt->nNode );
if( nSttCnt )
{
aIdx++;
if( pTNd )
pTNd->TransliterateText( rTrans, nSttCnt,
pTNd->GetTxt().Len(), pUndo );
}
for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
pTNd->TransliterateText( rTrans, 0, pTNd->GetTxt().Len(),
pUndo );
if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
}
else if( pTNd && nSttCnt < nEndCnt )
pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
if( pUndo )
{
if( pUndo->HasData() )
{
ClearRedo();
AppendUndo( pUndo );
}
else
delete pUndo;
}
SetModified();
}
#define MAX_REDLINE_COUNT 250
// -----------------------------------------------------------------------------
void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
{
const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
SwEditShell* pEditShell = GetEditShell();
Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
if ( pParent && !mbReadlineChecked && rRedlineTbl.Count() > MAX_REDLINE_COUNT
&& !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
{
WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION));
USHORT nResult = aWarning.Execute();
mbReadlineChecked = sal_True;
if ( nResult == RET_YES )
{
sal_Int32 nMode = (sal_Int32)_rReadlineMode;
nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
_rReadlineMode = (RedlineMode_t)nMode;
}
}
}
// -----------------------------------------------------------------------------
void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
{
// This is a modified version of SwDoc::TransliterateText
const SwPosition* pStt = rPaM.Start();
const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
: rPaM.GetPoint();
const ULONG nSttNd = pStt->nNode.GetIndex();
const ULONG nEndNd = pEnd->nNode.GetIndex();
const xub_StrLen nSttCnt = pStt->nContent.GetIndex();
const xub_StrLen nEndCnt = pEnd->nContent.GetIndex();
const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
if( pStt == pEnd && pTNd ) // no region ?
{
// do nothing
return;
}
if( nSttNd != nEndNd )
{
SwNodeIndex aIdx( pStt->nNode );
if( nSttCnt )
{
aIdx++;
if( pTNd )
pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().Len() );
}
for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
pTNd->CountWords( rStat, 0, pTNd->GetTxt().Len() );
if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
pTNd->CountWords( rStat, 0, nEndCnt );
}
else if( pTNd && nSttCnt < nEndCnt )
pTNd->CountWords( rStat, nSttCnt, nEndCnt );
}
void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
{
const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
if ( pTNd )
{
const String& rTxt = pTNd->GetTxt();
xub_StrLen nIdx = 0;
sal_Unicode cCh;
while( nIdx < rTxt.Len() &&
( '\t' == ( cCh = rTxt.GetChar( nIdx ) ) ||
( ' ' == cCh ) ) )
++nIdx;
if ( nIdx > 0 )
{
SwPaM aPam(rPos);
aPam.GetPoint()->nContent = 0;
aPam.SetMark();
aPam.GetMark()->nContent = nIdx;
DeleteRange( aPam );
}
}
}