diff options
Diffstat (limited to 'sw/source/core/doc')
46 files changed, 55486 insertions, 0 deletions
diff --git a/sw/source/core/doc/SwStyleNameMapper.cxx b/sw/source/core/doc/SwStyleNameMapper.cxx new file mode 100644 index 000000000000..d25c7d8417cb --- /dev/null +++ b/sw/source/core/doc/SwStyleNameMapper.cxx @@ -0,0 +1,1142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <SwStyleNameMapper.hxx> +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <tools/resmgr.hxx> +#include <poolfmt.hxx> +#ifndef _RDIC_HRC +#include <rcid.hrc> +#endif +#include <tools/debug.hxx> +extern ResMgr* pSwResMgr; +// Initialise UI names to 0 +SvStringsDtor *SwStyleNameMapper::pTextUINameArray = 0, + *SwStyleNameMapper::pListsUINameArray = 0, + *SwStyleNameMapper::pExtraUINameArray = 0, + *SwStyleNameMapper::pRegisterUINameArray = 0, + *SwStyleNameMapper::pDocUINameArray = 0, + *SwStyleNameMapper::pHTMLUINameArray = 0, + *SwStyleNameMapper::pFrmFmtUINameArray = 0, + *SwStyleNameMapper::pChrFmtUINameArray = 0, + *SwStyleNameMapper::pHTMLChrFmtUINameArray = 0, + *SwStyleNameMapper::pPageDescUINameArray = 0, + *SwStyleNameMapper::pNumRuleUINameArray = 0, + +// Initialise programmatic names to 0 + *SwStyleNameMapper::pTextProgNameArray = 0, + *SwStyleNameMapper::pListsProgNameArray = 0, + *SwStyleNameMapper::pExtraProgNameArray = 0, + *SwStyleNameMapper::pRegisterProgNameArray = 0, + *SwStyleNameMapper::pDocProgNameArray = 0, + *SwStyleNameMapper::pHTMLProgNameArray = 0, + *SwStyleNameMapper::pFrmFmtProgNameArray = 0, + *SwStyleNameMapper::pChrFmtProgNameArray = 0, + *SwStyleNameMapper::pHTMLChrFmtProgNameArray = 0, + *SwStyleNameMapper::pPageDescProgNameArray = 0, + *SwStyleNameMapper::pNumRuleProgNameArray = 0; + +NameToIdHash *SwStyleNameMapper::pParaUIMap = 0, + *SwStyleNameMapper::pCharUIMap = 0, + *SwStyleNameMapper::pPageUIMap = 0, + *SwStyleNameMapper::pFrameUIMap = 0, + *SwStyleNameMapper::pNumRuleUIMap = 0, + + *SwStyleNameMapper::pParaProgMap = 0, + *SwStyleNameMapper::pCharProgMap = 0, + *SwStyleNameMapper::pPageProgMap = 0, + *SwStyleNameMapper::pFrameProgMap = 0, + *SwStyleNameMapper::pNumRuleProgMap = 0; + +// SwTableEntry so we can pass the length to the String CTOR +struct SwTableEntry +{ + sal_uInt8 nLength; + const sal_Char *pChar; +}; + +#define ENTRY( s ) { sizeof (s)-1, s } + +// Hard coded Programmatic Name tables +const struct SwTableEntry TextProgNameTable [] = +{ + ENTRY( "Standard" ), // RES_POOLCOLL_STANDARD + ENTRY( "Text body" ), + ENTRY( "First line indent" ), + ENTRY( "Hanging indent" ), + ENTRY( "Text body indent" ), + ENTRY( "Salutation" ), + ENTRY( "Signature" ), + ENTRY( "List Indent" ), // RES_POOLCOLL_CONFRONTATION + ENTRY( "Marginalia" ), + ENTRY( "Heading" ), + ENTRY( "Heading 1" ), + ENTRY( "Heading 2" ), + ENTRY( "Heading 3" ), + ENTRY( "Heading 4" ), + ENTRY( "Heading 5" ), + ENTRY( "Heading 6" ), + ENTRY( "Heading 7" ), + ENTRY( "Heading 8" ), + ENTRY( "Heading 9" ), + ENTRY( "Heading 10" ), // RES_POOLCOLL_TEXT_END + { 0, NULL } +}; + +const struct SwTableEntry ListsProgNameTable [] = +{ + ENTRY( "List" ), // STR_POCO_PRGM_NUMBUL_BASE + ENTRY( "Numbering 1 Start" ), // STR_POCO_PRGM_NUM_LEVEL1S + ENTRY( "Numbering 1" ), + ENTRY( "Numbering 1 End" ), + ENTRY( "Numbering 1 Cont." ), + ENTRY( "Numbering 2 Start" ), + ENTRY( "Numbering 2" ), + ENTRY( "Numbering 2 End" ), + ENTRY( "Numbering 2 Cont." ), + ENTRY( "Numbering 3 Start" ), + ENTRY( "Numbering 3" ), + ENTRY( "Numbering 3 End" ), + ENTRY( "Numbering 3 Cont." ), + ENTRY( "Numbering 4 Start" ), + ENTRY( "Numbering 4" ), + ENTRY( "Numbering 4 End" ), + ENTRY( "Numbering 4 Cont." ), + ENTRY( "Numbering 5 Start" ), + ENTRY( "Numbering 5" ), + ENTRY( "Numbering 5 End" ), + ENTRY( "Numbering 5 Cont." ), + ENTRY( "List 1 Start" ), + ENTRY( "List 1" ), + ENTRY( "List 1 End" ), + ENTRY( "List 1 Cont." ), + ENTRY( "List 2 Start" ), + ENTRY( "List 2" ), + ENTRY( "List 2 End" ), + ENTRY( "List 2 Cont." ), + ENTRY( "List 3 Start" ), + ENTRY( "List 3" ), + ENTRY( "List 3 End" ), + ENTRY( "List 3 Cont." ), + ENTRY( "List 4 Start" ), + ENTRY( "List 4" ), + ENTRY( "List 4 End" ), + ENTRY( "List 4 Cont." ), + ENTRY( "List 5 Start" ), + ENTRY( "List 5" ), + ENTRY( "List 5 End" ), + ENTRY( "List 5 Cont." ), // STR_POCO_PRGM_BUL_NONUM5 + { 0, NULL } +}; + +const struct SwTableEntry ExtraProgNameTable [] = +{ + ENTRY( "Header" ), // RES_POOLCOLL_EXTRA_BEGIN + ENTRY( "Header left" ), + ENTRY( "Header right" ), + ENTRY( "Footer" ), + ENTRY( "Footer left" ), + ENTRY( "Footer right" ), + ENTRY( "Table Contents" ), + ENTRY( "Table Heading" ), + ENTRY( "Caption" ), + ENTRY( "Illustration" ), + ENTRY( "Table" ), + ENTRY( "Text" ), + ENTRY( "Frame contents" ), + ENTRY( "Footnote" ), + ENTRY( "Addressee" ), + ENTRY( "Sender" ), + ENTRY( "Endnote" ), + ENTRY( "Drawing" ), // RES_POOLCOLL_LABEL_DRAWING + { 0, NULL } +}; + +const struct SwTableEntry RegisterProgNameTable [] = +{ + ENTRY( "Index" ), // STR_POCO_PRGM_REGISTER_BASE + ENTRY( "Index Heading" ), // STR_POCO_PRGM_TOX_IDXH + ENTRY( "Index 1" ), + ENTRY( "Index 2" ), + ENTRY( "Index 3" ), + ENTRY( "Index Separator" ), + ENTRY( "Contents Heading" ), + ENTRY( "Contents 1" ), + ENTRY( "Contents 2" ), + ENTRY( "Contents 3" ), + ENTRY( "Contents 4" ), + ENTRY( "Contents 5" ), + ENTRY( "User Index Heading" ), + ENTRY( "User Index 1" ), + ENTRY( "User Index 2" ), + ENTRY( "User Index 3" ), + ENTRY( "User Index 4" ), + ENTRY( "User Index 5" ), + ENTRY( "Contents 6" ), + ENTRY( "Contents 7" ), + ENTRY( "Contents 8" ), + ENTRY( "Contents 9" ), + ENTRY( "Contents 10" ), + ENTRY( "Illustration Index Heading" ), + ENTRY( "Illustration Index 1" ), + ENTRY( "Object index heading" ), + ENTRY( "Object index 1" ), + ENTRY( "Table index heading" ), + ENTRY( "Table index 1" ), + ENTRY( "Bibliography Heading" ), + ENTRY( "Bibliography 1" ), + ENTRY( "User Index 6" ), + ENTRY( "User Index 7" ), + ENTRY( "User Index 8" ), + ENTRY( "User Index 9" ), + ENTRY( "User Index 10" ), // STR_POCO_PRGM_TOX_USER10 + { 0, NULL } +}; + +const struct SwTableEntry DocProgNameTable [] = +{ + ENTRY( "Title" ), // STR_POCO_PRGM_DOC_TITEL + ENTRY( "Subtitle" ), + { 0, NULL } +}; + +const struct SwTableEntry HTMLProgNameTable [] = +{ + ENTRY( "Quotations" ), + ENTRY( "Preformatted Text" ), + ENTRY( "Horizontal Line" ), + ENTRY( "List Contents" ), + ENTRY( "List Heading" ), // STR_POCO_PRGM_HTML_DT + { 0, NULL } +}; + +const struct SwTableEntry FrmFmtProgNameTable [] = +{ + ENTRY( "Frame" ), // RES_POOLFRM_FRAME + ENTRY( "Graphics" ), + ENTRY( "OLE" ), + ENTRY( "Formula" ), + ENTRY( "Marginalia" ), + ENTRY( "Watermark" ), + ENTRY( "Labels" ), // RES_POOLFRM_LABEL + { 0, NULL } +}; + +const struct SwTableEntry ChrFmtProgNameTable [] = +{ + ENTRY( "Footnote Symbol" ), // RES_POOLCHR_FOOTNOTE + ENTRY( "Page Number" ), + ENTRY( "Caption characters" ), + ENTRY( "Drop Caps" ), + ENTRY( "Numbering Symbols" ), + ENTRY( "Bullet Symbols" ), + ENTRY( "Internet link" ), + ENTRY( "Visited Internet Link" ), + ENTRY( "Placeholder" ), + ENTRY( "Index Link" ), + ENTRY( "Endnote Symbol" ), + ENTRY( "Line numbering" ), + ENTRY( "Main index entry" ), + ENTRY( "Footnote anchor" ), + ENTRY( "Endnote anchor" ), + ENTRY( "Rubies" ), // RES_POOLCHR_RUBYTEXT + ENTRY( "Vertical Numbering Symbols" ), // RES_POOLCHR_VERT_NUMBER + { 0, NULL } +}; + +const struct SwTableEntry HTMLChrFmtProgNameTable [] = +{ + ENTRY( "Emphasis" ), // RES_POOLCHR_HTML_EMPHASIS + ENTRY( "Citation" ), + ENTRY( "Strong Emphasis" ), + ENTRY( "Source Text" ), + ENTRY( "Example" ), + ENTRY( "User Entry" ), + ENTRY( "Variable" ), + ENTRY( "Definition" ), + ENTRY( "Teletype" ), // RES_POOLCHR_HTML_TELETYPE + { 0, NULL } +}; + +const struct SwTableEntry PageDescProgNameTable [] = +{ + ENTRY( "Standard" ), // STR_POOLPAGE_PRGM_STANDARD + ENTRY( "First Page" ), + ENTRY( "Left Page" ), + ENTRY( "Right Page" ), + ENTRY( "Envelope" ), + ENTRY( "Index" ), + ENTRY( "HTML" ), + ENTRY( "Footnote" ), + ENTRY( "Endnote" ), // STR_POOLPAGE_PRGM_ENDNOTE + ENTRY( "Landscape" ), + { 0, NULL } +}; + +const struct SwTableEntry NumRuleProgNameTable [] = +{ + ENTRY( "Numbering 1" ), // STR_POOLNUMRULE_PRGM_NUM1 + ENTRY( "Numbering 2" ), + ENTRY( "Numbering 3" ), + ENTRY( "Numbering 4" ), + ENTRY( "Numbering 5" ), + ENTRY( "List 1" ), + ENTRY( "List 2" ), + ENTRY( "List 3" ), + ENTRY( "List 4" ), + ENTRY( "List 5" ), // STR_POOLNUMRULE_PRGM_BUL5 + { 0, NULL } +}; +#undef ENTRY + +sal_Bool SwStyleNameMapper::SuffixIsUser ( const String & rString ) +{ + const sal_Unicode *pChar = rString.GetBuffer(); + sal_Int32 nLen = rString.Len(); + sal_Bool bRet = sal_False; + if( nLen > 8 && + pChar[nLen-7] == ' ' && + pChar[nLen-6] == '(' && + pChar[nLen-5] == 'u' && + pChar[nLen-4] == 's' && + pChar[nLen-3] == 'e' && + pChar[nLen-2] == 'r' && + pChar[nLen-1] == ')' ) + bRet = sal_True; + return bRet; +} +void SwStyleNameMapper::CheckSuffixAndDelete ( String & rString ) +{ + const sal_Unicode *pChar = rString.GetBuffer(); + xub_StrLen nLen = rString.Len(); + if (nLen > 8 && + pChar[nLen-7] == ' ' && + pChar[nLen-6] == '(' && + pChar[nLen-5] == 'u' && + pChar[nLen-4] == 's' && + pChar[nLen-3] == 'e' && + pChar[nLen-2] == 'r' && + pChar[nLen-1] == ')') + { + rString.Erase ( nLen - 7, 7 ); + } +} +const NameToIdHash & SwStyleNameMapper::getHashTable ( SwGetPoolIdFromName eFlags, sal_Bool bProgName ) +{ + NameToIdHash *pHash = 0; + const SvStringsDtor *pStrings; + + switch ( eFlags ) + { + case nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL: + { + sal_uInt16 nIndex; + sal_uInt16 nId; + + pHash = bProgName ? pParaProgMap : pParaUIMap; + if ( !pHash ) + { + pHash = new NameToIdHash ( RES_POOLCOLL_TEXT_END - RES_POOLCOLL_TEXT_BEGIN + + RES_POOLCOLL_LISTS_END - RES_POOLCOLL_LISTS_BEGIN + + RES_POOLCOLL_EXTRA_END - RES_POOLCOLL_EXTRA_BEGIN + + RES_POOLCOLL_REGISTER_END - RES_POOLCOLL_REGISTER_BEGIN + + RES_POOLCOLL_DOC_END - RES_POOLCOLL_DOC_BEGIN + + RES_POOLCOLL_HTML_END - RES_POOLCOLL_HTML_BEGIN ); + pStrings = bProgName ? &GetTextProgNameArray() : &GetTextUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_TEXT_BEGIN ; nId < RES_POOLCOLL_TEXT_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetListsProgNameArray() : &GetListsUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_LISTS_BEGIN ; nId < RES_POOLCOLL_LISTS_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetExtraProgNameArray() : &GetExtraUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_EXTRA_BEGIN ; nId < RES_POOLCOLL_EXTRA_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetRegisterProgNameArray() : &GetRegisterUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_REGISTER_BEGIN ; nId < RES_POOLCOLL_REGISTER_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetDocProgNameArray() : &GetDocUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_DOC_BEGIN ; nId < RES_POOLCOLL_DOC_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetHTMLProgNameArray() : &GetHTMLUINameArray(); + for ( nIndex = 0, nId = RES_POOLCOLL_HTML_BEGIN ; nId < RES_POOLCOLL_HTML_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + + if ( bProgName ) + pParaProgMap = pHash; + else + pParaUIMap = pHash; + } + } + break; + case nsSwGetPoolIdFromName::GET_POOLID_CHRFMT: + { + pHash = bProgName ? pCharProgMap : pCharUIMap; + if ( !pHash ) + { + sal_uInt16 nIndex; + sal_uInt16 nId; + + pHash = new NameToIdHash ( RES_POOLCHR_NORMAL_END - RES_POOLCHR_NORMAL_BEGIN + + RES_POOLCHR_HTML_END - RES_POOLCHR_HTML_BEGIN ); + pStrings = bProgName ? &GetChrFmtProgNameArray() : &GetChrFmtUINameArray(); + for ( nIndex = 0, nId = RES_POOLCHR_NORMAL_BEGIN ; nId < RES_POOLCHR_NORMAL_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + pStrings = bProgName ? &GetHTMLChrFmtProgNameArray() : &GetHTMLChrFmtUINameArray(); + for ( nIndex = 0, nId = RES_POOLCHR_HTML_BEGIN ; nId < RES_POOLCHR_HTML_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + if (bProgName ) + pCharProgMap = pHash; + else + pCharUIMap = pHash; + } + } + break; + case nsSwGetPoolIdFromName::GET_POOLID_FRMFMT: + { + pHash = bProgName ? pFrameProgMap : pFrameUIMap; + if ( !pHash ) + { + pHash = new NameToIdHash ( RES_POOLFRM_END - RES_POOLFRM_BEGIN ); + pStrings = bProgName ? &GetFrmFmtProgNameArray() : &GetFrmFmtUINameArray(); + for ( sal_uInt16 nIndex=0,nId = RES_POOLFRM_BEGIN ; nId < RES_POOLFRM_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + if ( bProgName ) + pFrameProgMap = pHash; + else + pFrameUIMap = pHash; + } + } + break; + case nsSwGetPoolIdFromName::GET_POOLID_PAGEDESC: + { + pHash = bProgName ? pPageProgMap : pPageUIMap; + if ( !pHash ) + { + pHash = new NameToIdHash ( RES_POOLPAGE_END - RES_POOLPAGE_BEGIN ); + pStrings = bProgName ? &GetPageDescProgNameArray() : &GetPageDescUINameArray(); + for ( sal_uInt16 nIndex=0,nId = RES_POOLPAGE_BEGIN ; nId < RES_POOLPAGE_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + if ( bProgName ) + pPageProgMap = pHash; + else + pPageUIMap = pHash; + } + } + break; + case nsSwGetPoolIdFromName::GET_POOLID_NUMRULE: + { + pHash = bProgName ? pNumRuleProgMap : pNumRuleUIMap; + if ( !pHash ) + { + pHash = new NameToIdHash ( RES_POOLNUMRULE_END - RES_POOLNUMRULE_BEGIN ); + pStrings = bProgName ? &GetNumRuleProgNameArray() : &GetNumRuleUINameArray(); + for ( sal_uInt16 nIndex=0,nId = RES_POOLNUMRULE_BEGIN ; nId < RES_POOLNUMRULE_END ; nId++,nIndex++ ) + (*pHash)[(*pStrings)[nIndex]] = nId; + if ( bProgName ) + pNumRuleProgMap = pHash; + else + pNumRuleUIMap = pHash; + } + } + break; + } +#ifdef _NEED_TO_DEBUG_MAPPING + static sal_Bool bTested = sal_False; + if ( !bTested ) + { + bTested = sal_True; + { + for ( sal_uInt16 nIndex = 0, nId = RES_POOLCOLL_TEXT_BEGIN ; nId < RES_POOLCOLL_TEXT_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCOLL_LISTS_BEGIN ; nId < RES_POOLCOLL_LISTS_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCOLL_EXTRA_BEGIN ; nId < RES_POOLCOLL_EXTRA_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCOLL_REGISTER_BEGIN ; nId < RES_POOLCOLL_REGISTER_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCOLL_DOC_BEGIN ; nId < RES_POOLCOLL_DOC_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCOLL_HTML_BEGIN ; nId < RES_POOLCOLL_HTML_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + } + { + for ( sal_uInt16 nIndex = 0, nId = RES_POOLCHR_NORMAL_BEGIN ; nId < RES_POOLCHR_NORMAL_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + for ( nIndex = 0, nId = RES_POOLCHR_HTML_BEGIN ; nId < RES_POOLCHR_HTML_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + } + { + for ( sal_uInt16 nIndex=0,nId = RES_POOLFRM_BEGIN ; nId < RES_POOLFRM_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + } + { + for ( sal_uInt16 nIndex=0,nId = RES_POOLPAGE_BEGIN ; nId < RES_POOLPAGE_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + } + { + for ( sal_uInt16 nIndex=0,nId = RES_POOLNUMRULE_BEGIN ; nId < RES_POOLNUMRULE_END ; nId++,nIndex++ ) + { + String aString, bString; + FillUIName ( nId, aString ); + bString = GetProgName ( nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL, aString ); + sal_uInt16 nNewId = GetPoolIdFromProgName ( bString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + FillProgName ( nNewId, aString ); + bString = GetUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + nNewId = GetPoolIdFromUIName ( aString, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); + if ( nNewId != nId ) + *((sal_Int32*)0) = 42; + } + } + } +#endif + return *pHash; +} +// This gets the UI Name from the programmatic name +const String& SwStyleNameMapper::GetUIName ( const String& rName, SwGetPoolIdFromName eFlags ) +{ + sal_uInt16 nId = GetPoolIdFromProgName ( rName, eFlags ); + return nId != USHRT_MAX ? GetUIName( nId, rName ) : rName; +} + + +// Get the programmatic Name from the UI name +const String& SwStyleNameMapper::GetProgName( const String& rName, SwGetPoolIdFromName eFlags ) +{ + sal_uInt16 nId = GetPoolIdFromUIName ( rName, eFlags ); + return nId != USHRT_MAX ? GetProgName( nId, rName ) : rName; +} + +// Get the programmatic name from the UI name in rName and put it into rFillName +void SwStyleNameMapper::FillProgName ( const String& rName, String& rFillName, SwGetPoolIdFromName eFlags, sal_Bool bDisambiguate ) +{ + sal_uInt16 nId = GetPoolIdFromUIName ( rName, eFlags ); + if ( bDisambiguate && nId == USHRT_MAX ) + { + // rName isn't in our UI name table...check if it's in the programmatic one + nId = GetPoolIdFromProgName ( rName, eFlags ); + + rFillName = rName; + if (nId == USHRT_MAX ) + { + // It isn't ...make sure the suffix isn't already " (user)"...if it is, + // we need to add another one + if ( SuffixIsUser ( rFillName ) ) + rFillName.AppendAscii ( RTL_CONSTASCII_STRINGPARAM ( " (user)" ) ); + } + else + { + // It's in the programmatic name table...append suffix + rFillName.AppendAscii ( RTL_CONSTASCII_STRINGPARAM ( " (user)" ) ); + } + } + else + { + // If we aren't trying to disambiguate, then just do a normal fill + fillNameFromId ( nId, rFillName, sal_True); + } +} +// Get the UI name from the programmatic name in rName and put it into rFillName +void SwStyleNameMapper::FillUIName ( const String& rName, String& rFillName, SwGetPoolIdFromName eFlags, sal_Bool bDisambiguate ) +{ + sal_uInt16 nId = GetPoolIdFromProgName ( rName, eFlags ); + if ( bDisambiguate && nId == USHRT_MAX ) + { + rFillName = rName; + // rName isn't in our Prog name table...check if it has a " (user)" suffix, if so remove it + CheckSuffixAndDelete ( rFillName ); + } + else + { + // If we aren't trying to disambiguate, then just do a normal fill + fillNameFromId ( nId, rFillName, sal_False); + } +} + +const String& SwStyleNameMapper::getNameFromId( sal_uInt16 nId, const String& rFillName, sal_Bool bProgName ) +{ + sal_uInt16 nStt = 0; + const SvStringsDtor* pStrArr = 0; + + switch( (USER_FMT | COLL_GET_RANGE_BITS | POOLGRP_NOCOLLID) & nId ) + { + case COLL_TEXT_BITS: + if( RES_POOLCOLL_TEXT_BEGIN <= nId && nId < RES_POOLCOLL_TEXT_END ) + { + pStrArr = bProgName ? &GetTextProgNameArray() : &GetTextUINameArray(); + nStt = RES_POOLCOLL_TEXT_BEGIN; + } + break; + case COLL_LISTS_BITS: + if( RES_POOLCOLL_LISTS_BEGIN <= nId && nId < RES_POOLCOLL_LISTS_END ) + { + pStrArr = bProgName ? &GetListsProgNameArray() : &GetListsUINameArray(); + nStt = RES_POOLCOLL_LISTS_BEGIN; + } + break; + case COLL_EXTRA_BITS: + if( RES_POOLCOLL_EXTRA_BEGIN <= nId && nId < RES_POOLCOLL_EXTRA_END ) + { + pStrArr = bProgName ? &GetExtraProgNameArray() : &GetExtraUINameArray(); + nStt = RES_POOLCOLL_EXTRA_BEGIN; + } + break; + case COLL_REGISTER_BITS: + if( RES_POOLCOLL_REGISTER_BEGIN <= nId && nId < RES_POOLCOLL_REGISTER_END ) + { + pStrArr = bProgName ? &GetRegisterProgNameArray() : &GetRegisterUINameArray(); + nStt = RES_POOLCOLL_REGISTER_BEGIN; + } + break; + case COLL_DOC_BITS: + if( RES_POOLCOLL_DOC_BEGIN <= nId && nId < RES_POOLCOLL_DOC_END ) + { + pStrArr = bProgName ? &GetDocProgNameArray() : &GetDocUINameArray(); + nStt = RES_POOLCOLL_DOC_BEGIN; + } + break; + case COLL_HTML_BITS: + if( RES_POOLCOLL_HTML_BEGIN <= nId && nId < RES_POOLCOLL_HTML_END ) + { + pStrArr = bProgName ? &GetHTMLProgNameArray() : &GetHTMLUINameArray(); + nStt = RES_POOLCOLL_HTML_BEGIN; + } + break; + case POOLGRP_CHARFMT: + if( RES_POOLCHR_NORMAL_BEGIN <= nId && nId < RES_POOLCHR_NORMAL_END ) + { + pStrArr = bProgName ? &GetChrFmtProgNameArray() : &GetChrFmtUINameArray(); + nStt = RES_POOLCHR_NORMAL_BEGIN; + } + else if( RES_POOLCHR_HTML_BEGIN <= nId && nId < RES_POOLCHR_HTML_END ) + { + pStrArr = bProgName ? &GetHTMLChrFmtProgNameArray() : &GetHTMLChrFmtUINameArray(); + nStt = RES_POOLCHR_HTML_BEGIN; + } + break; + case POOLGRP_FRAMEFMT: + if( RES_POOLFRM_BEGIN <= nId && nId < RES_POOLFRM_END ) + { + pStrArr = bProgName ? &GetFrmFmtProgNameArray() : &GetFrmFmtUINameArray(); + nStt = RES_POOLFRM_BEGIN; + } + break; + case POOLGRP_PAGEDESC: + if( RES_POOLPAGE_BEGIN <= nId && nId < RES_POOLPAGE_END ) + { + pStrArr = bProgName ? &GetPageDescProgNameArray() : &GetPageDescUINameArray(); + nStt = RES_POOLPAGE_BEGIN; + } + break; + case POOLGRP_NUMRULE: + if( RES_POOLNUMRULE_BEGIN <= nId && nId < RES_POOLNUMRULE_END ) + { + pStrArr = bProgName ? &GetNumRuleProgNameArray() : &GetNumRuleUINameArray(); + nStt = RES_POOLNUMRULE_BEGIN; + } + break; + } + return pStrArr ? *(pStrArr->operator[] ( nId - nStt ) ) : rFillName; +} +void SwStyleNameMapper::fillNameFromId( sal_uInt16 nId, String& rFillName, sal_Bool bProgName ) +{ + sal_uInt16 nStt = 0; + const SvStringsDtor* pStrArr = 0; + + switch( (USER_FMT | COLL_GET_RANGE_BITS | POOLGRP_NOCOLLID) & nId ) + { + case COLL_TEXT_BITS: + if( RES_POOLCOLL_TEXT_BEGIN <= nId && nId < RES_POOLCOLL_TEXT_END ) + { + pStrArr = bProgName ? &GetTextProgNameArray() : &GetTextUINameArray(); + nStt = RES_POOLCOLL_TEXT_BEGIN; + } + break; + case COLL_LISTS_BITS: + if( RES_POOLCOLL_LISTS_BEGIN <= nId && nId < RES_POOLCOLL_LISTS_END ) + { + pStrArr = bProgName ? &GetListsProgNameArray() : &GetListsUINameArray(); + nStt = RES_POOLCOLL_LISTS_BEGIN; + } + break; + case COLL_EXTRA_BITS: + if( RES_POOLCOLL_EXTRA_BEGIN <= nId && nId < RES_POOLCOLL_EXTRA_END ) + { + pStrArr = bProgName ? &GetExtraProgNameArray() : &GetExtraUINameArray(); + nStt = RES_POOLCOLL_EXTRA_BEGIN; + } + break; + case COLL_REGISTER_BITS: + if( RES_POOLCOLL_REGISTER_BEGIN <= nId && nId < RES_POOLCOLL_REGISTER_END ) + { + pStrArr = bProgName ? &GetRegisterProgNameArray() : &GetRegisterUINameArray(); + nStt = RES_POOLCOLL_REGISTER_BEGIN; + } + break; + case COLL_DOC_BITS: + if( RES_POOLCOLL_DOC_BEGIN <= nId && nId < RES_POOLCOLL_DOC_END ) + { + pStrArr = bProgName ? &GetDocProgNameArray() : &GetDocUINameArray(); + nStt = RES_POOLCOLL_DOC_BEGIN; + } + break; + case COLL_HTML_BITS: + if( RES_POOLCOLL_HTML_BEGIN <= nId && nId < RES_POOLCOLL_HTML_END ) + { + pStrArr = bProgName ? &GetHTMLProgNameArray() : &GetHTMLUINameArray(); + nStt = RES_POOLCOLL_HTML_BEGIN; + } + break; + case POOLGRP_CHARFMT: + if( RES_POOLCHR_NORMAL_BEGIN <= nId && nId < RES_POOLCHR_NORMAL_END ) + { + pStrArr = bProgName ? &GetChrFmtProgNameArray() : &GetChrFmtUINameArray(); + nStt = RES_POOLCHR_NORMAL_BEGIN; + } + else if( RES_POOLCHR_HTML_BEGIN <= nId && nId < RES_POOLCHR_HTML_END ) + { + pStrArr = bProgName ? &GetHTMLChrFmtProgNameArray() : &GetHTMLChrFmtUINameArray(); + nStt = RES_POOLCHR_HTML_BEGIN; + } + break; + case POOLGRP_FRAMEFMT: + if( RES_POOLFRM_BEGIN <= nId && nId < RES_POOLFRM_END ) + { + pStrArr = bProgName ? &GetFrmFmtProgNameArray() : &GetFrmFmtUINameArray(); + nStt = RES_POOLFRM_BEGIN; + } + break; + case POOLGRP_PAGEDESC: + if( RES_POOLPAGE_BEGIN <= nId && nId < RES_POOLPAGE_END ) + { + pStrArr = bProgName ? &GetPageDescProgNameArray() : &GetPageDescUINameArray(); + nStt = RES_POOLPAGE_BEGIN; + } + break; + case POOLGRP_NUMRULE: + if( RES_POOLNUMRULE_BEGIN <= nId && nId < RES_POOLNUMRULE_END ) + { + pStrArr = bProgName ? &GetNumRuleProgNameArray() : &GetNumRuleUINameArray(); + nStt = RES_POOLNUMRULE_BEGIN; + } + break; + } + if (pStrArr) + rFillName = *(pStrArr->operator[] ( nId - nStt ) ); +} +// Get the UI Name from the pool ID +void SwStyleNameMapper::FillUIName ( sal_uInt16 nId, String& rFillName ) +{ + fillNameFromId ( nId, rFillName, sal_False ); +} +// Get the UI Name from the pool ID +const String& SwStyleNameMapper::GetUIName ( sal_uInt16 nId, const String& rName ) +{ + return getNameFromId ( nId, rName, sal_False ); +} + +// Get the programmatic Name from the pool ID +void SwStyleNameMapper::FillProgName ( sal_uInt16 nId, String& rFillName ) +{ + fillNameFromId ( nId, rFillName, sal_True ); +} +// Get the programmatic Name from the pool ID +const String& SwStyleNameMapper::GetProgName ( sal_uInt16 nId, const String& rName ) +{ + return getNameFromId ( nId, rName, sal_True ); +} +// This gets the PoolId from the UI Name +sal_uInt16 SwStyleNameMapper::GetPoolIdFromUIName( const String& rName, SwGetPoolIdFromName eFlags ) +{ + const NameToIdHash & rHashMap = getHashTable ( eFlags, sal_False ); + NameToIdHash::const_iterator aIter = rHashMap.find ( &rName ); + return aIter != rHashMap.end() ? (*aIter).second : USHRT_MAX; +} +// Get the Pool ID from the programmatic name +sal_uInt16 SwStyleNameMapper::GetPoolIdFromProgName( const String& rName, SwGetPoolIdFromName eFlags ) +{ + const NameToIdHash & rHashMap = getHashTable ( eFlags, sal_True ); + NameToIdHash::const_iterator aIter = rHashMap.find ( &rName ); + return aIter != rHashMap.end() ? (*aIter).second : USHRT_MAX; +} + +SvStringsDtor* SwStyleNameMapper::NewUINameArray( SvStringsDtor*& pNameArray, sal_uInt16 nStt, sal_uInt16 nEnd ) +{ + if( !pNameArray ) + { + pNameArray = new SvStringsDtor( static_cast < sal_Int8 > (nEnd - nStt), 1 ); + while( nStt < nEnd ) + { + const ResId rRId( nStt, *pSwResMgr ); + String* pStr = new String( rRId ); + pNameArray->Insert( pStr, pNameArray->Count() ); + ++nStt; + } + } + return pNameArray; +} + +const SvStringsDtor& SwStyleNameMapper::GetTextUINameArray() +{ + return pTextUINameArray ? *pTextUINameArray : + *NewUINameArray( pTextUINameArray, RC_POOLCOLL_TEXT_BEGIN, + ( RC_POOLCOLL_TEXT_BEGIN + + (RES_POOLCOLL_TEXT_END - RES_POOLCOLL_TEXT_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetListsUINameArray() +{ + return pListsUINameArray ? *pListsUINameArray : + *NewUINameArray( pListsUINameArray, RC_POOLCOLL_LISTS_BEGIN, + ( RC_POOLCOLL_LISTS_BEGIN + + (RES_POOLCOLL_LISTS_END - RES_POOLCOLL_LISTS_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetExtraUINameArray() +{ + return pExtraUINameArray ? *pExtraUINameArray : + *NewUINameArray( pExtraUINameArray, RC_POOLCOLL_EXTRA_BEGIN, + ( RC_POOLCOLL_EXTRA_BEGIN + + (RES_POOLCOLL_EXTRA_END - RES_POOLCOLL_EXTRA_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetRegisterUINameArray() +{ + return pRegisterUINameArray ? *pRegisterUINameArray : + *NewUINameArray( pRegisterUINameArray, RC_POOLCOLL_REGISTER_BEGIN, + ( RC_POOLCOLL_REGISTER_BEGIN + + (RES_POOLCOLL_REGISTER_END - RES_POOLCOLL_REGISTER_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetDocUINameArray() +{ + return pDocUINameArray ? *pDocUINameArray : + *NewUINameArray( pDocUINameArray, RC_POOLCOLL_DOC_BEGIN, + ( RC_POOLCOLL_DOC_BEGIN + + (RES_POOLCOLL_DOC_END - RES_POOLCOLL_DOC_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetHTMLUINameArray() +{ + return pHTMLUINameArray ? *pHTMLUINameArray : + *NewUINameArray( pHTMLUINameArray, RC_POOLCOLL_HTML_BEGIN, + ( RC_POOLCOLL_HTML_BEGIN + + (RES_POOLCOLL_HTML_END - RES_POOLCOLL_HTML_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetFrmFmtUINameArray() +{ + return pFrmFmtUINameArray ? *pFrmFmtUINameArray : + *NewUINameArray( pFrmFmtUINameArray, RC_POOLFRMFMT_BEGIN, + ( RC_POOLFRMFMT_BEGIN + + (RES_POOLFRM_END - RES_POOLFRM_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetChrFmtUINameArray() +{ + return pChrFmtUINameArray ? *pChrFmtUINameArray : + *NewUINameArray( pChrFmtUINameArray, RC_POOLCHRFMT_BEGIN, + ( RC_POOLCHRFMT_BEGIN + + (RES_POOLCHR_NORMAL_END - RES_POOLCHR_NORMAL_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetHTMLChrFmtUINameArray() +{ + return pHTMLChrFmtUINameArray ? *pHTMLChrFmtUINameArray : + *NewUINameArray( pHTMLChrFmtUINameArray, RC_POOLCHRFMT_HTML_BEGIN, + ( RC_POOLCHRFMT_HTML_BEGIN + + (RES_POOLCHR_HTML_END - RES_POOLCHR_HTML_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetPageDescUINameArray() +{ + return pPageDescUINameArray ? *pPageDescUINameArray : + *NewUINameArray( pPageDescUINameArray, RC_POOLPAGEDESC_BEGIN, + ( RC_POOLPAGEDESC_BEGIN + + (RES_POOLPAGE_END - RES_POOLPAGE_BEGIN )) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetNumRuleUINameArray() +{ + return pNumRuleUINameArray ? *pNumRuleUINameArray : + *NewUINameArray( pNumRuleUINameArray, RC_POOLNUMRULE_BEGIN, + ( RC_POOLNUMRULE_BEGIN + + (RES_POOLNUMRULE_END - RES_POOLNUMRULE_BEGIN )) ); +} + +SvStringsDtor* SwStyleNameMapper::NewProgNameArray( SvStringsDtor*& pProgNameArray, const SwTableEntry *pTable, sal_uInt8 nCount ) +{ + if( !pProgNameArray ) + { + pProgNameArray = new SvStringsDtor( nCount, 1 ); + while (pTable->nLength) + { + String* pStr = new String( pTable->pChar, pTable->nLength, RTL_TEXTENCODING_ASCII_US ); + pProgNameArray->Insert( pStr, pProgNameArray->Count() ); + pTable++; + } + } + return pProgNameArray; +} + +const SvStringsDtor& SwStyleNameMapper::GetTextProgNameArray() +{ + return pTextProgNameArray ? *pTextProgNameArray : + *NewProgNameArray( pTextProgNameArray, TextProgNameTable, + sizeof ( TextProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetListsProgNameArray() +{ + return pListsProgNameArray ? *pListsProgNameArray : + *NewProgNameArray( pListsProgNameArray, ListsProgNameTable, + sizeof ( ListsProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetExtraProgNameArray() +{ + return pExtraProgNameArray ? *pExtraProgNameArray : + *NewProgNameArray( pExtraProgNameArray, ExtraProgNameTable, + sizeof ( ExtraProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetRegisterProgNameArray() +{ + return pRegisterProgNameArray ? *pRegisterProgNameArray : + *NewProgNameArray( pRegisterProgNameArray, RegisterProgNameTable, + sizeof ( RegisterProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetDocProgNameArray() +{ + return pDocProgNameArray ? *pDocProgNameArray : + *NewProgNameArray( pDocProgNameArray, DocProgNameTable, + sizeof ( DocProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetHTMLProgNameArray() +{ + return pHTMLProgNameArray ? *pHTMLProgNameArray : + *NewProgNameArray( pHTMLProgNameArray, HTMLProgNameTable, + sizeof ( HTMLProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetFrmFmtProgNameArray() +{ + return pFrmFmtProgNameArray ? *pFrmFmtProgNameArray : + *NewProgNameArray( pFrmFmtProgNameArray, FrmFmtProgNameTable, + sizeof ( FrmFmtProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetChrFmtProgNameArray() +{ + return pChrFmtProgNameArray ? *pChrFmtProgNameArray : + *NewProgNameArray( pChrFmtProgNameArray, ChrFmtProgNameTable, + sizeof ( ChrFmtProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetHTMLChrFmtProgNameArray() +{ + return pHTMLChrFmtProgNameArray ? *pHTMLChrFmtProgNameArray : + *NewProgNameArray( pHTMLChrFmtProgNameArray, HTMLChrFmtProgNameTable, + sizeof ( HTMLChrFmtProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetPageDescProgNameArray() +{ + return pPageDescProgNameArray ? *pPageDescProgNameArray : + *NewProgNameArray( pPageDescProgNameArray, PageDescProgNameTable, + sizeof ( PageDescProgNameTable ) / sizeof ( SwTableEntry ) ); +} + +const SvStringsDtor& SwStyleNameMapper::GetNumRuleProgNameArray() +{ + return pNumRuleProgNameArray ? *pNumRuleProgNameArray : + *NewProgNameArray( pNumRuleProgNameArray, NumRuleProgNameTable, + sizeof ( NumRuleProgNameTable ) / sizeof ( SwTableEntry ) ); +} + + +const String SwStyleNameMapper::GetSpecialExtraProgName( const String& rExtraUIName ) +{ + String aRes = rExtraUIName; + sal_Bool bChgName = sal_False; + const SvStringsDtor& rExtraArr = GetExtraUINameArray(); + static sal_uInt16 nIds[] = + { + RES_POOLCOLL_LABEL_DRAWING - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_ABB - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_TABLE - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_FRAME- RES_POOLCOLL_EXTRA_BEGIN, + 0 + }; + const sal_uInt16 * pIds; + for ( pIds = nIds; *pIds; ++pIds) + { + if (aRes == *rExtraArr[ *pIds ]) + { + bChgName = sal_True; + break; + } + } + if (bChgName) + aRes = *GetExtraProgNameArray()[*pIds]; + return aRes; +} + +const String SwStyleNameMapper::GetSpecialExtraUIName( const String& rExtraProgName ) +{ + String aRes = rExtraProgName; + sal_Bool bChgName = sal_False; + const SvStringsDtor& rExtraArr = GetExtraProgNameArray(); + static sal_uInt16 nIds[] = + { + RES_POOLCOLL_LABEL_DRAWING - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_ABB - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_TABLE - RES_POOLCOLL_EXTRA_BEGIN, + RES_POOLCOLL_LABEL_FRAME- RES_POOLCOLL_EXTRA_BEGIN, + 0 + }; + const sal_uInt16 * pIds; + + for ( pIds = nIds; *pIds; ++pIds) + { + if (aRes == *rExtraArr[ *pIds ]) + { + bChgName = sal_True; + break; + } + } + if (bChgName) + aRes = *GetExtraUINameArray()[*pIds]; + return aRes; +} + diff --git a/sw/source/core/doc/acmplwrd.cxx b/sw/source/core/doc/acmplwrd.cxx new file mode 100644 index 000000000000..e53679d8d92e --- /dev/null +++ b/sw/source/core/doc/acmplwrd.cxx @@ -0,0 +1,473 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <tools/urlobj.hxx> +#include <hintids.hxx> +#include <hints.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <acmplwrd.hxx> +#include <doc.hxx> +#include <ndindex.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <calbck.hxx> +#include <editeng/svxacorr.hxx> + +#include <editeng/acorrcfg.hxx> +#include <sfx2/docfile.hxx> +#include <docsh.hxx> + +#include <vector> +/* -----------------------------05.08.2002 12:43------------------------------ + + ---------------------------------------------------------------------------*/ +class SwAutoCompleteClient : public SwClient +{ + SwAutoCompleteWord* pAutoCompleteWord; + SwDoc* pDoc; +#ifdef DBG_UTIL + static sal_uLong nSwAutoCompleteClientCount; +#endif +public: + SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc); + SwAutoCompleteClient(const SwAutoCompleteClient& rClient); + ~SwAutoCompleteClient(); + + SwAutoCompleteClient& operator=(const SwAutoCompleteClient& rClient); + + virtual void Modify( SfxPoolItem *pOld, SfxPoolItem *pNew); + const SwDoc& GetDoc(){return *pDoc;} +#ifdef DBG_UTIL + static sal_uLong GetElementCount() {return nSwAutoCompleteClientCount;} +#endif +}; +/* -----------------------------05.08.2002 12:48------------------------------ + + ---------------------------------------------------------------------------*/ +typedef std::vector<SwAutoCompleteClient> SwAutoCompleteClientVector; + +class SwAutoCompleteWord_Impl +{ + SwAutoCompleteClientVector aClientVector; + SwAutoCompleteWord& rAutoCompleteWord; +public: + SwAutoCompleteWord_Impl(SwAutoCompleteWord& rParent) : + rAutoCompleteWord(rParent){} + void AddDocument(SwDoc& rDoc); + void RemoveDocument(const SwDoc& rDoc); +}; + +/* -----------------------------05.08.2002 14:11------------------------------ + + ---------------------------------------------------------------------------*/ +typedef const SwDoc* SwDocPtr; +typedef std::vector<SwDocPtr> SwDocPtrVector; +class SwAutoCompleteString : public String +{ +#ifdef DBG_UTIL + static sal_uLong nSwAutoCompleteStringCount; +#endif + SwDocPtrVector aSourceDocs; + public: + SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen); + + ~SwAutoCompleteString(); + void AddDocument(const SwDoc& rDoc); + //returns true if last document reference has been removed + sal_Bool RemoveDocument(const SwDoc& rDoc); +#ifdef DBG_UTIL + static sal_uLong GetElementCount() {return nSwAutoCompleteStringCount;} +#endif +}; +#ifdef DBG_UTIL + sal_uLong SwAutoCompleteClient::nSwAutoCompleteClientCount = 0; + sal_uLong SwAutoCompleteString::nSwAutoCompleteStringCount = 0; +#endif +/* -----------------------------06.08.2002 08:57------------------------------ + + ---------------------------------------------------------------------------*/ +SwAutoCompleteClient::SwAutoCompleteClient(SwAutoCompleteWord& rToTell, SwDoc& rSwDoc) : + pAutoCompleteWord(&rToTell), + pDoc(&rSwDoc) +{ + pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this); +#ifdef DBG_UTIL + ++nSwAutoCompleteClientCount; +#endif +} +/* -----------------------------05.08.2002 14:07------------------------------ + + ---------------------------------------------------------------------------*/ +SwAutoCompleteClient::SwAutoCompleteClient(const SwAutoCompleteClient& rClient) : + SwClient(), + pAutoCompleteWord(rClient.pAutoCompleteWord), + pDoc(rClient.pDoc) +{ + pDoc->GetPageDescFromPool(RES_POOLPAGE_STANDARD)->Add(this); +#ifdef DBG_UTIL + ++nSwAutoCompleteClientCount; +#endif +} +/* -----------------------------05.08.2002 14:10------------------------------ + + ---------------------------------------------------------------------------*/ +SwAutoCompleteClient::~SwAutoCompleteClient() +{ +#ifdef DBG_UTIL + --nSwAutoCompleteClientCount; +#endif +} +/* -----------------06.03.2003 15:30----------------- + + --------------------------------------------------*/ +SwAutoCompleteClient& SwAutoCompleteClient::operator=(const SwAutoCompleteClient& rClient) +{ + pAutoCompleteWord = rClient.pAutoCompleteWord; + pDoc = rClient.pDoc; + if(rClient.GetRegisteredIn()) + rClient.pRegisteredIn->Add(this); + else if(GetRegisteredIn()) + pRegisteredIn->Remove(this); + return *this; +} +/* -----------------------------05.08.2002 12:49------------------------------ + + ---------------------------------------------------------------------------*/ +void SwAutoCompleteClient::Modify(SfxPoolItem *pOld, SfxPoolItem *) +{ + switch( pOld ? pOld->Which() : 0 ) + { + case RES_REMOVE_UNO_OBJECT: + case RES_OBJECTDYING: + if( (void*)GetRegisteredIn() == ((SwPtrMsgPoolItem *)pOld)->pObject ) + ((SwModify*)GetRegisteredIn())->Remove(this); + pAutoCompleteWord->DocumentDying(*pDoc); + break; + + } +} +/* -----------------------------05.08.2002 13:03------------------------------ + + ---------------------------------------------------------------------------*/ +void SwAutoCompleteWord_Impl::AddDocument(SwDoc& rDoc) +{ + SwAutoCompleteClientVector::iterator aIt; + for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++) + { + if(&aIt->GetDoc() == &rDoc) + return; + } + aClientVector.push_back(SwAutoCompleteClient(rAutoCompleteWord, rDoc)); +} +/* -----------------------------05.08.2002 14:33------------------------------ + + ---------------------------------------------------------------------------*/ +void SwAutoCompleteWord_Impl::RemoveDocument(const SwDoc& rDoc) +{ + SwAutoCompleteClientVector::iterator aIt; + for(aIt = aClientVector.begin(); aIt != aClientVector.end(); aIt++) + { + if(&aIt->GetDoc() == &rDoc) + { + aClientVector.erase(aIt); + return; + } + } +} +/* -----------------------------06.08.2002 08:54------------------------------ + + ---------------------------------------------------------------------------*/ +SwAutoCompleteString::SwAutoCompleteString(const String& rStr, xub_StrLen nPos, xub_StrLen nLen) : + String( rStr, nPos, nLen ) +{ +#ifdef DBG_UTIL + ++nSwAutoCompleteStringCount; +#endif +} +/* -----------------------------05.08.2002 14:22------------------------------ + + ---------------------------------------------------------------------------*/ +SwAutoCompleteString::~SwAutoCompleteString() +{ +#ifdef DBG_UTIL + --nSwAutoCompleteStringCount; +#endif +} +/* -----------------------------05.08.2002 14:17------------------------------ + + ---------------------------------------------------------------------------*/ +void SwAutoCompleteString::AddDocument(const SwDoc& rDoc) +{ + SwDocPtrVector::iterator aIt; + for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++) + { + if(*aIt == &rDoc) + return; + } + SwDocPtr pNew = &rDoc; + aSourceDocs.push_back(pNew); +} +/* -----------------------------05.08.2002 14:36------------------------------ + + ---------------------------------------------------------------------------*/ +sal_Bool SwAutoCompleteString::RemoveDocument(const SwDoc& rDoc) +{ + SwDocPtrVector::iterator aIt; + for(aIt = aSourceDocs.begin(); aIt != aSourceDocs.end(); aIt++) + { + if(*aIt == &rDoc) + { + aSourceDocs.erase(aIt); + return !aSourceDocs.size(); + } + } + return sal_False; +} +/* --------------------------------------------------------------------------- + + ---------------------------------------------------------------------------*/ +SwAutoCompleteWord::SwAutoCompleteWord( sal_uInt16 nWords, sal_uInt16 nMWrdLen ) + : aWordLst( 0, 255 ), aLRULst( 0, 255 ), + pImpl(new SwAutoCompleteWord_Impl(*this)), + nMaxCount( nWords ), + nMinWrdLen( nMWrdLen ), + bLockWordLst( sal_False ) +{ +} + +SwAutoCompleteWord::~SwAutoCompleteWord() +{ + for(sal_uInt16 nPos = aWordLst.Count(); nPos; nPos--) + { + SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ]; + aWordLst.Remove( nPos - 1 ); + delete pCurrent; + } + delete pImpl; +#ifdef DBG_UTIL + sal_uLong nStrings = SwAutoCompleteString::GetElementCount(); + sal_uLong nClients = SwAutoCompleteClient::GetElementCount(); + DBG_ASSERT(!nStrings && !nClients, "AutoComplete: clients or string count mismatch"); +#endif +} + +sal_Bool SwAutoCompleteWord::InsertWord( const String& rWord, SwDoc& rDoc ) +{ + SwDocShell* pDocShell = rDoc.GetDocShell(); + SfxMedium* pMedium = pDocShell ? pDocShell->GetMedium() : 0; + // strings from help module should not be added + if( pMedium ) + { + const INetURLObject& rURL = pMedium->GetURLObject(); + if ( rURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP ) + return sal_False; + } + + String aNewWord(rWord); + aNewWord.EraseAllChars( CH_TXTATR_INWORD ); + aNewWord.EraseAllChars( CH_TXTATR_BREAKWORD ); + + pImpl->AddDocument(rDoc); + sal_Bool bRet = sal_False; + xub_StrLen nWrdLen = aNewWord.Len(); + while( nWrdLen && '.' == aNewWord.GetChar( nWrdLen-1 )) + --nWrdLen; + + if( !bLockWordLst && nWrdLen >= nMinWrdLen ) + { + SwAutoCompleteString* pAutoString; + StringPtr pNew = pAutoString = new SwAutoCompleteString( aNewWord, 0, nWrdLen ); + pAutoString->AddDocument(rDoc); + sal_uInt16 nInsPos; + if( aWordLst.Insert( pNew, nInsPos ) ) + { + bRet = sal_True; + if( aLRULst.Count() < nMaxCount ) + aLRULst.Insert( pNew, 0 ); + else + { + // der letzte muss entfernt werden + // damit der neue vorne Platz hat + String* pDel = (String*)aLRULst[ nMaxCount - 1 ]; + + void** ppData = (void**)aLRULst.GetData(); + memmove( ppData+1, ppData, (nMaxCount - 1) * sizeof( void* )); + *ppData = pNew; + + aWordLst.Remove( pDel ); + delete (SwAutoCompleteString*)pDel; + } + } + else + { + delete (SwAutoCompleteString*)pNew; + // dann aber auf jedenfall nach "oben" moven + pNew = aWordLst[ nInsPos ]; + + //add the document to the already inserted string + SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)pNew; + pCurrent->AddDocument(rDoc); + + nInsPos = aLRULst.GetPos( (void*)pNew ); + ASSERT( USHRT_MAX != nInsPos, "String nicht gefunden" ); + if( nInsPos ) + { + void** ppData = (void**)aLRULst.GetData(); + memmove( ppData+1, ppData, nInsPos * sizeof( void* ) ); + *ppData = pNew; + } + } + } + return bRet; +} + +void SwAutoCompleteWord::SetMaxCount( sal_uInt16 nNewMax ) +{ + if( nNewMax < nMaxCount && aLRULst.Count() > nNewMax ) + { + // dann die unten ueberhaengenden entfernen + sal_uInt16 nLRUIndex = nNewMax-1; + while( nNewMax < aWordLst.Count() && nLRUIndex < aLRULst.Count()) + { + sal_uInt16 nPos = aWordLst.GetPos( (String*)aLRULst[ nLRUIndex++ ] ); + ASSERT( USHRT_MAX != nPos, "String nicht gefunden" ); + void * pDel = aWordLst[nPos]; + aWordLst.Remove(nPos); + delete (SwAutoCompleteString*)pDel; + } + aLRULst.Remove( nNewMax-1, aLRULst.Count() - nNewMax ); + } + nMaxCount = nNewMax; +} + +void SwAutoCompleteWord::SetMinWordLen( sal_uInt16 n ) +{ + // will man wirklich alle Worte, die kleiner als die neue Min Laenge + // sind entfernen? + // JP 02.02.99 - erstmal nicht. + + // JP 11.03.99 - mal testhalber eingebaut + if( n < nMinWrdLen ) + { + for( sal_uInt16 nPos = 0; nPos < aWordLst.Count(); ++nPos ) + if( aWordLst[ nPos ]->Len() < n ) + { + void* pDel = aWordLst[ nPos ]; + aWordLst.Remove(nPos); + + sal_uInt16 nDelPos = aLRULst.GetPos( pDel ); + ASSERT( USHRT_MAX != nDelPos, "String nicht gefunden" ); + aLRULst.Remove( nDelPos ); + --nPos; + delete (SwAutoCompleteString*)pDel; + } + } + + nMinWrdLen = n; +} + +sal_Bool SwAutoCompleteWord::GetRange( const String& rWord, sal_uInt16& rStt, + sal_uInt16& rEnd ) const +{ + const StringPtr pStr = (StringPtr)&rWord; + aWordLst.Seek_Entry( pStr, &rStt ); + rEnd = rStt; + + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + while( rEnd < aWordLst.Count() && rSCmp.isMatch( rWord, *aWordLst[ rEnd ])) + ++rEnd; + + return rStt < rEnd; +} + +void SwAutoCompleteWord::CheckChangedList( const SvStringsISortDtor& rNewLst ) +{ + sal_uInt16 nMyLen = aWordLst.Count(), nNewLen = rNewLst.Count(); + sal_uInt16 nMyPos = 0, nNewPos = 0; + + for( ; nMyPos < nMyLen && nNewPos < nNewLen; ++nMyPos, ++nNewPos ) + { + const StringPtr pStr = rNewLst[ nNewPos ]; + while( aWordLst[ nMyPos ] != pStr ) + { + void* pDel = aWordLst[ nMyPos ]; + aWordLst.Remove(nMyPos); + + sal_uInt16 nPos = aLRULst.GetPos( pDel ); + ASSERT( USHRT_MAX != nPos, "String nicht gefunden" ); + aLRULst.Remove( nPos ); + delete (SwAutoCompleteString*)pDel; + if( nMyPos >= --nMyLen ) + break; + } + } + //remove the elements at the end of the array + if( nMyPos < nMyLen ) + { + //clear LRU array first then delete the string object + for( ; nNewPos < nMyLen; ++nNewPos ) + { + void* pDel = aWordLst[ nNewPos ]; + sal_uInt16 nPos = aLRULst.GetPos( pDel ); + ASSERT( USHRT_MAX != nPos, "String nicht gefunden" ); + aLRULst.Remove( nPos ); + delete (SwAutoCompleteString*)pDel; + } + //remove from array + aWordLst.Remove( nMyPos, nMyLen - nMyPos ); + } +} +/* -----------------------------05.08.2002 12:54------------------------------ + + ---------------------------------------------------------------------------*/ +void SwAutoCompleteWord::DocumentDying(const SwDoc& rDoc) +{ + pImpl->RemoveDocument(rDoc); + + SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get()->GetAutoCorrect(); + const sal_Bool bDelete = !pACorr->GetSwFlags().bAutoCmpltKeepList; + for(sal_uInt16 nPos = aWordLst.Count(); nPos; nPos--) + { + SwAutoCompleteString* pCurrent = (SwAutoCompleteString*)aWordLst[ nPos - 1 ]; + if(pCurrent->RemoveDocument(rDoc) && bDelete) + { + aWordLst.Remove( nPos - 1 ); + sal_uInt16 nLRUPos = aLRULst.GetPos( (void*)pCurrent ); + DBG_ASSERT(nLRUPos < USHRT_MAX, "word not found in LRU list" ); + aLRULst.Remove( nLRUPos ); + delete pCurrent; + } + } +} + diff --git a/sw/source/core/doc/dbgoutsw.cxx b/sw/source/core/doc/dbgoutsw.cxx new file mode 100644 index 000000000000..08dab4aff359 --- /dev/null +++ b/sw/source/core/doc/dbgoutsw.cxx @@ -0,0 +1,1040 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#ifdef DEBUG + +#include <tools/string.hxx> +#include <svl/poolitem.hxx> +#include <svl/itemiter.hxx> +#include <string> +#include <map> +#include <node.hxx> +#include <ndtxt.hxx> +#include <ndhints.hxx> +#include <txatbase.hxx> +#include <pam.hxx> +#include <docary.hxx> +#include <swundo.hxx> +#include <undobj.hxx> +#include <numrule.hxx> +#include <doc.hxx> +#include <frmfmt.hxx> +#include <fmtanchr.hxx> +#include <swrect.hxx> +#include <ndarr.hxx> +#include <paratr.hxx> +#include <SwNodeNum.hxx> +#include <dbgoutsw.hxx> +#include <SwRewriter.hxx> +#include <iostream> +#include <cstdio> + +using namespace std; + +static ByteString aDbgOutResult; +bool bDbgOutStdErr = false; +bool bDbgOutPrintAttrSet = false; + +char* db_pretty_print(const String* str, int flags, char* fmt) +{ + (void) fmt; + (void) flags; + return const_cast<char*>(dbg_out(*str)); +} + +template<class T> +String lcl_dbg_out_SvPtrArr(const T & rArr) +{ + String aStr("[ ", RTL_TEXTENCODING_ASCII_US); + + for (sal_Int16 n = 0; n < rArr.Count(); n++) + { + if (n > 0) + aStr += String(", ", RTL_TEXTENCODING_ASCII_US); + + if (rArr[n]) + aStr += lcl_dbg_out(*rArr[n]); + else + aStr += String("(null)", RTL_TEXTENCODING_ASCII_US); + } + + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const void * pVoid) +{ + char sBuffer[1024]; + + sprintf(sBuffer, "%p", pVoid); + + String aTmpStr(sBuffer, RTL_TEXTENCODING_ASCII_US); + + return dbg_out(aTmpStr); +} + +SW_DLLPUBLIC const char * dbg_out(const String & aStr) +{ + aDbgOutResult = ByteString(aStr, RTL_TEXTENCODING_ASCII_US); + + if (bDbgOutStdErr) + fprintf(stderr, "%s", aDbgOutResult.GetBuffer()); + + return aDbgOutResult.GetBuffer(); +} + +SW_DLLPUBLIC const char * dbg_out(const ::rtl::OUString & aStr) +{ + return OUStringToOString(aStr, RTL_TEXTENCODING_ASCII_US).getStr(); +} + + +struct CompareUShort +{ + bool operator()(sal_uInt16 a, sal_uInt16 b) const + { + return a < b; + } +}; + +map<sal_uInt16,String,CompareUShort> & GetItemWhichMap() +{ + static map<sal_uInt16,String,CompareUShort> aItemWhichMap; + static bool bInitialized = false; + + if (! bInitialized) + { + aItemWhichMap[RES_CHRATR_CASEMAP] = String("CHRATR_CASEMAP", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CHARSETCOLOR] = String("CHRATR_CHARSETCOLOR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_COLOR] = String("CHRATR_COLOR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CONTOUR] = String("CHRATR_CONTOUR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CROSSEDOUT] = String("CHRATR_CROSSEDOUT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_ESCAPEMENT] = String("CHRATR_ESCAPEMENT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_FONT] = String("CHRATR_FONT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_FONTSIZE] = String("CHRATR_FONTSIZE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_KERNING] = String("CHRATR_KERNING", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_LANGUAGE] = String("CHRATR_LANGUAGE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_POSTURE] = String("CHRATR_POSTURE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_PROPORTIONALFONTSIZE] = String("CHRATR_PROPORTIONALFONTSIZE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_SHADOWED] = String("CHRATR_SHADOWED", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_UNDERLINE] = String("CHRATR_UNDERLINE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_OVERLINE] = String("CHRATR_OVERLINE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_WEIGHT] = String("CHRATR_WEIGHT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_WORDLINEMODE] = String("CHRATR_WORDLINEMODE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_AUTOKERN] = String("CHRATR_AUTOKERN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_BLINK] = String("CHRATR_BLINK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_NOHYPHEN] = String("CHRATR_NOHYPHEN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_NOLINEBREAK] = String("CHRATR_NOLINEBREAK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_BACKGROUND] = String("CHRATR_BACKGROUND", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CJK_FONT] = String("CHRATR_CJK_FONT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CJK_FONTSIZE] = String("CHRATR_CJK_FONTSIZE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CJK_LANGUAGE] = String("CHRATR_CJK_LANGUAGE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CJK_POSTURE] = String("CHRATR_CJK_POSTURE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CJK_WEIGHT] = String("CHRATR_CJK_WEIGHT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CTL_FONT] = String("CHRATR_CTL_FONT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CTL_FONTSIZE] = String("CHRATR_CTL_FONTSIZE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CTL_LANGUAGE] = String("CHRATR_CTL_LANGUAGE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CTL_POSTURE] = String("CHRATR_CTL_POSTURE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_CTL_WEIGHT] = String("CHRATR_CTL_WEIGHT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_ROTATE] = String("CHRATR_ROTATE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_EMPHASIS_MARK] = String("CHRATR_EMPHASIS_MARK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_TWO_LINES] = String("CHRATR_TWO_LINES", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_SCALEW] = String("CHRATR_SCALEW", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_RELIEF] = String("CHRATR_RELIEF", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHRATR_HIDDEN] = String("CHRATR_HIDDEN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_AUTOFMT] = String("TXTATR_AUTOFMT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_INETFMT] = String("TXTATR_INETFMT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_REFMARK] = String("TXTATR_REFMARK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_TOXMARK] = String("TXTATR_TOXMARK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_CHARFMT] = String("TXTATR_CHARFMT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_DUMMY5] = String("TXTATR_DUMMY5", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_CJK_RUBY] = String("TXTATR_CJK_RUBY", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_UNKNOWN_CONTAINER] = String("TXTATR_UNKNOWN_CONTAINER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_META] = String("TXTATR_META", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_METAFIELD] = String("TXTATR_METAFIELD", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_FIELD] = String("TXTATR_FIELD", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_FLYCNT] = String("TXTATR_FLYCNT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_FTN] = String("TXTATR_FTN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_DUMMY4] = String("TXTATR_DUMMY4", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_DUMMY3] = String("TXTATR_DUMMY3", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_DUMMY1] = String("TXTATR_DUMMY1", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TXTATR_DUMMY2] = String("TXTATR_DUMMY2", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_LINESPACING] = String("PARATR_LINESPACING", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_ADJUST] = String("PARATR_ADJUST", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_SPLIT] = String("PARATR_SPLIT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_ORPHANS] = String("PARATR_ORPHANS", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_WIDOWS] = String("PARATR_WIDOWS", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_TABSTOP] = String("PARATR_TABSTOP", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_HYPHENZONE] = String("PARATR_HYPHENZONE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_DROP] = String("PARATR_DROP", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_REGISTER] = String("PARATR_REGISTER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_NUMRULE] = String("PARATR_NUMRULE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_SCRIPTSPACE] = String("PARATR_SCRIPTSPACE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_HANGINGPUNCTUATION] = String("PARATR_HANGINGPUNCTUATION", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_FORBIDDEN_RULES] = String("PARATR_FORBIDDEN_RULES", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_VERTALIGN] = String("PARATR_VERTALIGN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_SNAPTOGRID] = String("PARATR_SNAPTOGRID", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PARATR_CONNECT_BORDER] = String("PARATR_CONNECT_BORDER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FILL_ORDER] = String("FILL_ORDER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FRM_SIZE] = String("FRM_SIZE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PAPER_BIN] = String("PAPER_BIN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_LR_SPACE] = String("LR_SPACE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_UL_SPACE] = String("UL_SPACE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PAGEDESC] = String("PAGEDESC", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BREAK] = String("BREAK", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CNTNT] = String("CNTNT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_HEADER] = String("HEADER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FOOTER] = String("FOOTER", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PRINT] = String("PRINT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_OPAQUE] = String("OPAQUE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_PROTECT] = String("PROTECT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_SURROUND] = String("SURROUND", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_VERT_ORIENT] = String("VERT_ORIENT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_HORI_ORIENT] = String("HORI_ORIENT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_ANCHOR] = String("ANCHOR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BACKGROUND] = String("BACKGROUND", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BOX] = String("BOX", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_SHADOW] = String("SHADOW", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FRMMACRO] = String("FRMMACRO", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_COL] = String("COL", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_KEEP] = String("KEEP", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_URL] = String("URL", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_EDIT_IN_READONLY] = String("EDIT_IN_READONLY", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_LAYOUT_SPLIT] = String("LAYOUT_SPLIT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_CHAIN] = String("CHAIN", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_TEXTGRID] = String("TEXTGRID", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_LINENUMBER ] = String("LINENUMBER ", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FTN_AT_TXTEND] = String("FTN_AT_TXTEND", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_END_AT_TXTEND] = String("END_AT_TXTEND", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_COLUMNBALANCE] = String("COLUMNBALANCE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_FRAMEDIR] = String("FRAMEDIR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_HEADER_FOOTER_EAT_SPACING] = String("HEADER_FOOTER_EAT_SPACING", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_ROW_SPLIT] = String("ROW_SPLIT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_MIRRORGRF] = String("GRFATR_MIRRORGRF", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_CROPGRF] = String("GRFATR_CROPGRF", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_ROTATION] = String("GRFATR_ROTATION", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_LUMINANCE] = String("GRFATR_LUMINANCE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_CONTRAST] = String("GRFATR_CONTRAST", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_CHANNELR] = String("GRFATR_CHANNELR", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_CHANNELG] = String("GRFATR_CHANNELG", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_CHANNELB] = String("GRFATR_CHANNELB", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_GAMMA] = String("GRFATR_GAMMA", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_INVERT] = String("GRFATR_INVERT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_TRANSPARENCY] = String("GRFATR_TRANSPARENCY", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_GRFATR_DRAWMODE] = String("GRFATR_DRAWMODE", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BOXATR_FORMAT] = String("BOXATR_FORMAT", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BOXATR_FORMULA] = String("BOXATR_FORMULA", RTL_TEXTENCODING_ASCII_US); + aItemWhichMap[RES_BOXATR_VALUE] = String("BOXATR_VALUE", RTL_TEXTENCODING_ASCII_US); + + bInitialized = true; + } + + return aItemWhichMap; +} + +const String lcl_dbg_out(const SfxPoolItem & rItem) +{ + String aStr("[ ", RTL_TEXTENCODING_ASCII_US); + + if (GetItemWhichMap().find(rItem.Which()) != GetItemWhichMap().end()) + aStr += GetItemWhichMap()[rItem.Which()]; + else + aStr += String::CreateFromInt32(rItem.Which()); + + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SfxPoolItem & rItem) +{ + return dbg_out(lcl_dbg_out(rItem)); +} + +SW_DLLPUBLIC const char * dbg_out(const SfxPoolItem * pItem) +{ + return dbg_out(pItem ? lcl_dbg_out(*pItem) : + String("(nil)", RTL_TEXTENCODING_ASCII_US)); +} + +SW_DLLPUBLIC const String lcl_dbg_out(const SfxItemSet & rSet) +{ + SfxItemIter aIter(rSet); + const SfxPoolItem * pItem; + bool bFirst = true; + String aStr = String("[ ", RTL_TEXTENCODING_ASCII_US); + + pItem = aIter.FirstItem(); + + while (pItem ) + { + if (!bFirst) + aStr += String(", ", RTL_TEXTENCODING_ASCII_US); + + if ((sal_uIntPtr)pItem != SAL_MAX_SIZE) + aStr += lcl_dbg_out(*pItem); + else + aStr += String("invalid", RTL_TEXTENCODING_ASCII_US); + + bFirst = false; + + pItem = aIter.NextItem(); + } + + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SfxItemSet & rSet) +{ + return dbg_out(lcl_dbg_out(rSet)); +} + +const String lcl_dbg_out(const SwTxtAttr & rAttr) +{ + String aStr("[ ", RTL_TEXTENCODING_ASCII_US); + + aStr += String::CreateFromInt32(*rAttr.GetStart()); + aStr += String("->", RTL_TEXTENCODING_ASCII_US); + aStr += String::CreateFromInt32(*rAttr.GetEnd()); + aStr += String(" ", RTL_TEXTENCODING_ASCII_US); + aStr += lcl_dbg_out(rAttr.GetAttr()); + + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwTxtAttr & rAttr) +{ + return dbg_out(lcl_dbg_out(rAttr)); +} + +const String lcl_dbg_out(const SwpHints & rHints) +{ + String aStr("[ SwpHints\n", RTL_TEXTENCODING_ASCII_US); + + for (sal_uInt16 i = 0; i < rHints.Count(); i++) + { + aStr += String(" ", RTL_TEXTENCODING_ASCII_US); + aStr += lcl_dbg_out(*rHints[i]); + aStr += String("\n", RTL_TEXTENCODING_ASCII_US); + } + + aStr += String("]\n", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwpHints &rHints) +{ + return dbg_out(lcl_dbg_out(rHints)); +} + +String lcl_dbg_out(const SwPosition & rPos) +{ + String aStr("( ", RTL_TEXTENCODING_ASCII_US); + + aStr += String::CreateFromInt32(rPos.nNode.GetIndex()); + aStr += String(", ", RTL_TEXTENCODING_ASCII_US); + aStr += String::CreateFromInt32(rPos.nContent.GetIndex()); + aStr += String(": ", RTL_TEXTENCODING_ASCII_US); + aStr += String::CreateFromInt32 + (reinterpret_cast<sal_IntPtr>(rPos.nContent.GetIdxReg()), 16); + + aStr += String(" )", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwPosition & rPos) +{ + return dbg_out(lcl_dbg_out(rPos)); +} + +String lcl_dbg_out(const SwPaM & rPam) +{ + String aStr("[ Pt: ", RTL_TEXTENCODING_ASCII_US); + + aStr += lcl_dbg_out(*rPam.GetPoint()); + + if (rPam.HasMark()) + { + aStr += String(", Mk: ", RTL_TEXTENCODING_ASCII_US); + aStr += lcl_dbg_out(*rPam.GetMark()); + } + + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwPaM & rPam) +{ + return dbg_out(lcl_dbg_out(rPam)); +} + +String lcl_dbg_out(const SwNodeNum & ) +{ + return String();/*rNum.ToString();*/ +} + +SW_DLLPUBLIC const char * dbg_out(const SwNodeNum & rNum) +{ + return dbg_out(lcl_dbg_out(rNum)); +} + +String lcl_dbg_out(const SwRect & rRect) +{ + String aResult("[ [", RTL_TEXTENCODING_ASCII_US); + + aResult += String::CreateFromInt32(rRect.Left()); + aResult += String(", ", RTL_TEXTENCODING_ASCII_US); + aResult += String::CreateFromInt32(rRect.Top()); + aResult += String("], [", RTL_TEXTENCODING_ASCII_US); + aResult += String::CreateFromInt32(rRect.Right()); + aResult += String(", ", RTL_TEXTENCODING_ASCII_US); + aResult += String::CreateFromInt32(rRect.Bottom()); + + aResult += String("] ]", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwRect & rRect) +{ + return dbg_out(lcl_dbg_out(rRect)); +} + +String lcl_dbg_out(const SwFrmFmt & rFrmFmt) +{ + String aResult("[ ", RTL_TEXTENCODING_ASCII_US); + + char sBuffer[256]; + sprintf(sBuffer, "%p", &rFrmFmt); + + aResult += String(sBuffer, RTL_TEXTENCODING_ASCII_US); + aResult += String("(", RTL_TEXTENCODING_ASCII_US); + aResult += rFrmFmt.GetName(); + aResult += String(")", RTL_TEXTENCODING_ASCII_US); + + if (rFrmFmt.IsAuto()) + aResult += String("*", RTL_TEXTENCODING_ASCII_US); + + aResult += String(" ,", RTL_TEXTENCODING_ASCII_US); + aResult += lcl_dbg_out(rFrmFmt.FindLayoutRect()); + aResult += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwFrmFmt & rFrmFmt) +{ + return dbg_out(lcl_dbg_out(rFrmFmt)); +} + +const String lcl_AnchoredFrames(const SwNode & rNode) +{ + String aResult("[", RTL_TEXTENCODING_ASCII_US); + + const SwDoc * pDoc = rNode.GetDoc(); + if (pDoc) + { + const SwSpzFrmFmts * pFrmFmts = pDoc->GetSpzFrmFmts(); + + if (pFrmFmts) + { + bool bFirst = true; + for (sal_uInt16 nI = 0; nI < pFrmFmts->Count(); nI++) + { + const SwFmtAnchor & rAnchor = (*pFrmFmts)[nI]->GetAnchor(); + const SwPosition * pPos = rAnchor.GetCntntAnchor(); + + if (pPos && &pPos->nNode.GetNode() == &rNode) + { + if (! bFirst) + aResult += String(", ", RTL_TEXTENCODING_ASCII_US); + + if ((*pFrmFmts)[nI]) + aResult += lcl_dbg_out(*(*pFrmFmts)[nI]); + bFirst = false; + } + } + } + } + + aResult += String("]", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +String lcl_dbg_out_NumType(sal_Int16 nType) +{ + String aTmpStr; + + switch (nType) + { + case SVX_NUM_NUMBER_NONE: + aTmpStr += String(" NONE", RTL_TEXTENCODING_ASCII_US); + + break; + case SVX_NUM_CHARS_UPPER_LETTER: + aTmpStr += String(" CHARS_UPPER_LETTER", + RTL_TEXTENCODING_ASCII_US); + + break; + case SVX_NUM_CHARS_LOWER_LETTER: + aTmpStr += String(" CHARS_LOWER_LETTER", + RTL_TEXTENCODING_ASCII_US); + + break; + case SVX_NUM_ROMAN_UPPER: + aTmpStr += String(" ROMAN_UPPER", + RTL_TEXTENCODING_ASCII_US); + + break; + case SVX_NUM_ROMAN_LOWER: + aTmpStr += String(" ROMAN_LOWER", + RTL_TEXTENCODING_ASCII_US); + + break; + case SVX_NUM_ARABIC: + aTmpStr += String(" ARABIC", + RTL_TEXTENCODING_ASCII_US); + + break; + default: + aTmpStr += String(" ??", + RTL_TEXTENCODING_ASCII_US); + + break; + } + + return aTmpStr; +} + +String lcl_dbg_out(const SwNode & rNode) +{ + String aTmpStr; + + aTmpStr += String("<node ", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String("index=\"", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String::CreateFromInt32(rNode.GetIndex()); + aTmpStr += String("\"", RTL_TEXTENCODING_ASCII_US); + +#ifdef DBG_UTIL + aTmpStr += String(" serial=\"", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String::CreateFromInt32(rNode.GetSerial()); + aTmpStr += String("\"", RTL_TEXTENCODING_ASCII_US); +#endif + + aTmpStr += String(" type=\"", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String::CreateFromInt32(sal_Int32( rNode.GetNodeType() ) ); + aTmpStr += String("\"", RTL_TEXTENCODING_ASCII_US); + + aTmpStr += String(" pointer=\"", RTL_TEXTENCODING_ASCII_US); + + char aBuffer[128]; + sprintf(aBuffer, "%p", &rNode); + aTmpStr += String(aBuffer, RTL_TEXTENCODING_ASCII_US); + + aTmpStr += String("\">", RTL_TEXTENCODING_ASCII_US); + + const SwTxtNode * pTxtNode = rNode.GetTxtNode(); + + if (rNode.IsTxtNode()) + { + const SfxItemSet * pAttrSet = pTxtNode->GetpSwAttrSet(); + + aTmpStr += String("<txt>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += pTxtNode->GetTxt().Copy(0, 10); + aTmpStr += String("</txt>", RTL_TEXTENCODING_ASCII_US); + + if (rNode.IsTableNode()) + aTmpStr += String("<tbl/>", RTL_TEXTENCODING_ASCII_US); + + aTmpStr += String("<outlinelevel>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String::CreateFromInt32(pTxtNode->GetAttrOutlineLevel()-1); + aTmpStr += String("</outlinelevel>", RTL_TEXTENCODING_ASCII_US); + + const SwNumRule * pNumRule = pTxtNode->GetNumRule(); + + if (pNumRule != NULL) + { + aTmpStr += String("<number>", RTL_TEXTENCODING_ASCII_US); + if ( pTxtNode->GetNum() ) + { + aTmpStr += lcl_dbg_out(*(pTxtNode->GetNum())); + } + aTmpStr += String("</number>", RTL_TEXTENCODING_ASCII_US); + + aTmpStr += String("<rule>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += pNumRule->GetName(); + + const SfxPoolItem * pItem = NULL; + + if (pAttrSet && SFX_ITEM_SET == + pAttrSet->GetItemState(RES_PARATR_NUMRULE, sal_False, &pItem)) + { + aTmpStr += String("(", RTL_TEXTENCODING_ASCII_US); + aTmpStr += + static_cast<const SwNumRuleItem *>(pItem)->GetValue(); + aTmpStr += String(")", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String("*", RTL_TEXTENCODING_ASCII_US); + } + + const SwNumFmt * pNumFmt = NULL; + aTmpStr += String("</rule>", RTL_TEXTENCODING_ASCII_US); + + if (pTxtNode->GetActualListLevel() > 0) + pNumFmt = pNumRule->GetNumFmt( static_cast< sal_uInt16 >(pTxtNode->GetActualListLevel()) ); + + if (pNumFmt) + { + aTmpStr += String("<numformat>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += + lcl_dbg_out_NumType(pNumFmt->GetNumberingType()); + aTmpStr += String("</numformat>", RTL_TEXTENCODING_ASCII_US); + } + } + + if (pTxtNode->IsCountedInList()) + aTmpStr += String("<counted/>", RTL_TEXTENCODING_ASCII_US); + + SwFmtColl * pColl = pTxtNode->GetFmtColl(); + + if (pColl) + { + aTmpStr += String("<coll>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += pColl->GetName(); + + aTmpStr += String("(", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String::CreateFromInt32 + //(static_cast<SwTxtFmtColl *>(pColl)->GetOutlineLevel());//#outline level,zhaojianwei + (static_cast<SwTxtFmtColl *>(pColl)->GetAssignedOutlineStyleLevel());//<-end,zhaojianwei + + const SwNumRuleItem & rItem = + static_cast<const SwNumRuleItem &> + (pColl->GetFmtAttr(RES_PARATR_NUMRULE)); + const String sNumruleName = rItem.GetValue(); + + if (sNumruleName.Len() > 0) + { + aTmpStr += String(", ", RTL_TEXTENCODING_ASCII_US); + aTmpStr += sNumruleName; + } + aTmpStr += String(")", RTL_TEXTENCODING_ASCII_US); + aTmpStr += String("</coll>", RTL_TEXTENCODING_ASCII_US); + } + + SwFmtColl * pCColl = pTxtNode->GetCondFmtColl(); + + if (pCColl) + { + aTmpStr += String("<ccoll>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += pCColl->GetName(); + aTmpStr += String("</ccoll>", RTL_TEXTENCODING_ASCII_US); + } + + aTmpStr += String("<frms>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += lcl_AnchoredFrames(rNode); + aTmpStr += String("</frms>", RTL_TEXTENCODING_ASCII_US); + + if (bDbgOutPrintAttrSet) + { + aTmpStr += String("<attrs>", RTL_TEXTENCODING_ASCII_US); + aTmpStr += lcl_dbg_out(pTxtNode->GetSwAttrSet()); + aTmpStr += String("</attrs>", RTL_TEXTENCODING_ASCII_US); + } + } + else if (rNode.IsStartNode()) + { + aTmpStr += String("<start end=\"", RTL_TEXTENCODING_ASCII_US); + + const SwStartNode * pStartNode = dynamic_cast<const SwStartNode *> (&rNode); + if (pStartNode != NULL) + aTmpStr += String::CreateFromInt32(pStartNode->EndOfSectionNode()->GetIndex()); + + aTmpStr += String("\"/>", RTL_TEXTENCODING_ASCII_US); + } + else if (rNode.IsEndNode()) + aTmpStr += String("<end/>", RTL_TEXTENCODING_ASCII_US); + + aTmpStr += String("</node>", RTL_TEXTENCODING_ASCII_US); + + return aTmpStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwNode & rNode) +{ + return dbg_out(lcl_dbg_out(rNode)); +} + +SW_DLLPUBLIC const char * dbg_out(const SwNode * pNode) +{ + if (NULL != pNode) + return dbg_out(*pNode); + else + return NULL; +} + +SW_DLLPUBLIC const char * dbg_out(const SwCntntNode * pNode) +{ + if (NULL != pNode) + return dbg_out(*pNode); + else + return NULL; +} + +SW_DLLPUBLIC const char * dbg_out(const SwTxtNode * pNode) +{ + if (NULL != pNode) + return dbg_out(*pNode); + else + return NULL; +} + +sal_Bool lcl_dbg_add_node(const SwNodePtr & pNode, void * pArgs) +{ + if (pNode) + { + (*((String *) pArgs)) += lcl_dbg_out(*pNode); + (*((String *) pArgs)) += String("\n", RTL_TEXTENCODING_ASCII_US); + } + + //MBA: this code didn't compile, needed to add a return value + return sal_True; +} + +void lcl_dbg_nodes_inner(String & aStr, SwNodes & rNodes, sal_uLong & nIndex) +{ + SwNode * pNode = rNodes[nIndex]; + SwStartNode * pStartNode = dynamic_cast<SwStartNode *> (pNode); + + SwNode * pEndNode = NULL; + if (pStartNode != NULL) + pEndNode = pStartNode->EndOfSectionNode(); + + sal_uLong nCount = rNodes.Count(); + sal_uLong nStartIndex = nIndex; + + bool bDone = false; + + String aTag; + if (pNode->IsTableNode()) + aTag += String("table", RTL_TEXTENCODING_ASCII_US); + else if (pNode->IsSectionNode()) + aTag += String("section", RTL_TEXTENCODING_ASCII_US); + else + aTag += String("nodes", RTL_TEXTENCODING_ASCII_US); + + aStr += String("<", RTL_TEXTENCODING_ASCII_US); + aStr += aTag; + aStr += String(">", RTL_TEXTENCODING_ASCII_US); + + while (! bDone) + { + if (pNode->IsStartNode() && nIndex != nStartIndex) + lcl_dbg_nodes_inner(aStr, rNodes, nIndex); + else + { + aStr += lcl_dbg_out(*pNode); + aStr += String("\n", RTL_TEXTENCODING_ASCII_US); + + nIndex++; + } + + if (pNode == pEndNode || nIndex >= nCount) + bDone = true; + else + pNode = rNodes[nIndex]; + } + + aStr += String("</", RTL_TEXTENCODING_ASCII_US); + aStr += aTag; + aStr += String(">\n", RTL_TEXTENCODING_ASCII_US); +} + +String lcl_dbg_out(SwNodes & rNodes) +{ + String aStr("<nodes-array>", RTL_TEXTENCODING_ASCII_US); + + sal_uLong nIndex = 0; + sal_uLong nCount = rNodes.Count(); + + while (nIndex < nCount) + { + lcl_dbg_nodes_inner(aStr, rNodes, nIndex); + } + + aStr += String("</nodes-array>\n", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(SwNodes & rNodes) +{ + return dbg_out(lcl_dbg_out(rNodes)); +} + +String lcl_dbg_out(const SwUndo & rUndo) +{ + String aStr("[ ", RTL_TEXTENCODING_ASCII_US); + + aStr += String::CreateFromInt32( + static_cast<SfxUndoAction const&>(rUndo).GetId()); + aStr += String(": ", RTL_TEXTENCODING_ASCII_US); + + aStr += rUndo.GetComment(); + aStr += String(" ]", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwUndo & rUndo) +{ + return dbg_out(lcl_dbg_out(rUndo)); +} + +String lcl_dbg_out(SwOutlineNodes & rNodes) +{ + String aStr("[\n", RTL_TEXTENCODING_ASCII_US); + + for (sal_uInt16 i = 0; i < rNodes.Count(); i++) + { + aStr += lcl_dbg_out(*rNodes[i]); + aStr += String("\n", RTL_TEXTENCODING_ASCII_US); + } + + aStr += String("]\n", RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(SwOutlineNodes & rNodes) +{ + return dbg_out(lcl_dbg_out(rNodes)); +} + +String lcl_dbg_out(const SwRewriter & rRewriter) +{ + (void) rRewriter; + String aResult; + + //aResult = rRewriter.ToString(); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwRewriter & rRewriter) +{ + return dbg_out(lcl_dbg_out(rRewriter)); +} + +String lcl_dbg_out(const SvxNumberFormat & rFmt) +{ + String aResult; + + aResult = lcl_dbg_out_NumType(rFmt.GetNumberingType()); + + return aResult; +} + +String lcl_dbg_out(const SwNumRule & rRule) +{ + String aResult("[ ", RTL_TEXTENCODING_ASCII_US); + + aResult += rRule.GetName(); + aResult += String(" [", RTL_TEXTENCODING_ASCII_US); + + for (sal_uInt8 n = 0; n < MAXLEVEL; n++) + { + if (n > 0) + aResult += String(", ", RTL_TEXTENCODING_ASCII_US); + + aResult += lcl_dbg_out(rRule.Get(n)); + } + + aResult += String("]", RTL_TEXTENCODING_ASCII_US); + + aResult += String("]", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwNumRule & rRule) +{ + return dbg_out(lcl_dbg_out(rRule)); +} + +String lcl_dbg_out(const SwTxtFmtColl & rFmt) +{ + String aResult(rFmt.GetName()); + + aResult += String("(", RTL_TEXTENCODING_ASCII_US); + aResult += String::CreateFromInt32(rFmt.GetAttrOutlineLevel()); + aResult += String(")", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwTxtFmtColl & rFmt) +{ + return dbg_out(lcl_dbg_out(rFmt)); +} + +String lcl_dbg_out(const SwFrmFmts & rFrmFmts) +{ + return lcl_dbg_out_SvPtrArr<SwFrmFmts>(rFrmFmts); +} + +SW_DLLPUBLIC const char * dbg_out(const SwFrmFmts & rFrmFmts) +{ + return dbg_out(lcl_dbg_out(rFrmFmts)); +} + +String lcl_dbg_out(const SwNumRuleTbl & rTbl) +{ + String aResult("[", RTL_TEXTENCODING_ASCII_US); + + for (sal_uInt16 n = 0; n < rTbl.Count(); n++) + { + if (n > 0) + aResult += String(", ", RTL_TEXTENCODING_ASCII_US); + + aResult += rTbl[n]->GetName(); + + char sBuffer[256]; + sprintf(sBuffer, "(%p)", rTbl[n]); + aResult += String(sBuffer, RTL_TEXTENCODING_ASCII_US); + } + + aResult += String("]", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +SW_DLLPUBLIC const char * dbg_out(const SwNumRuleTbl & rTbl) +{ + return dbg_out(lcl_dbg_out(rTbl)); +} + +String lcl_TokenType2Str(FormTokenType nType) +{ + switch(nType) + { + case TOKEN_ENTRY_NO: + return String("NO", RTL_TEXTENCODING_ASCII_US); + case TOKEN_ENTRY_TEXT: + return String("ENTRY_TEXT", RTL_TEXTENCODING_ASCII_US); + case TOKEN_ENTRY: + return String("ENTRY", RTL_TEXTENCODING_ASCII_US); + case TOKEN_TAB_STOP: + return String("TAB_STOP", RTL_TEXTENCODING_ASCII_US); + case TOKEN_TEXT: + return String("TOKEN_TEXT", RTL_TEXTENCODING_ASCII_US); + case TOKEN_PAGE_NUMS: + return String("NUMS", RTL_TEXTENCODING_ASCII_US); + case TOKEN_CHAPTER_INFO: + return String("CHAPTER_INFO", RTL_TEXTENCODING_ASCII_US); + case TOKEN_LINK_START: + return String("LINK_START", RTL_TEXTENCODING_ASCII_US); + case TOKEN_LINK_END: + return String("LINK_END", RTL_TEXTENCODING_ASCII_US); + case TOKEN_AUTHORITY: + return String("AUTHORITY", RTL_TEXTENCODING_ASCII_US); + case TOKEN_END: + return String("END", RTL_TEXTENCODING_ASCII_US); + default: + return String("??", RTL_TEXTENCODING_ASCII_US); + } + + ASSERT(false, "should not be reached"); + + return String("??", RTL_TEXTENCODING_ASCII_US); +} + +String lcl_dbg_out(const SwFormToken & rToken) +{ + return rToken.GetString(); +} + +SW_DLLPUBLIC const char * dbg_out(const SwFormToken & rToken) +{ + return dbg_out(lcl_dbg_out(rToken)); +} + +String lcl_dbg_out(const SwFormTokens & rTokens) +{ + String aStr("[", RTL_TEXTENCODING_ASCII_US); + + SwFormTokens::const_iterator aIt; + + for (aIt = rTokens.begin(); aIt != rTokens.end(); aIt++) + { + if (aIt != rTokens.begin()) + aStr += String(", ", RTL_TEXTENCODING_ASCII_US); + + aStr += lcl_TokenType2Str(aIt->eTokenType); + aStr += String(": ", RTL_TEXTENCODING_ASCII_US); + aStr += lcl_dbg_out(*aIt); + } + + aStr += String("]" , RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwFormTokens & rTokens) +{ + return dbg_out(lcl_dbg_out(rTokens)); +} + +String lcl_dbg_out(const SwNodeRange & rRange) +{ + String aStr("[", RTL_TEXTENCODING_ASCII_US); + + aStr += lcl_dbg_out(SwPosition(rRange.aStart)); + aStr += String(", ", RTL_TEXTENCODING_ASCII_US); + aStr += lcl_dbg_out(SwPosition(rRange.aEnd)); + + aStr += String("]" , RTL_TEXTENCODING_ASCII_US); + + return aStr; +} + +SW_DLLPUBLIC const char * dbg_out(const SwNodeRange & rRange) +{ + return dbg_out(lcl_dbg_out(rRange)); +} + +#endif // DEBUG + diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx new file mode 100644 index 000000000000..47dc02014aa7 --- /dev/null +++ b/sw/source/core/doc/doc.cxx @@ -0,0 +1,2836 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <doc.hxx> +#include <UndoManager.hxx> +#include <hintids.hxx> + +#include <tools/shl.hxx> +#include <tools/globname.hxx> +#include <svx/svxids.hrc> +#include <com/sun/star/i18n/WordType.hdl> +#include <com/sun/star/i18n/ForbiddenCharacters.hdl> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <comphelper/processfactory.hxx> +#include <tools/urlobj.hxx> +#include <tools/poly.hxx> +#include <tools/multisel.hxx> +#include <rtl/ustring.hxx> +#include <vcl/virdev.hxx> +#include <svl/itemiter.hxx> +#include <svl/poolitem.hxx> +#include <unotools/syslocale.hxx> +#include <sfx2/printer.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/brkitem.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <svx/svdmodel.hxx> +#include <editeng/pbinitem.hxx> +#include <unotools/charclass.hxx> +#include <unotools/localedatawrapper.hxx> + +#include <swatrset.hxx> +#include <swmodule.hxx> +#include <fmtpdsc.hxx> +#include <fmtanchr.hxx> +#include <fmtrfmrk.hxx> +#include <fmtinfmt.hxx> +#include <fmtfld.hxx> +#include <txtfld.hxx> +#include <dbfld.hxx> +#include <txtinet.hxx> +#include <txtrfmrk.hxx> +#include <frmatr.hxx> +#include <linkenum.hxx> +#include <errhdl.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <swtable.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <UndoCore.hxx> +#include <UndoInsert.hxx> +#include <UndoSplitMove.hxx> +#include <UndoTable.hxx> +#include <pagedesc.hxx> //DTor +#include <breakit.hxx> +#include <ndole.hxx> +#include <ndgrf.hxx> +#include <rolbck.hxx> // Undo-Attr +#include <doctxm.hxx> // fuer die Verzeichnisse +#include <grfatr.hxx> +#include <poolfmt.hxx> // PoolVorlagen-Id's +#include <mvsave.hxx> // fuer Server-Funktionalitaet +#include <SwGrammarMarkUp.hxx> +#include <scriptinfo.hxx> +#include <acorrect.hxx> // Autokorrektur +#include <mdiexp.hxx> // Statusanzeige +#include <docstat.hxx> +#include <docary.hxx> +#include <redline.hxx> +#include <fldupde.hxx> +#include <swbaslnk.hxx> +#include <printdata.hxx> +#include <cmdid.h> // fuer den dflt - Printer in SetJob +#include <statstr.hrc> // StatLine-String +#include <comcore.hrc> +#include <SwUndoTOXChange.hxx> +#include <SwUndoFmt.hxx> +#include <unocrsr.hxx> +#include <docsh.hxx> +#include <docfld.hxx> // _SetGetExpFld +#include <docufld.hxx> // SwPostItField +#include <viewsh.hxx> +#include <shellres.hxx> +#include <txtfrm.hxx> +#include <wdocsh.hxx> // SwWebDocShell +#include <prtopt.hxx> // SwPrintOptions + +#include <vector> +#include <map> + +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <vbahelper/vbaaccesshelper.hxx> + +/* @@@MAINTAINABILITY-HORROR@@@ + Probably unwanted dependency on SwDocShell +*/ +// --> OD 2005-08-29 #125370# +#include <layouter.hxx> +// <-- + +using namespace ::com::sun::star; +using ::rtl::OUString; + + +// Seiten-Deskriptoren +SV_IMPL_PTRARR(SwPageDescs,SwPageDescPtr); +// Verzeichnisse +SV_IMPL_PTRARR( SwTOXTypes, SwTOXTypePtr ) +// FeldTypen +SV_IMPL_PTRARR( SwFldTypes, SwFldTypePtr) + +/** IInterface +*/ +sal_Int32 SwDoc::acquire() +{ + OSL_ASSERT(mReferenceCount >= 0 && "Negative reference count detected! This is a sign for unbalanced acquire/release calls."); + return osl_incrementInterlockedCount(&mReferenceCount); +} + +sal_Int32 SwDoc::release() +{ + OSL_PRECOND(mReferenceCount >= 1, "Object is already released! Releasing it again leads to a negative reference count."); + return osl_decrementInterlockedCount(&mReferenceCount); +} + +sal_Int32 SwDoc::getReferenceCount() const +{ + OSL_ASSERT(mReferenceCount >= 0 && "Negative reference count detected! This is a sign for unbalanced acquire/release calls."); + return mReferenceCount; +} + +/** IDocumentSettingAccess +*/ +bool SwDoc::get(/*[in]*/ DocumentSettingId id) const +{ + switch (id) + { + // COMPATIBILITY FLAGS START + case PARA_SPACE_MAX: return mbParaSpaceMax; //(n8Dummy1 & DUMMY_PARASPACEMAX); + case PARA_SPACE_MAX_AT_PAGES: return mbParaSpaceMaxAtPages; //(n8Dummy1 & DUMMY_PARASPACEMAX_AT_PAGES); + case TAB_COMPAT: return mbTabCompat; //(n8Dummy1 & DUMMY_TAB_COMPAT); + case ADD_FLY_OFFSETS: return mbAddFlyOffsets; //(n8Dummy2 & DUMMY_ADD_FLY_OFFSETS); + case ADD_EXT_LEADING: return mbAddExternalLeading; //(n8Dummy2 & DUMMY_ADD_EXTERNAL_LEADING); + case USE_VIRTUAL_DEVICE: return mbUseVirtualDevice; //(n8Dummy1 & DUMMY_USE_VIRTUAL_DEVICE); + case USE_HIRES_VIRTUAL_DEVICE: return mbUseHiResolutionVirtualDevice; //(n8Dummy2 & DUMMY_USE_HIRES_VIR_DEV); + case OLD_NUMBERING: return mbOldNumbering; + case OLD_LINE_SPACING: return mbOldLineSpacing; + case ADD_PARA_SPACING_TO_TABLE_CELLS: return mbAddParaSpacingToTableCells; + case USE_FORMER_OBJECT_POS: return mbUseFormerObjectPos; + case USE_FORMER_TEXT_WRAPPING: return mbUseFormerTextWrapping; + case CONSIDER_WRAP_ON_OBJECT_POSITION: return mbConsiderWrapOnObjPos; + case DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK: return mbDoNotJustifyLinesWithManualBreak; + case IGNORE_FIRST_LINE_INDENT_IN_NUMBERING: return mbIgnoreFirstLineIndentInNumbering; + case OUTLINE_LEVEL_YIELDS_OUTLINE_RULE: return mbOutlineLevelYieldsOutlineRule; + case TABLE_ROW_KEEP: return mbTableRowKeep; + case IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION: return mbIgnoreTabsAndBlanksForLineCalculation; + case DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE: return mbDoNotCaptureDrawObjsOnPage; + // --> OD 2006-08-25 #i68949# + case CLIP_AS_CHARACTER_ANCHORED_WRITER_FLY_FRAME: return mbClipAsCharacterAnchoredWriterFlyFrames; + // <-- + case UNIX_FORCE_ZERO_EXT_LEADING: return mbUnixForceZeroExtLeading; + case USE_OLD_PRINTER_METRICS: return mbOldPrinterMetrics; + case TABS_RELATIVE_TO_INDENT : return mbTabRelativeToIndent; + case PROTECT_FORM: return mbProtectForm; + // --> OD 2008-06-05 #i89181# + case TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST: return mbTabAtLeftIndentForParagraphsInList; + // <-- + // COMPATIBILITY FLAGS END + + case BROWSE_MODE: return mbBrowseMode; + case HTML_MODE: return mbHTMLMode; + case GLOBAL_DOCUMENT: return mbIsGlobalDoc; + case GLOBAL_DOCUMENT_SAVE_LINKS: return mbGlblDocSaveLinks; + case LABEL_DOCUMENT: return mbIsLabelDoc; + case PURGE_OLE: return mbPurgeOLE; + case KERN_ASIAN_PUNCTUATION: return mbKernAsianPunctuation; + case DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT: return mbDoNotResetParaAttrsForNumFont; + case MATH_BASELINE_ALIGNMENT: return mbMathBaselineAlignment; + default: + ASSERT(false, "Invalid setting id"); + } + return false; +} + +void SwDoc::set(/*[in]*/ DocumentSettingId id, /*[in]*/ bool value) +{ + switch (id) + { + // COMPATIBILITY FLAGS START + case PARA_SPACE_MAX: + mbParaSpaceMax = value; + break; + case PARA_SPACE_MAX_AT_PAGES: + mbParaSpaceMaxAtPages = value; + break; + case TAB_COMPAT: + mbTabCompat = value; + break; + case ADD_FLY_OFFSETS: + mbAddFlyOffsets = value; + break; + case ADD_EXT_LEADING: + mbAddExternalLeading = value; + break; + case USE_VIRTUAL_DEVICE: + mbUseVirtualDevice = value; + break; + case USE_HIRES_VIRTUAL_DEVICE: + mbUseHiResolutionVirtualDevice = value; + break; + case OLD_NUMBERING: + if (mbOldNumbering != value) + { + mbOldNumbering = value; + + const SwNumRuleTbl& rNmTbl = GetNumRuleTbl(); + for( sal_uInt16 n = 0; n < rNmTbl.Count(); ++n ) + rNmTbl[n]->SetInvalidRule(sal_True); + + UpdateNumRule(); + + if (pOutlineRule) + { + pOutlineRule->Validate(); + // --> OD 2005-10-21 - counting of phantoms depends on <IsOldNumbering()> + pOutlineRule->SetCountPhantoms( !mbOldNumbering ); + // <-- + } + } + break; + case OLD_LINE_SPACING: + mbOldLineSpacing = value; + break; + case ADD_PARA_SPACING_TO_TABLE_CELLS: + mbAddParaSpacingToTableCells = value; + break; + case USE_FORMER_OBJECT_POS: + mbUseFormerObjectPos = value; + break; + case USE_FORMER_TEXT_WRAPPING: + mbUseFormerTextWrapping = value; + break; + case CONSIDER_WRAP_ON_OBJECT_POSITION: + mbConsiderWrapOnObjPos = value; + break; + case DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK: + mbDoNotJustifyLinesWithManualBreak = value; + break; + case IGNORE_FIRST_LINE_INDENT_IN_NUMBERING: + mbIgnoreFirstLineIndentInNumbering = value; + break; + + case OUTLINE_LEVEL_YIELDS_OUTLINE_RULE: + mbOutlineLevelYieldsOutlineRule = value; + break; + + case TABLE_ROW_KEEP: + mbTableRowKeep = value; + break; + + case IGNORE_TABS_AND_BLANKS_FOR_LINE_CALCULATION: + mbIgnoreTabsAndBlanksForLineCalculation = value; + break; + + case DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE: + mbDoNotCaptureDrawObjsOnPage = value; + break; + + // --> OD 2006-08-25 #i68949# + case CLIP_AS_CHARACTER_ANCHORED_WRITER_FLY_FRAME: + mbClipAsCharacterAnchoredWriterFlyFrames = value; + break; + // <-- + case UNIX_FORCE_ZERO_EXT_LEADING: + mbUnixForceZeroExtLeading = value; + break; + case PROTECT_FORM: + mbProtectForm = value; + break; + + case USE_OLD_PRINTER_METRICS: + mbOldPrinterMetrics = value; + break; + case TABS_RELATIVE_TO_INDENT: + mbTabRelativeToIndent = value; + break; + // --> OD 2008-06-05 #i89181# + case TAB_AT_LEFT_INDENT_FOR_PARA_IN_LIST: + mbTabAtLeftIndentForParagraphsInList = value; + break; + // <-- + // COMPATIBILITY FLAGS END + + case BROWSE_MODE: + mbBrowseMode = value; + break; + case HTML_MODE: + mbHTMLMode = value; + break; + case GLOBAL_DOCUMENT: + mbIsGlobalDoc = value; + break; + case GLOBAL_DOCUMENT_SAVE_LINKS: + mbGlblDocSaveLinks = value; + break; + case LABEL_DOCUMENT: + mbIsLabelDoc = value; + break; + case PURGE_OLE: + mbPurgeOLE = value; + break; + case KERN_ASIAN_PUNCTUATION: + mbKernAsianPunctuation = value; + break; + case DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT: + mbDoNotResetParaAttrsForNumFont = value; + break; + case MATH_BASELINE_ALIGNMENT: + mbMathBaselineAlignment = value; + break; + default: + ASSERT(false, "Invalid setting id"); + } +} + +const i18n::ForbiddenCharacters* + SwDoc::getForbiddenCharacters(/*[in]*/ sal_uInt16 nLang, /*[in]*/ bool bLocaleData ) const +{ + const i18n::ForbiddenCharacters* pRet = 0; + if( xForbiddenCharsTable.isValid() ) + pRet = xForbiddenCharsTable->GetForbiddenCharacters( nLang, sal_False ); + if( bLocaleData && !pRet && pBreakIt ) + pRet = &pBreakIt->GetForbidden( (LanguageType)nLang ); + return pRet; +} + +void SwDoc::setForbiddenCharacters(/*[in]*/ sal_uInt16 nLang, + /*[in]*/ const i18n::ForbiddenCharacters& rFChars ) +{ + if( !xForbiddenCharsTable.isValid() ) + { + uno::Reference< + lang::XMultiServiceFactory > xMSF = + ::comphelper::getProcessServiceFactory(); + xForbiddenCharsTable = new SvxForbiddenCharactersTable( xMSF ); + } + xForbiddenCharsTable->SetForbiddenCharacters( nLang, rFChars ); + if( pDrawModel ) + { + pDrawModel->SetForbiddenCharsTable( xForbiddenCharsTable ); + if( !mbInReading ) + pDrawModel->ReformatAllTextObjects(); + } + + if( pLayout && !mbInReading ) + { + pLayout->StartAllAction(); + pLayout->InvalidateAllCntnt(); + pLayout->EndAllAction(); + } + SetModified(); +} + +vos::ORef<SvxForbiddenCharactersTable>& SwDoc::getForbiddenCharacterTable() +{ + if( !xForbiddenCharsTable.isValid() ) + { + uno::Reference< + lang::XMultiServiceFactory > xMSF = + ::comphelper::getProcessServiceFactory(); + xForbiddenCharsTable = new SvxForbiddenCharactersTable( xMSF ); + } + return xForbiddenCharsTable; +} + +const vos::ORef<SvxForbiddenCharactersTable>& SwDoc::getForbiddenCharacterTable() const +{ + return xForbiddenCharsTable; +} + +sal_uInt16 SwDoc::getLinkUpdateMode( /*[in]*/bool bGlobalSettings ) const +{ + sal_uInt16 nRet = nLinkUpdMode; + if( bGlobalSettings && GLOBALSETTING == nRet ) + nRet = SW_MOD()->GetLinkUpdMode(get(IDocumentSettingAccess::HTML_MODE)); + return nRet; +} + +void SwDoc::setLinkUpdateMode( /*[in]*/sal_uInt16 eMode ) +{ + nLinkUpdMode = eMode; +} + +SwFldUpdateFlags SwDoc::getFieldUpdateFlags( /*[in]*/bool bGlobalSettings ) const +{ + SwFldUpdateFlags eRet = eFldUpdMode; + if( bGlobalSettings && AUTOUPD_GLOBALSETTING == eRet ) + eRet = SW_MOD()->GetFldUpdateFlags(get(IDocumentSettingAccess::HTML_MODE)); + return eRet; +} + +void SwDoc::setFieldUpdateFlags(/*[in]*/SwFldUpdateFlags eMode ) +{ + eFldUpdMode = eMode; +} + +SwCharCompressType SwDoc::getCharacterCompressionType() const +{ + return eChrCmprType; +} + +void SwDoc::setCharacterCompressionType( /*[in]*/SwCharCompressType n ) +{ + if( eChrCmprType != n ) + { + eChrCmprType = n; + if( pDrawModel ) + { + pDrawModel->SetCharCompressType( static_cast<sal_uInt16>(n) ); + if( !mbInReading ) + pDrawModel->ReformatAllTextObjects(); + } + + if( pLayout && !mbInReading ) + { + pLayout->StartAllAction(); + pLayout->InvalidateAllCntnt(); + pLayout->EndAllAction(); + } + SetModified(); + } +} + +/** IDocumentDeviceAccess +*/ +SfxPrinter* SwDoc::getPrinter(/*[in]*/ bool bCreate ) const +{ + SfxPrinter* pRet = 0; + if ( !bCreate || pPrt ) + pRet = pPrt; + else + pRet = &CreatePrinter_(); + + return pRet; +} + +void SwDoc::setPrinter(/*[in]*/ SfxPrinter *pP,/*[in]*/ bool bDeleteOld,/*[in]*/ bool bCallPrtDataChanged ) +{ + if ( pP != pPrt ) + { + if ( bDeleteOld ) + delete pPrt; + pPrt = pP; + + // our printer should always use TWIP. Don't rely on this being set in ViewShell::InitPrt, there + // are situations where this isn't called. + // #i108712# / 2010-02-26 / frank.schoenheit@sun.com + if ( pPrt ) + { + MapMode aMapMode( pPrt->GetMapMode() ); + aMapMode.SetMapUnit( MAP_TWIP ); + pPrt->SetMapMode( aMapMode ); + } + + if ( pDrawModel && !get( IDocumentSettingAccess::USE_VIRTUAL_DEVICE ) ) + pDrawModel->SetRefDevice( pPrt ); + } + + if ( bCallPrtDataChanged && + // --> FME 2005-01-21 #i41075# Do not call PrtDataChanged() if we do not + // use the printer for formatting: + !get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE) ) + // <-- + PrtDataChanged(); +} + +VirtualDevice* SwDoc::getVirtualDevice(/*[in]*/ bool bCreate ) const +{ + VirtualDevice* pRet = 0; + if ( !bCreate || pVirDev ) + pRet = pVirDev; + else + pRet = &CreateVirtualDevice_(); + + return pRet; +} + +void SwDoc::setVirtualDevice(/*[in]*/ VirtualDevice* pVd,/*[in]*/ bool bDeleteOld, /*[in]*/ bool ) +{ + if ( pVirDev != pVd ) + { + if ( bDeleteOld ) + delete pVirDev; + pVirDev = pVd; + + if ( pDrawModel && get( IDocumentSettingAccess::USE_VIRTUAL_DEVICE ) ) + pDrawModel->SetRefDevice( pVirDev ); + } +} + +OutputDevice* SwDoc::getReferenceDevice(/*[in]*/ bool bCreate ) const +{ + OutputDevice* pRet = 0; + if ( !get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE) ) + { + pRet = getPrinter( bCreate ); + + if ( bCreate && !pPrt->IsValid() ) + { + pRet = getVirtualDevice( sal_True ); + } + } + else + { + pRet = getVirtualDevice( bCreate ); + } + + return pRet; +} + +void SwDoc::setReferenceDeviceType(/*[in]*/ bool bNewVirtual,/*[in]*/ bool bNewHiRes ) +{ + if ( get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE) != bNewVirtual || + get(IDocumentSettingAccess::USE_HIRES_VIRTUAL_DEVICE) != bNewHiRes ) + { + if ( bNewVirtual ) + { + VirtualDevice* pMyVirDev = getVirtualDevice( true ); + if ( !bNewHiRes ) + pMyVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE06 ); + else + pMyVirDev->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 ); + + if( pDrawModel ) + pDrawModel->SetRefDevice( pMyVirDev ); + } + else + { + // --> FME 2005-01-21 #i41075# + // We have to take care that a printer exists before calling + // PrtDataChanged() in order to prevent that PrtDataChanged() + // triggers this funny situation: + // getReferenceDevice()->getPrinter()->CreatePrinter_() + // ->setPrinter()-> PrtDataChanged() + SfxPrinter* pPrinter = getPrinter( true ); + // <-- + if( pDrawModel ) + pDrawModel->SetRefDevice( pPrinter ); + } + + set(IDocumentSettingAccess::USE_VIRTUAL_DEVICE, bNewVirtual ); + set(IDocumentSettingAccess::USE_HIRES_VIRTUAL_DEVICE, bNewHiRes ); + PrtDataChanged(); + SetModified(); + } +} + +const JobSetup* SwDoc::getJobsetup() const +{ + return pPrt ? &pPrt->GetJobSetup() : 0; +} + +void SwDoc::setJobsetup(/*[in]*/ const JobSetup &rJobSetup ) +{ + sal_Bool bCheckPageDescs = 0 == pPrt; + sal_Bool bDataChanged = sal_False; + + if ( pPrt ) + { + if ( pPrt->GetName() == rJobSetup.GetPrinterName() ) + { + if ( pPrt->GetJobSetup() != rJobSetup ) + { + pPrt->SetJobSetup( rJobSetup ); + bDataChanged = sal_True; + } + } + else + delete pPrt, pPrt = 0; + } + + if( !pPrt ) + { + //Das ItemSet wird vom Sfx geloescht! + SfxItemSet *pSet = new SfxItemSet( GetAttrPool(), + FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER, + SID_HTML_MODE, SID_HTML_MODE, + SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC, + 0 ); + SfxPrinter *p = new SfxPrinter( pSet, rJobSetup ); + if ( bCheckPageDescs ) + setPrinter( p, true, true ); + else + { + pPrt = p; + bDataChanged = sal_True; + } + } + if ( bDataChanged && !get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE) ) + PrtDataChanged(); +} + +const SwPrintData & SwDoc::getPrintData() const +{ + if(!pPrtData) + { + SwDoc * pThis = const_cast< SwDoc * >(this); + pThis->pPrtData = new SwPrintData; + + // SwPrintData should be initialized from the configuration, + // the respective config item is implememted by SwPrintOptions which + // is also derived from SwPrintData + const SwDocShell *pDocSh = GetDocShell(); + DBG_ASSERT( pDocSh, "pDocSh is 0, can't determine if this is a WebDoc or not" ); + bool bWeb = 0 != dynamic_cast< const SwWebDocShell * >(pDocSh); + SwPrintOptions aPrintOptions( bWeb ); + *pThis->pPrtData = aPrintOptions; + } + return *pPrtData; +} + +void SwDoc::setPrintData(/*[in]*/ const SwPrintData& rPrtData ) +{ + if(!pPrtData) + pPrtData = new SwPrintData; + *pPrtData = rPrtData; +} + +/** Implementations the next Interface here +*/ + +/* + * Dokumenteditieren (Doc-SS) zum Fuellen des Dokuments + * durch den RTF Parser und fuer die EditShell. + */ +void SwDoc::ChgDBData(const SwDBData& rNewData) +{ + if( rNewData != aDBData ) + { + aDBData = rNewData; + SetModified(); + } + GetSysFldType(RES_DBNAMEFLD)->UpdateFlds(); +} + +bool SwDoc::SplitNode( const SwPosition &rPos, bool bChkTableStart ) +{ + SwCntntNode *pNode = rPos.nNode.GetNode().GetCntntNode(); + if(0 == pNode) + return false; + + { + // 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( this, rPos, 0 ); + } + + SwUndoSplitNode* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + // einfuegen vom Undo-Object, z.Z. nur beim TextNode + if( pNode->IsTxtNode() ) + { + pUndo = new SwUndoSplitNode( this, rPos, bChkTableStart ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + + //JP 28.01.97: Sonderfall fuer SplitNode am Tabellenanfang: + // steht die am Doc/Fly/Footer/..-Anfang oder direkt + // hinter einer Tabelle, dann fuege davor + // einen Absatz ein + if( bChkTableStart && !rPos.nContent.GetIndex() && pNode->IsTxtNode() ) + { + sal_uLong nPrevPos = rPos.nNode.GetIndex() - 1; + const SwTableNode* pTblNd; + const SwNode* pNd = GetNodes()[ nPrevPos ]; + if( pNd->IsStartNode() && + SwTableBoxStartNode == ((SwStartNode*)pNd)->GetStartNodeType() && + 0 != ( pTblNd = GetNodes()[ --nPrevPos ]->GetTableNode() ) && + ((( pNd = GetNodes()[ --nPrevPos ])->IsStartNode() && + SwTableBoxStartNode != ((SwStartNode*)pNd)->GetStartNodeType() ) + || ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() ) + || pNd->IsCntntNode() )) + { + if( pNd->IsCntntNode() ) + { + //JP 30.04.99 Bug 65660: + // ausserhalb des normalen BodyBereiches gibt es keine + // Seitenumbrueche, also ist das hier kein gueltige + // Bedingung fuers einfuegen eines Absatzes + if( nPrevPos < GetNodes().GetEndOfExtras().GetIndex() ) + pNd = 0; + else + { + // Dann nur, wenn die Tabelle Umbrueche traegt! + const SwFrmFmt* pFrmFmt = pTblNd->GetTable().GetFrmFmt(); + if( SFX_ITEM_SET != pFrmFmt->GetItemState(RES_PAGEDESC, sal_False) && + SFX_ITEM_SET != pFrmFmt->GetItemState( RES_BREAK, sal_False ) ) + pNd = 0; + } + } + + if( pNd ) + { + SwTxtNode* pTxtNd = GetNodes().MakeTxtNode( + SwNodeIndex( *pTblNd ), + GetTxtCollFromPool( RES_POOLCOLL_TEXT )); + if( pTxtNd ) + { + ((SwPosition&)rPos).nNode = pTblNd->GetIndex()-1; + ((SwPosition&)rPos).nContent.Assign( pTxtNd, 0 ); + + // nur im BodyBereich den SeitenUmbruch/-Vorlage umhaengem + if( nPrevPos > GetNodes().GetEndOfExtras().GetIndex() ) + { + SwFrmFmt* pFrmFmt = pTblNd->GetTable().GetFrmFmt(); + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pFrmFmt->GetItemState( RES_PAGEDESC, + sal_False, &pItem ) ) + { + pTxtNd->SetAttr( *pItem ); + pFrmFmt->ResetFmtAttr( RES_PAGEDESC ); + } + if( SFX_ITEM_SET == pFrmFmt->GetItemState( RES_BREAK, + sal_False, &pItem ) ) + { + pTxtNd->SetAttr( *pItem ); + pFrmFmt->ResetFmtAttr( RES_BREAK ); + } + } + + if( pUndo ) + pUndo->SetTblFlag(); + SetModified(); + return true; + } + } + } + } + + SvULongs aBkmkArr( 15, 15 ); + _SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), + aBkmkArr, SAVEFLY_SPLIT ); + // FIXME: only SwTxtNode has a valid implementation of SplitCntntNode! + ASSERT(pNode->IsTxtNode(), "splitting non-text node?"); + pNode = pNode->SplitCntntNode( rPos ); + if (pNode) + { + // verschiebe noch alle Bookmarks/TOXMarks/FlyAtCnt + if( aBkmkArr.Count() ) + _RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True ); + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + SwPaM aPam( rPos ); + aPam.SetMark(); + aPam.Move( fnMoveBackward ); + if( IsRedlineOn() ) + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + else + SplitRedline( aPam ); + } + } + + SetModified(); + return true; +} + +bool SwDoc::AppendTxtNode( SwPosition& rPos ) +{ + // create new node before EndOfContent + SwTxtNode * pCurNode = rPos.nNode.GetNode().GetTxtNode(); + if( !pCurNode ) + { + // dann kann ja einer angelegt werden! + SwNodeIndex aIdx( rPos.nNode, 1 ); + pCurNode = GetNodes().MakeTxtNode( aIdx, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); + } + else + pCurNode = (SwTxtNode*)pCurNode->AppendNode( rPos ); + + rPos.nNode++; + rPos.nContent.Assign( pCurNode, 0 ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoInsert( rPos.nNode ) ); + } + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + SwPaM aPam( rPos ); + aPam.SetMark(); + aPam.Move( fnMoveBackward ); + if( IsRedlineOn() ) + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + else + SplitRedline( aPam ); + } + + SetModified(); + return sal_True; +} + +bool SwDoc::InsertString( const SwPaM &rRg, const String &rStr, + const enum InsertFlags nInsertMode ) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called! + } + + const SwPosition& rPos = *rRg.GetPoint(); + + if( pACEWord ) // Aufnahme in die Autokorrektur + { + if( 1 == rStr.Len() && pACEWord->IsDeleted() ) + { + pACEWord->CheckChar( rPos, rStr.GetChar( 0 ) ); + } + delete pACEWord, pACEWord = 0; + } + + SwTxtNode *const pNode = rPos.nNode.GetNode().GetTxtNode(); + if(!pNode) + { + return false; + } + + SwDataChanged aTmp( rRg, 0 ); + + if (!GetIDocumentUndoRedo().DoesUndo() || + !GetIDocumentUndoRedo().DoesGroupUndo()) + { + pNode->InsertText( rStr, rPos.nContent, nInsertMode ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoInsert * const pUndo( new SwUndoInsert( + rPos.nNode, rPos.nContent.GetIndex(), rStr.Len(), nInsertMode)); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + else + { // ist Undo und Gruppierung eingeschaltet, ist alles anders ! + SwUndoInsert * pUndo = NULL; // #111827# + + // don't group the start if hints at the start should be expanded + if (!(nInsertMode & IDocumentContentOperations::INS_FORCEHINTEXPAND)) + // -> #111827# + { + SwUndo *const pLastUndo = GetUndoManager().GetLastUndo(); + SwUndoInsert *const pUndoInsert( + dynamic_cast<SwUndoInsert *>(pLastUndo) ); + if (pUndoInsert && pUndoInsert->CanGrouping(rPos)) + { + pUndo = pUndoInsert; + } + } + // <- #111827# + + CharClass const& rCC = GetAppCharClass(); + xub_StrLen nInsPos = rPos.nContent.GetIndex(); + + if (!pUndo) + { + pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 0, nInsertMode, + !rCC.isLetterNumeric( rStr, 0 ) ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + + pNode->InsertText( rStr, rPos.nContent, nInsertMode ); + + for( xub_StrLen i = 0; i < rStr.Len(); ++i ) + { + nInsPos++; + // wenn CanGrouping() sal_True returnt, ist schon alles erledigt + if( !pUndo->CanGrouping( rStr.GetChar( i ) )) + { + pUndo = new SwUndoInsert( rPos.nNode, nInsPos, 1, nInsertMode, + !rCC.isLetterNumeric( rStr, i ) ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + } + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + SwPaM aPam( rPos.nNode, aTmp.GetCntnt(), + rPos.nNode, rPos.nContent.GetIndex()); + if( IsRedlineOn() ) + { + AppendRedline( + new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + } + else + { + SplitRedline( aPam ); + } + } + + SetModified(); + return true; +} + +SwFlyFrmFmt* SwDoc::_InsNoTxtNode( const SwPosition& rPos, SwNoTxtNode* pNode, + const SfxItemSet* pFlyAttrSet, + const SfxItemSet* pGrfAttrSet, + SwFrmFmt* pFrmFmt) +{ + SwFlyFrmFmt *pFmt = 0; + if( pNode ) + { + pFmt = _MakeFlySection( rPos, *pNode, FLY_AT_PARA, + pFlyAttrSet, pFrmFmt ); + if( pGrfAttrSet ) + pNode->SetAttr( *pGrfAttrSet ); + } + return pFmt; +} + +SwFlyFrmFmt* SwDoc::Insert( const SwPaM &rRg, + const String& rGrfName, + const String& rFltName, + const Graphic* pGraphic, + const SfxItemSet* pFlyAttrSet, + const SfxItemSet* pGrfAttrSet, + SwFrmFmt* pFrmFmt ) +{ + if( !pFrmFmt ) + pFrmFmt = GetFrmFmtFromPool( RES_POOLFRM_GRAPHIC ); + return _InsNoTxtNode( *rRg.GetPoint(), GetNodes().MakeGrfNode( + SwNodeIndex( GetNodes().GetEndOfAutotext() ), + rGrfName, rFltName, pGraphic, + pDfltGrfFmtColl ), + pFlyAttrSet, pGrfAttrSet, pFrmFmt ); +} +SwFlyFrmFmt* SwDoc::Insert( const SwPaM &rRg, const GraphicObject& rGrfObj, + const SfxItemSet* pFlyAttrSet, + const SfxItemSet* pGrfAttrSet, + SwFrmFmt* pFrmFmt ) +{ + if( !pFrmFmt ) + pFrmFmt = GetFrmFmtFromPool( RES_POOLFRM_GRAPHIC ); + return _InsNoTxtNode( *rRg.GetPoint(), GetNodes().MakeGrfNode( + SwNodeIndex( GetNodes().GetEndOfAutotext() ), + rGrfObj, pDfltGrfFmtColl ), + pFlyAttrSet, pGrfAttrSet, pFrmFmt ); +} + +SwFlyFrmFmt* SwDoc::Insert(const SwPaM &rRg, const svt::EmbeddedObjectRef& xObj, + const SfxItemSet* pFlyAttrSet, + const SfxItemSet* pGrfAttrSet, + SwFrmFmt* pFrmFmt ) +{ + if( !pFrmFmt ) + { + sal_uInt16 nId = RES_POOLFRM_OLE; + SvGlobalName aClassName( xObj->getClassID() ); + if (SotExchange::IsMath(aClassName)) + nId = RES_POOLFRM_FORMEL; + + pFrmFmt = GetFrmFmtFromPool( nId ); + } + return _InsNoTxtNode( *rRg.GetPoint(), GetNodes().MakeOLENode( + SwNodeIndex( GetNodes().GetEndOfAutotext() ), + xObj, + pDfltGrfFmtColl ), + pFlyAttrSet, pGrfAttrSet, + pFrmFmt ); +} + +SwFlyFrmFmt* SwDoc::InsertOLE(const SwPaM &rRg, const String& rObjName, + sal_Int64 nAspect, + const SfxItemSet* pFlyAttrSet, + const SfxItemSet* pGrfAttrSet, + SwFrmFmt* pFrmFmt ) +{ + if( !pFrmFmt ) + pFrmFmt = GetFrmFmtFromPool( RES_POOLFRM_OLE ); + + return _InsNoTxtNode( *rRg.GetPoint(), + GetNodes().MakeOLENode( + SwNodeIndex( GetNodes().GetEndOfAutotext() ), + rObjName, + nAspect, + pDfltGrfFmtColl, + 0 ), + pFlyAttrSet, pGrfAttrSet, + pFrmFmt ); +} + +/************************************************************************* +|* SwDoc::GetFldType() +|* Beschreibung: liefert den am Doc eingerichteten Feldtypen zurueck +*************************************************************************/ + +SwFieldType *SwDoc::GetSysFldType( const sal_uInt16 eWhich ) const +{ + for( sal_uInt16 i = 0; i < INIT_FLDTYPES; ++i ) + if( eWhich == (*pFldTypes)[i]->Which() ) + return (*pFldTypes)[i]; + return 0; +} +/************************************************************************* + * void SetDocStat( const SwDocStat& rStat ); + *************************************************************************/ + +void SwDoc::SetDocStat( const SwDocStat& rStat ) +{ + *pDocStat = rStat; +} + +const SwDocStat& SwDoc::GetDocStat() const +{ + return *pDocStat; +} + +/*************************************************************************/ + + +struct _PostItFld : public _SetGetExpFld +{ + _PostItFld( const SwNodeIndex& rNdIdx, const SwTxtFld* pFld, const SwIndex* pIdx = 0 ) + : _SetGetExpFld( rNdIdx, pFld, pIdx ) {} + + sal_uInt16 GetPageNo( const StringRangeEnumerator &rRangeEnum, + const std::set< sal_Int32 > &rPossiblePages, + sal_uInt16& rVirtPgNo, sal_uInt16& rLineNo ); + + SwPostItField* GetPostIt() const + { + return (SwPostItField*) GetFld()->GetFld().GetFld(); + } +}; + + +sal_uInt16 _PostItFld::GetPageNo( + const StringRangeEnumerator &rRangeEnum, + const std::set< sal_Int32 > &rPossiblePages, + /* out */ sal_uInt16& rVirtPgNo, /* out */ sal_uInt16& rLineNo ) +{ + //Problem: Wenn ein PostItFld in einem Node steht, der von mehr als + //einer Layout-Instanz repraesentiert wird, steht die Frage im Raum, + //ob das PostIt nur ein- oder n-mal gedruck werden soll. + //Wahrscheinlich nur einmal, als Seitennummer soll hier keine Zufaellige + //sondern die des ersten Auftretens des PostIts innerhalb des selektierten + //Bereichs ermittelt werden. + rVirtPgNo = 0; + sal_uInt16 nPos = GetCntnt(); + SwClientIter aIter( (SwModify &)GetFld()->GetTxtNode() ); + for( SwTxtFrm* pFrm = (SwTxtFrm*)aIter.First( TYPE( SwFrm )); + pFrm; pFrm = (SwTxtFrm*)aIter.Next() ) + { + if( pFrm->GetOfst() > nPos || + (pFrm->HasFollow() && pFrm->GetFollow()->GetOfst() <= nPos) ) + continue; + sal_uInt16 nPgNo = pFrm->GetPhyPageNum(); + if( rRangeEnum.hasValue( nPgNo, &rPossiblePages )) + { + rLineNo = (sal_uInt16)(pFrm->GetLineCount( nPos ) + + pFrm->GetAllLines() - pFrm->GetThisLines()); + rVirtPgNo = pFrm->GetVirtPageNum(); + return nPgNo; + } + } + return 0; +} + + +bool lcl_GetPostIts( + IDocumentFieldsAccess* pIDFA, + _SetGetExpFlds * pSrtLst ) +{ + bool bHasPostIts = false; + + SwFieldType* pFldType = pIDFA->GetSysFldType( RES_POSTITFLD ); + DBG_ASSERT( pFldType, "kein PostItType ? "); + + if( pFldType->GetDepends() ) + { + // Modify-Object gefunden, trage alle Felder ins Array ein + SwClientIter aIter( *pFldType ); + SwClient* pLast; + const SwTxtFld* pTxtFld; + + for( pLast = aIter.First( TYPE(SwFmtFld)); pLast; pLast = aIter.Next() ) + { + if( 0 != ( pTxtFld = ((SwFmtFld*)pLast)->GetTxtFld() ) && + pTxtFld->GetTxtNode().GetNodes().IsDocNodes() ) + { + bHasPostIts = true; + if (pSrtLst) + { + SwNodeIndex aIdx( pTxtFld->GetTxtNode() ); + _PostItFld* pNew = new _PostItFld( aIdx, pTxtFld ); + pSrtLst->Insert( pNew ); + } + else + break; // we just wanted to check for the existence of postits ... + } + } + } + + return bHasPostIts; +} + + +static void lcl_FormatPostIt( + IDocumentContentOperations* pIDCO, + SwPaM& aPam, + SwPostItField* pField, + bool bNewPage, bool bIsFirstPostIt, + sal_uInt16 nPageNo, sal_uInt16 nLineNo ) +{ + static char __READONLY_DATA sTmp[] = " : "; + + DBG_ASSERT( ViewShell::GetShellRes(), "missing ShellRes" ); + + if (bNewPage) + { + pIDCO->InsertPoolItem( aPam, SvxFmtBreakItem( SVX_BREAK_PAGE_AFTER, RES_BREAK ), 0 ); + pIDCO->SplitNode( *aPam.GetPoint(), false ); + } + else if (!bIsFirstPostIt) + { + // add an empty line between different notes + pIDCO->SplitNode( *aPam.GetPoint(), false ); + pIDCO->SplitNode( *aPam.GetPoint(), false ); + } + + String aStr( ViewShell::GetShellRes()->aPostItPage ); + aStr.AppendAscii(sTmp); + + aStr += XubString::CreateFromInt32( nPageNo ); + aStr += ' '; + if( nLineNo ) + { + aStr += ViewShell::GetShellRes()->aPostItLine; + aStr.AppendAscii(sTmp); + aStr += XubString::CreateFromInt32( nLineNo ); + aStr += ' '; + } + aStr += ViewShell::GetShellRes()->aPostItAuthor; + aStr.AppendAscii(sTmp); + aStr += pField->GetPar1(); + aStr += ' '; + SvtSysLocale aSysLocale; + aStr += /*(LocaleDataWrapper&)*/aSysLocale.GetLocaleData().getDate( pField->GetDate() ); + pIDCO->InsertString( aPam, aStr ); + + pIDCO->SplitNode( *aPam.GetPoint(), false ); + aStr = pField->GetPar2(); +#if defined( WNT ) || defined( PM2 ) + // Bei Windows und Co alle CR rausschmeissen + aStr.EraseAllChars( '\r' ); +#endif + pIDCO->InsertString( aPam, aStr ); +} + + +// provide the paper tray to use according to the page style in use, +// but do that only if the respective item is NOT just the default item +static sal_Int32 lcl_GetPaperBin( const SwPageFrm *pStartFrm ) +{ + sal_Int32 nRes = -1; + + const SwFrmFmt &rFmt = pStartFrm->GetPageDesc()->GetMaster(); + const SfxPoolItem *pItem = NULL; + SfxItemState eState = rFmt.GetItemState( RES_PAPER_BIN, sal_False, &pItem ); + const SvxPaperBinItem *pPaperBinItem = dynamic_cast< const SvxPaperBinItem * >(pItem); + if (eState > SFX_ITEM_DEFAULT && pPaperBinItem) + nRes = pPaperBinItem->GetValue(); + + return nRes; +} + + +void SwDoc::CalculatePagesForPrinting( + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + bool bIsPDFExport, + sal_Int32 nDocPageCount ) +{ + DBG_ASSERT( pLayout, "no layout present" ); + if (!pLayout) + return; + + const sal_Int32 nContent = rOptions.getIntValue( "PrintContent", 0 ); + const bool bPrintSelection = nContent == 2; + + // properties to take into account when calcualting the set of pages + // (PDF export UI does not allow for selecting left or right pages only) + bool bPrintLeftPages = bIsPDFExport ? true : rOptions.IsPrintLeftPages(); + bool bPrintRightPages = bIsPDFExport ? true : rOptions.IsPrintRightPages(); + // #i103700# printing selections should not allow for automatic inserting empty pages + bool bPrintEmptyPages = bPrintSelection ? false : rOptions.IsPrintEmptyPages( bIsPDFExport ); + + Range aPages( 1, nDocPageCount ); + + MultiSelection aMulti( aPages ); + aMulti.SetTotalRange( Range( 0, RANGE_MAX ) ); + aMulti.Select( aPages ); + + const SwPageFrm *pStPage = (SwPageFrm*)pLayout->Lower(); + const SwFrm *pEndPage = pStPage; + + sal_uInt16 nFirstPageNo = 0; + sal_uInt16 nLastPageNo = 0; + sal_uInt16 nPageNo = 1; + + for( sal_uInt16 i = 1; i <= (sal_uInt16)aPages.Max(); ++i ) + { + if( i < (sal_uInt16)aPages.Min() ) + { + if( !pStPage->GetNext() ) + break; + pStPage = (SwPageFrm*)pStPage->GetNext(); + pEndPage= pStPage; + } + else if( i == (sal_uInt16)aPages.Min() ) + { + nFirstPageNo = i; + nLastPageNo = nFirstPageNo; + if( !pStPage->GetNext() || (i == (sal_uInt16)aPages.Max()) ) + break; + pEndPage = pStPage->GetNext(); + } + else if( i > (sal_uInt16)aPages.Min() ) + { + nLastPageNo = i; + if( !pEndPage->GetNext() || (i == (sal_uInt16)aPages.Max()) ) + break; + pEndPage = pEndPage->GetNext(); + } + } + + DBG_ASSERT( nFirstPageNo, "first page not found! Should not happen!" ); + if (nFirstPageNo) + { +// HACK: Hier muss von der MultiSelection noch eine akzeptable Moeglichkeit +// geschaffen werden, alle Seiten von Seite x an zu deselektieren. +// Z.B. durch SetTotalRange .... + +// aMulti.Select( Range( nLastPageNo+1, SELECTION_MAX ), sal_False ); + MultiSelection aTmpMulti( Range( 1, nLastPageNo ) ); + long nTmpIdx = aMulti.FirstSelected(); + static long nEndOfSelection = SFX_ENDOFSELECTION; + while ( nEndOfSelection != nTmpIdx && nTmpIdx <= long(nLastPageNo) ) + { + aTmpMulti.Select( nTmpIdx ); + nTmpIdx = aMulti.NextSelected(); + } + aMulti = aTmpMulti; +// Ende des HACKs + + nPageNo = nFirstPageNo; + + std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays(); + std::set< sal_Int32 > &rValidPages = rData.GetValidPagesSet(); + std::map< sal_Int32, const SwPageFrm * > &rValidStartFrms = rData.GetValidStartFrames(); + rValidPages.clear(); + rValidStartFrms.clear(); + while ( pStPage ) + { + const sal_Bool bRightPg = pStPage->OnRightPage(); + if ( aMulti.IsSelected( nPageNo ) && + ( (bRightPg && bPrintRightPages) || + (!bRightPg && bPrintLeftPages) ) ) + { + // --> FME 2005-12-12 #b6354161# Feature - Print empty pages + if ( bPrintEmptyPages || pStPage->Frm().Height() ) + // <-- + { + rValidPages.insert( nPageNo ); + rValidStartFrms[ nPageNo ] = pStPage; + + rPrinterPaperTrays[ nPageNo ] = lcl_GetPaperBin( pStPage ); + } + } + + if ( pStPage == pEndPage ) + { + pStPage = 0; + } + else + { ++nPageNo; + pStPage = (SwPageFrm*)pStPage->GetNext(); + } + } + } + + + // + // now that we have identified the valid pages for printing according + // to the print settings we need to get the PageRange to use and + // use both results to get the actual pages to be printed + // (post-it settings need to be taken into account later on!) + // + + // get PageRange value to use + OUString aPageRange; + // --> PL, OD #i116085# - adjusting fix for i113919 +// if (bIsPDFExport) +// { +// aPageRange = rOptions.getStringValue( "PageRange", OUString() ); +// } +// else + if ( !bIsPDFExport ) + // <-- + { + // PageContent : + // 0 -> print all pages (default if aPageRange is empty) + // 1 -> print range according to PageRange + // 2 -> print selection + if (1 == nContent) + aPageRange = rOptions.getStringValue( "PageRange", OUString() ); + if (2 == nContent) + { + // note that printing selections is actually implemented by copying + // the selection to a new temporary document and printing all of that one. + // Thus for Writer "PrintContent" must never be 2. + // See SwXTextDocument::GetRenderDoc for evaluating if a selection is to be + // printed and for creating the temporary document. + } + + // please note + } + if (aPageRange.getLength() == 0) // empty string -> print all + { + // set page range to print to 'all pages' + aPageRange = OUString::valueOf( (sal_Int32)1 ); + aPageRange += OUString::valueOf( (sal_Unicode)'-'); + aPageRange += OUString::valueOf( nDocPageCount ); + } + rData.SetPageRange( aPageRange ); + + // get vector of pages to print according to PageRange and valid pages set from above + // (result may be an empty vector, for example if the range string is not correct) + StringRangeEnumerator::getRangesFromString( + aPageRange, rData.GetPagesToPrint(), + 1, nDocPageCount, 0, &rData.GetValidPagesSet() ); +} + + +void SwDoc::UpdatePagesForPrintingWithPostItData( + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + bool /*bIsPDFExport*/, + sal_Int32 nDocPageCount ) +{ + + sal_Int16 nPostItMode = (sal_Int16) rOptions.getIntValue( "PrintAnnotationMode", 0 ); + DBG_ASSERT(nPostItMode == POSTITS_NONE || rData.HasPostItData(), + "print post-its without post-it data?" ); + const sal_uInt16 nPostItCount = rData.HasPostItData() ? rData.m_pPostItFields->Count() : 0; + if (nPostItMode != POSTITS_NONE && nPostItCount > 0) + { + SET_CURR_SHELL( rData.m_pPostItShell ); + + // clear document and move to end of it + SwPaM aPam( rData.m_pPostItDoc->GetNodes().GetEndOfContent() ); + aPam.Move( fnMoveBackward, fnGoDoc ); + aPam.SetMark(); + aPam.Move( fnMoveForward, fnGoDoc ); + rData.m_pPostItDoc->DeleteRange( aPam ); + + const StringRangeEnumerator aRangeEnum( rData.GetPageRange(), 1, nDocPageCount, 0 ); + + // For mode POSTITS_ENDPAGE: + // maps a physical page number to the page number in post-it document that holds + // the first post-it for that physical page . Needed to relate the correct start frames + // from the post-it doc to the physical page of the document + std::map< sal_Int32, sal_Int32 > aPostItLastStartPageNum; + + // add all post-its on valid pages within the the page range to the + // temporary post-it document. + // Since the array of post-it fileds is sorted by page and line number we will + // already get them in the correct order + sal_uInt16 nVirtPg = 0, nLineNo = 0, nLastPageNum = 0, nPhyPageNum = 0; + bool bIsFirstPostIt = true; + for (sal_uInt16 i = 0; i < nPostItCount; ++i) + { + _PostItFld& rPostIt = (_PostItFld&)*(*rData.m_pPostItFields)[ i ]; + nLastPageNum = nPhyPageNum; + nPhyPageNum = rPostIt.GetPageNo( + aRangeEnum, rData.GetValidPagesSet(), nVirtPg, nLineNo ); + if (nPhyPageNum) + { + // need to insert a page break? + // In POSTITS_ENDPAGE mode for each document page the following + // post-it page needs to start on a new page + const bool bNewPage = nPostItMode == POSTITS_ENDPAGE && + !bIsFirstPostIt && nPhyPageNum != nLastPageNum; + + lcl_FormatPostIt( rData.m_pPostItShell->GetDoc(), aPam, + rPostIt.GetPostIt(), bNewPage, bIsFirstPostIt, nVirtPg, nLineNo ); + bIsFirstPostIt = false; + + if (nPostItMode == POSTITS_ENDPAGE) + { + // get the correct number of current pages for the post-it document + rData.m_pPostItShell->CalcLayout(); + const sal_Int32 nPages = rData.m_pPostItDoc->GetPageCount(); + aPostItLastStartPageNum[ nPhyPageNum ] = nPages; + } + } + } + + // format post-it doc to get correct number of pages + rData.m_pPostItShell->CalcLayout(); + const sal_Int32 nPostItDocPageCount = rData.m_pPostItDoc->GetPageCount(); + + if (nPostItMode == POSTITS_ONLY || nPostItMode == POSTITS_ENDDOC) + { + // now add those post-it pages to the vector of pages to print + // or replace them if only post-its should be printed + + rData.GetPostItStartFrames().clear(); + if (nPostItMode == POSTITS_ENDDOC) + { + // set all values up to number of pages to print currently known to NULL, + // meaning none of the pages currently in the vector is from the + // post-it document, they are the documents pages. + rData.GetPostItStartFrames().resize( rData.GetPagesToPrint().size() ); + } + else if (nPostItMode == POSTITS_ONLY) + { + // no document page to be printed + rData.GetPagesToPrint().clear(); + } + + // now we just need to add the post-it pages to be printed to the end + // of the vector of pages to print and keep the GetValidStartFrames + // data conform with it + sal_Int32 nPageNum = 0; + const SwPageFrm * pPageFrm = (SwPageFrm*)rData.m_pPostItShell->GetLayout()->Lower(); + while( pPageFrm && nPageNum < nPostItDocPageCount ) + { + DBG_ASSERT( pPageFrm, "Empty page frame. How are we going to print this?" ); + ++nPageNum; + rData.GetPagesToPrint().push_back( 0 ); // a page number of 0 indicates this page is from the post-it doc + DBG_ASSERT( pPageFrm, "pPageFrm is NULL!" ); + rData.GetPostItStartFrames().push_back( pPageFrm ); + pPageFrm = (SwPageFrm*)pPageFrm->GetNext(); + } + DBG_ASSERT( nPageNum == nPostItDocPageCount, "unexpected number of pages" ); + } + else if (nPostItMode == POSTITS_ENDPAGE) + { + // the next step is to find all the start frames from the post-it + // document that should be printed for a given physical page of the document + std::map< sal_Int32, std::vector< const SwPageFrm * > > aPhysPageToPostItFrames; + + // ... thus, first collect all post-it doc start frames in a vector + sal_Int32 nPostItPageNum = 0; + std::vector< const SwPageFrm * > aAllPostItStartFrames; + const SwPageFrm * pPageFrm = (SwPageFrm*)rData.m_pPostItShell->GetLayout()->Lower(); + while( pPageFrm && sal_Int32(aAllPostItStartFrames.size()) < nPostItDocPageCount ) + { + DBG_ASSERT( pPageFrm, "Empty page frame. How are we going to print this?" ); + ++nPostItPageNum; + aAllPostItStartFrames.push_back( pPageFrm ); + pPageFrm = (SwPageFrm*)pPageFrm->GetNext(); + } + DBG_ASSERT( sal_Int32(aAllPostItStartFrames.size()) == nPostItDocPageCount, + "unexpected number of frames; does not match number of pages" ); + + // get a map that holds all post-it frames to be printed for a + // given physical page from the document + sal_Int32 nLastStartPageNum = 0; + std::map< sal_Int32, sal_Int32 >::const_iterator aIt; + for (aIt = aPostItLastStartPageNum.begin(); aIt != aPostItLastStartPageNum.end(); ++aIt) + { + const sal_Int32 nFrames = aIt->second - nLastStartPageNum; + const sal_Int32 nFirstStartPageNum = aIt == aPostItLastStartPageNum.begin() ? + 1 : aIt->second - nFrames + 1; + DBG_ASSERT( 1 <= nFirstStartPageNum && nFirstStartPageNum <= nPostItDocPageCount, + "page number for first frame out of range" ); + std::vector< const SwPageFrm * > aStartFrames; + for (sal_Int32 i = 0; i < nFrames; ++i) + { + const sal_Int32 nIdx = nFirstStartPageNum - 1 + i; // -1 because lowest page num is 1 + DBG_ASSERT( 0 <= nIdx && nIdx < sal_Int32(aAllPostItStartFrames.size()), + "index out of range" ); + aStartFrames.push_back( aAllPostItStartFrames[ nIdx ] ); + } + aPhysPageToPostItFrames[ aIt->first /* phys page num */ ] = aStartFrames; + nLastStartPageNum = aIt->second; + } + + + // ok, now that aPhysPageToPostItFrames can give the start frames for all + // post-it pages to be printed we need to merge those at the correct + // position into the GetPagesToPrint vector and build and maintain the + // GetValidStartFrames vector as well. + // Since inserting a larger number of entries in the middle of a vector + // isn't that efficient we will create new vectors by copying the required data + std::vector< sal_Int32 > aTmpPagesToPrint; + std::vector< const SwPageFrm * > aTmpPostItStartFrames; + const size_t nNum = rData.GetPagesToPrint().size(); + for (size_t i = 0 ; i < nNum; ++i) + { + // add the physical page to print from the document + const sal_Int32 nPhysPage = rData.GetPagesToPrint()[i]; + aTmpPagesToPrint.push_back( nPhysPage ); + aTmpPostItStartFrames.push_back( NULL ); + + // add the post-it document pages to print, i.e those + // post-it pages that have the data for the above physical page + const std::vector< const SwPageFrm * > &rPostItFrames = aPhysPageToPostItFrames[ nPhysPage ]; + const size_t nPostItFrames = rPostItFrames.size(); + for (size_t k = 0; k < nPostItFrames; ++k) + { + aTmpPagesToPrint.push_back( 0 ); + aTmpPostItStartFrames.push_back( rPostItFrames[k] ); + } + } + + // finally we need to assign those vectors to the resulting ones. + // swapping the data should be more efficient than assigning since + // we won't need the temporary vectors anymore + rData.GetPagesToPrint().swap( aTmpPagesToPrint ); + rData.GetPostItStartFrames().swap( aTmpPostItStartFrames ); + } + } +} + + +void SwDoc::CalculatePagePairsForProspectPrinting( + /* out */ SwRenderData &rData, + const SwPrintUIOptions &rOptions, + sal_Int32 nDocPageCount ) +{ + std::map< sal_Int32, sal_Int32 > &rPrinterPaperTrays = rData.GetPrinterPaperTrays(); + std::set< sal_Int32 > &rValidPagesSet = rData.GetValidPagesSet(); + std::map< sal_Int32, const SwPageFrm * > &rValidStartFrms = rData.GetValidStartFrames(); + std::vector< std::pair< sal_Int32, sal_Int32 > > &rPagePairs = rData.GetPagePairsForProspectPrinting(); + + rPagePairs.clear(); + rValidPagesSet.clear(); + rValidStartFrms.clear(); + + rtl::OUString aPageRange = rOptions.getStringValue( "PageRange", rtl::OUString() ); + // PageContent : + // 0 -> print all pages (default if aPageRange is empty) + // 1 -> print range according to PageRange + // 2 -> print selection + const sal_Int32 nContent = rOptions.getIntValue( "PrintContent", 0 ); + if (0 == nContent) + { + // set page range to print to 'all pages' + aPageRange = OUString::valueOf( (sal_Int32)1 ); + aPageRange += OUString::valueOf( (sal_Unicode)'-'); + aPageRange += OUString::valueOf( nDocPageCount ); + } + StringRangeEnumerator aRange( aPageRange, 1, nDocPageCount, 0 ); + + DBG_ASSERT( pLayout, "no layout present" ); + if (!pLayout || aRange.size() <= 0) + return; + + const SwPageFrm *pStPage = (SwPageFrm*)pLayout->Lower(); + sal_Int32 i = 0; + for ( i = 1; pStPage && i < nDocPageCount; ++i ) + pStPage = (SwPageFrm*)pStPage->GetNext(); + if ( !pStPage ) // dann wars das + return; + + // currently for prospect printing all pages are valid to be printed + // thus we add them all to the respective map and set for later use + sal_Int32 nPageNum = 0; + const SwPageFrm *pPageFrm = (SwPageFrm*)pLayout->Lower(); + while( pPageFrm && nPageNum < nDocPageCount ) + { + DBG_ASSERT( pPageFrm, "Empty page frame. How are we going to print this?" ); + ++nPageNum; + rValidPagesSet.insert( nPageNum ); + rValidStartFrms[ nPageNum ] = pPageFrm; + pPageFrm = (SwPageFrm*)pPageFrm->GetNext(); + + rPrinterPaperTrays[ nPageNum ] = lcl_GetPaperBin( pStPage ); + } + DBG_ASSERT( nPageNum == nDocPageCount, "unexpected number of pages" ); + + // properties to take into account when calcualting the set of pages + // Note: here bPrintLeftPages and bPrintRightPages refer to the (virtual) resulting pages + // of the prospect! + bool bPrintLeftPages = rOptions.IsPrintLeftPages(); + bool bPrintRightPages = rOptions.IsPrintRightPages(); + bool bPrintProspectRTL = rOptions.getIntValue( "PrintProspectRTL", 0 ) ? true : false; + + // get pages for prospect printing according to the 'PageRange' + // (duplicates and any order allowed!) + std::vector< sal_Int32 > aPagesToPrint; + StringRangeEnumerator::getRangesFromString( + aPageRange, aPagesToPrint, 1, nDocPageCount, 0 ); + + // now fill the vector for calculating the page pairs with the start frames + // from the above obtained vector + std::vector< const SwPageFrm * > aVec; + for ( i = 0; i < sal_Int32(aPagesToPrint.size()); ++i) + { + const sal_Int32 nPage = aPagesToPrint[i]; + const SwPageFrm *pFrm = rValidStartFrms[ nPage ]; + aVec.push_back( pFrm ); + } + + // just one page is special ... + if ( 1 == aVec.size() ) + aVec.insert( aVec.begin() + 1, 0 ); // insert a second empty page + else + { + // now extend the number of pages to fit a multiple of 4 + // (4 'normal' pages are needed for a single prospect paper + // with back and front) + while( aVec.size() & 3 ) + aVec.push_back( 0 ); + } + + // dann sorge mal dafuer, das alle Seiten in der richtigen + // Reihenfolge stehen: + sal_uInt16 nSPg = 0, nEPg = aVec.size(), nStep = 1; + if ( 0 == (nEPg & 1 )) // ungerade gibt es nicht! + --nEPg; + + if ( !bPrintLeftPages ) + ++nStep; + else if ( !bPrintRightPages ) + { + ++nStep; + ++nSPg, --nEPg; + } + + // the number of 'virtual' pages to be printed + sal_Int32 nCntPage = (( nEPg - nSPg ) / ( 2 * nStep )) + 1; + + for ( sal_uInt16 nPrintCount = 0; nSPg < nEPg && + nPrintCount < nCntPage; ++nPrintCount ) + { + pStPage = aVec[ nSPg ]; + const SwPageFrm* pNxtPage = nEPg < aVec.size() ? aVec[ nEPg ] : 0; + + short nRtlOfs = bPrintProspectRTL ? 1 : 0; + if ( 0 == (( nSPg + nRtlOfs) & 1 ) ) // switch for odd number in LTR, even number in RTL + { + const SwPageFrm* pTmp = pStPage; + pStPage = pNxtPage; + pNxtPage = pTmp; + } + + sal_Int32 nFirst = -1, nSecond = -1; + for ( int nC = 0; nC < 2; ++nC ) + { + sal_Int32 nPage = -1; + if ( pStPage ) + nPage = pStPage->GetPhyPageNum(); + if (nC == 0) + nFirst = nPage; + else + nSecond = nPage; + + pStPage = pNxtPage; + } + rPagePairs.push_back( std::pair< sal_Int32, sal_Int32 >(nFirst, nSecond) ); + + nSPg = nSPg + nStep; + nEPg = nEPg - nStep; + } + DBG_ASSERT( size_t(nCntPage) == rPagePairs.size(), "size mismatch for number of page pairs" ); + + // luckily prospect printing does not make use of post-its so far, + // thus we are done here. +} + + +sal_uInt16 SwDoc::GetPageCount() const +{ + return GetRootFrm() ? GetRootFrm()->GetPageNum() : 0; +} + +const Size SwDoc::GetPageSize( sal_uInt16 nPageNum, bool bSkipEmptyPages ) const +{ + Size aSize; + if ( GetRootFrm() && nPageNum ) + { + const SwPageFrm* pPage = static_cast<const SwPageFrm*> + (GetRootFrm()->Lower()); + + while ( --nPageNum && pPage->GetNext() ) + { + pPage = static_cast<const SwPageFrm*>( pPage->GetNext() ); + } + + // switch to next page for an empty page, if empty pages are not skipped + // in order to get a sensible page size for an empty page - e.g. for printing. + if ( !bSkipEmptyPages && pPage->IsEmptyPage() && pPage->GetNext() ) + { + pPage = static_cast<const SwPageFrm*>( pPage->GetNext() ); + } + + aSize = pPage->Frm().SSize(); + } + return aSize; +} + + +/************************************************************************* + * void UpdateDocStat( const SwDocStat& rStat ); + *************************************************************************/ + +void SwDoc::UpdateDocStat( SwDocStat& rStat ) +{ + if( rStat.bModified ) + { + rStat.Reset(); + rStat.nPara = 0; // Default ist auf 1 !! + SwNode* pNd; + + for( sal_uLong i = GetNodes().Count(); i; ) + { + switch( ( pNd = GetNodes()[ --i ])->GetNodeType() ) + { + case ND_TEXTNODE: + ((SwTxtNode*)pNd)->CountWords( rStat, 0, ((SwTxtNode*)pNd)->GetTxt().Len() ); + break; + case ND_TABLENODE: ++rStat.nTbl; break; + case ND_GRFNODE: ++rStat.nGrf; break; + case ND_OLENODE: ++rStat.nOLE; break; + case ND_SECTIONNODE: break; + } + } + + // #i93174#: notes contain paragraphs that are not nodes + { + SwFieldType * const pPostits( GetSysFldType(RES_POSTITFLD) ); + SwClientIter aIter(*pPostits); + SwFmtFld const * pFmtFld = + static_cast<SwFmtFld const*>(aIter.First( TYPE(SwFmtFld) )); + while (pFmtFld) + { + if (pFmtFld->IsFldInDoc()) + { + SwPostItField const * const pField( + static_cast<SwPostItField const*>(pFmtFld->GetFld())); + rStat.nAllPara += pField->GetNumberOfParagraphs(); + } + pFmtFld = static_cast<SwFmtFld const*>(aIter.Next()); + } + } + + rStat.nPage = GetRootFrm() ? GetRootFrm()->GetPageNum() : 0; + rStat.bModified = sal_False; + SetDocStat( rStat ); + + com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aStat( rStat.nPage ? 7 : 6); + sal_Int32 n=0; + aStat[n].Name = ::rtl::OUString::createFromAscii("TableCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nTbl; + aStat[n].Name = ::rtl::OUString::createFromAscii("ImageCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nGrf; + aStat[n].Name = ::rtl::OUString::createFromAscii("ObjectCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nOLE; + if ( rStat.nPage ) + { + aStat[n].Name = ::rtl::OUString::createFromAscii("PageCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nPage; + } + aStat[n].Name = ::rtl::OUString::createFromAscii("ParagraphCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nPara; + aStat[n].Name = ::rtl::OUString::createFromAscii("WordCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nWord; + aStat[n].Name = ::rtl::OUString::createFromAscii("CharacterCount"); + aStat[n++].Value <<= (sal_Int32)rStat.nChar; + + // For e.g. autotext documents there is no pSwgInfo (#i79945) + SfxObjectShell * const pObjShell( GetDocShell() ); + if (pObjShell) + { + const uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pObjShell->GetModel(), uno::UNO_QUERY_THROW); + const uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + // #i96786#: do not set modified flag when updating statistics + const bool bDocWasModified( IsModified() ); + const ModifyBlocker_Impl b(pObjShell); + xDocProps->setDocumentStatistics(aStat); + if (!bDocWasModified) + { + ResetModified(); + } + } + + // event. Stat. Felder Updaten + SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD); + pType->UpdateFlds(); + } +} + + +// Dokument - Info + +void SwDoc::DocInfoChgd( ) +{ + GetSysFldType( RES_DOCINFOFLD )->UpdateFlds(); + GetSysFldType( RES_TEMPLNAMEFLD )->UpdateFlds(); + SetModified(); +} + + // returne zum Namen die im Doc gesetzte Referenz +const SwFmtRefMark* SwDoc::GetRefMark( const String& rName ) const +{ + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_REFMARK ); + for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + { + if( 0 == (pItem = GetAttrPool().GetItem2( RES_TXTATR_REFMARK, n ) )) + continue; + + const SwFmtRefMark* pFmtRef = (SwFmtRefMark*)pItem; + const SwTxtRefMark* pTxtRef = pFmtRef->GetTxtRefMark(); + if( pTxtRef && &pTxtRef->GetTxtNode().GetNodes() == &GetNodes() && + rName.Equals( pFmtRef->GetRefName() ) ) + return pFmtRef; + } + return 0; +} + + // returne die RefMark per Index - fuer Uno +const SwFmtRefMark* SwDoc::GetRefMark( sal_uInt16 nIndex ) const +{ + const SfxPoolItem* pItem; + const SwTxtRefMark* pTxtRef; + const SwFmtRefMark* pRet = 0; + + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_REFMARK ); + sal_uInt32 nCount = 0; + for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = GetAttrPool().GetItem2( RES_TXTATR_REFMARK, n )) && + 0 != (pTxtRef = ((SwFmtRefMark*)pItem)->GetTxtRefMark()) && + &pTxtRef->GetTxtNode().GetNodes() == &GetNodes() ) + { + if(nCount == nIndex) + { + pRet = (SwFmtRefMark*)pItem; + break; + } + nCount++; + } + return pRet; +} + + // returne die Namen aller im Doc gesetzten Referenzen + //JP 24.06.96: Ist der ArrayPointer 0 dann returne nur, ob im Doc. eine + // RefMark gesetzt ist + // OS 25.06.96: ab jetzt wird immer die Anzahl der Referenzen returnt +sal_uInt16 SwDoc::GetRefMarks( SvStringsDtor* pNames ) const +{ + const SfxPoolItem* pItem; + const SwTxtRefMark* pTxtRef; + + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_REFMARK ); + sal_uInt32 nCount = 0; + for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = GetAttrPool().GetItem2( RES_TXTATR_REFMARK, n )) && + 0 != (pTxtRef = ((SwFmtRefMark*)pItem)->GetTxtRefMark()) && + &pTxtRef->GetTxtNode().GetNodes() == &GetNodes() ) + { + if( pNames ) + { + String* pTmp = new String( ((SwFmtRefMark*)pItem)->GetRefName() ); + pNames->Insert( pTmp, nCount ); + } + nCount ++; + } + + return nCount; +} + +bool SwDoc::IsLoaded() const +{ + return mbLoaded; +} + +bool SwDoc::IsUpdateExpFld() const +{ + return mbUpdateExpFld; +} + +bool SwDoc::IsNewDoc() const +{ + return mbNewDoc; +} + +bool SwDoc::IsPageNums() const +{ + return mbPageNums; +} + +void SwDoc::SetPageNums(bool b) +{ + mbPageNums = b; +} + +void SwDoc::SetNewDoc(bool b) +{ + mbNewDoc = b; +} + +void SwDoc::SetUpdateExpFldStat(bool b) +{ + mbUpdateExpFld = b; +} + +void SwDoc::SetLoaded(bool b) +{ + mbLoaded = b; +} + +bool SwDoc::IsModified() const +{ + return mbModified; +} + +void SwDoc::SetModified() +{ + // --> OD 2005-08-29 #125370# + SwLayouter::ClearMovedFwdFrms( *this ); + SwLayouter::ClearObjsTmpConsiderWrapInfluence( *this ); + SwLayouter::ClearFrmsNotToWrap( *this ); + // <-- + // --> OD 2006-05-10 #i65250# + SwLayouter::ClearMoveBwdLayoutInfo( *this ); + // <-- + // dem Link wird der Status returnt, wie die Flags waren und werden + // Bit 0: -> alter Zustand + // Bit 1: -> neuer Zustand + long nCall = mbModified ? 3 : 2; + mbModified = sal_True; + pDocStat->bModified = sal_True; + if( aOle2Link.IsSet() ) + { + mbInCallModified = sal_True; + aOle2Link.Call( (void*)nCall ); + mbInCallModified = sal_False; + } + + if( pACEWord && !pACEWord->IsDeleted() ) + delete pACEWord, pACEWord = 0; +} + +void SwDoc::ResetModified() +{ + // dem Link wird der Status returnt, wie die Flags waren und werden + // Bit 0: -> alter Zustand + // Bit 1: -> neuer Zustand + long nCall = mbModified ? 1 : 0; + mbModified = sal_False; + // If there is already a document statistic, we assume that + // it is correct. In this case we reset the modified flag. + if ( 0 != pDocStat->nChar ) + pDocStat->bModified = sal_False; + GetIDocumentUndoRedo().SetUndoNoModifiedPosition(); + if( nCall && aOle2Link.IsSet() ) + { + mbInCallModified = sal_True; + aOle2Link.Call( (void*)nCall ); + mbInCallModified = sal_False; + } +} + + +void SwDoc::ReRead( SwPaM& rPam, const String& rGrfName, + const String& rFltName, const Graphic* pGraphic, + const GraphicObject* pGrafObj ) +{ + SwGrfNode *pGrfNd; + if( ( !rPam.HasMark() + || rPam.GetPoint()->nNode.GetIndex() == rPam.GetMark()->nNode.GetIndex() ) + && 0 != ( pGrfNd = rPam.GetPoint()->nNode.GetNode().GetGrfNode() ) ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoReRead(rPam, *pGrfNd)); + } + + // Weil nicht bekannt ist, ob sich die Grafik spiegeln laesst, + // immer das SpiegelungsAttribut zuruecksetzen + if( RES_MIRROR_GRAPH_DONT != pGrfNd->GetSwAttrSet(). + GetMirrorGrf().GetValue() ) + pGrfNd->SetAttr( SwMirrorGrf() ); + + pGrfNd->ReRead( rGrfName, rFltName, pGraphic, pGrafObj, sal_True ); + SetModified(); + } +} + +sal_Bool lcl_SpellAndGrammarAgain( const SwNodePtr& rpNd, void* pArgs ) +{ + SwTxtNode *pTxtNode = (SwTxtNode*)rpNd->GetTxtNode(); + sal_Bool bOnlyWrong = *(sal_Bool*)pArgs; + if( pTxtNode ) + { + if( bOnlyWrong ) + { + if( pTxtNode->GetWrong() && + pTxtNode->GetWrong()->InvalidateWrong() ) + pTxtNode->SetWrongDirty( true ); + if( pTxtNode->GetGrammarCheck() && + pTxtNode->GetGrammarCheck()->InvalidateWrong() ) + pTxtNode->SetGrammarCheckDirty( true ); + } + else + { + pTxtNode->SetWrongDirty( true ); + if( pTxtNode->GetWrong() ) + pTxtNode->GetWrong()->SetInvalid( 0, STRING_LEN ); + pTxtNode->SetGrammarCheckDirty( true ); + if( pTxtNode->GetGrammarCheck() ) + pTxtNode->GetGrammarCheck()->SetInvalid( 0, STRING_LEN ); + } + } + return sal_True; +} + +sal_Bool lcl_CheckSmartTagsAgain( const SwNodePtr& rpNd, void* ) +{ + SwTxtNode *pTxtNode = (SwTxtNode*)rpNd->GetTxtNode(); +// sal_Bool bOnlyWrong = *(sal_Bool*)pArgs; + if( pTxtNode ) + { + pTxtNode->SetSmartTagDirty( true ); + if( pTxtNode->GetSmartTags() ) + { +// if ( bOnlyWrong ) // only some smart tag types have been enabled or disabled +// pTxtNode->GetSmartTags()->SetInvalid( 0, STRING_LEN ); +// else // smart tags all have been enabled or disabled + pTxtNode->SetSmartTags( NULL ); + } + } + return sal_True; +} + + +/************************************************************************* + * SwDoc::SpellItAgainSam( sal_Bool bInvalid, sal_Bool bOnlyWrong ) + * + * stoesst das Spelling im Idle-Handler wieder an. + * Wird bInvalid als sal_True uebergeben, so werden zusaetzlich die WrongListen + * an allen Nodes invalidiert und auf allen Seiten das SpellInvalid-Flag + * gesetzt. + * Mit bOnlyWrong kann man dann steuern, ob nur die Bereiche mit falschen + * Woertern oder die kompletten Bereiche neu ueberprueft werden muessen. + ************************************************************************/ + +void SwDoc::SpellItAgainSam( sal_Bool bInvalid, sal_Bool bOnlyWrong, sal_Bool bSmartTags ) +{ + ASSERT( GetRootFrm(), "SpellAgain: Where's my RootFrm?" ); + if( bInvalid ) + { + SwPageFrm *pPage = (SwPageFrm*)GetRootFrm()->Lower(); + while ( pPage ) + { + if ( bSmartTags ) + pPage->InvalidateSmartTags(); + + pPage->InvalidateSpelling(); + pPage = (SwPageFrm*)pPage->GetNext(); + } + GetRootFrm()->SetNeedGrammarCheck( true ); + + if ( bSmartTags ) + GetNodes().ForEach( lcl_CheckSmartTagsAgain, &bOnlyWrong ); + + GetNodes().ForEach( lcl_SpellAndGrammarAgain, &bOnlyWrong ); + } + + GetRootFrm()->SetIdleFlags(); +} + +void SwDoc::InvalidateAutoCompleteFlag() +{ + if( GetRootFrm() ) + { + SwPageFrm *pPage = (SwPageFrm*)GetRootFrm()->Lower(); + while ( pPage ) + { + pPage->InvalidateAutoCompleteWords(); + pPage = (SwPageFrm*)pPage->GetNext(); + } + for( sal_uLong nNd = 1, nCnt = GetNodes().Count(); nNd < nCnt; ++nNd ) + { + SwTxtNode* pTxtNode = GetNodes()[ nNd ]->GetTxtNode(); + if ( pTxtNode ) pTxtNode->SetAutoCompleteWordDirty( true ); + } + GetRootFrm()->SetIdleFlags(); + } +} + +const SwFmtINetFmt* SwDoc::FindINetAttr( const String& rName ) const +{ + const SwFmtINetFmt* pItem; + const SwTxtINetFmt* pTxtAttr; + const SwTxtNode* pTxtNd; + sal_uInt32 n, nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_INETFMT ); + for( n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = (SwFmtINetFmt*)GetAttrPool().GetItem2( + RES_TXTATR_INETFMT, n ) ) && + pItem->GetName().Equals( rName ) && + 0 != ( pTxtAttr = pItem->GetTxtINetFmt()) && + 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) && + &pTxtNd->GetNodes() == &GetNodes() ) + { + return pItem; + } + + return 0; +} + +void SwDoc::Summary( SwDoc* pExtDoc, sal_uInt8 nLevel, sal_uInt8 nPara, sal_Bool bImpress ) +{ + const SwOutlineNodes& rOutNds = GetNodes().GetOutLineNds(); + if( pExtDoc && rOutNds.Count() ) + { + sal_uInt16 i; + ::StartProgress( STR_STATSTR_SUMMARY, 0, rOutNds.Count(), GetDocShell() ); + SwNodeIndex aEndOfDoc( pExtDoc->GetNodes().GetEndOfContent(), -1 ); + for( i = 0; i < rOutNds.Count(); ++i ) + { + ::SetProgressState( i, GetDocShell() ); + const sal_uLong nIndex = rOutNds[ i ]->GetIndex(); + //sal_uInt8 nLvl = ((SwTxtNode*)GetNodes()[ nIndex ])->GetTxtColl()//#outline level,zhaojianwei + // ->GetOutlineLevel(); + const int nLvl = ((SwTxtNode*)GetNodes()[ nIndex ])->GetAttrOutlineLevel()-1;//<-end,zhaojianwei + if( nLvl > nLevel ) + continue; + sal_uInt16 nEndOfs = 1; + sal_uInt8 nWish = nPara; + sal_uLong nNextOutNd = i + 1 < rOutNds.Count() ? + rOutNds[ i + 1 ]->GetIndex() : GetNodes().Count(); + sal_Bool bKeep = sal_False; + while( ( nWish || bKeep ) && nIndex + nEndOfs < nNextOutNd && + GetNodes()[ nIndex + nEndOfs ]->IsTxtNode() ) + { + SwTxtNode* pTxtNode = (SwTxtNode*)GetNodes()[ nIndex+nEndOfs ]; + if( pTxtNode->GetTxt().Len() && nWish ) + --nWish; + bKeep = pTxtNode->GetSwAttrSet().GetKeep().GetValue(); + ++nEndOfs; + } + + SwNodeRange aRange( *rOutNds[ i ], 0, *rOutNds[ i ], nEndOfs ); + GetNodes()._Copy( aRange, aEndOfDoc ); + } + const SwTxtFmtColls *pColl = pExtDoc->GetTxtFmtColls(); + for( i = 0; i < pColl->Count(); ++i ) + (*pColl)[ i ]->ResetFmtAttr( RES_PAGEDESC, RES_BREAK ); + SwNodeIndex aIndx( pExtDoc->GetNodes().GetEndOfExtras() ); + ++aEndOfDoc; + while( aIndx < aEndOfDoc ) + { + SwNode *pNode; + sal_Bool bDelete = sal_False; + if( (pNode = &aIndx.GetNode())->IsTxtNode() ) + { + SwTxtNode *pNd = (SwTxtNode*)pNode; + if( pNd->HasSwAttrSet() ) + pNd->ResetAttr( RES_PAGEDESC, RES_BREAK ); + if( bImpress ) + { + SwTxtFmtColl* pMyColl = pNd->GetTxtColl(); + //sal_uInt16 nHeadLine = static_cast<sal_uInt16>(pMyColl->GetOutlineLevel()==NO_NUMBERING ?//#outlinelevel,zhaojianwei + const sal_uInt16 nHeadLine = static_cast<sal_uInt16>( + !pMyColl->IsAssignedToListLevelOfOutlineStyle() //<-end,zhaojianwei + ? RES_POOLCOLL_HEADLINE2 + : RES_POOLCOLL_HEADLINE1 ); + pMyColl = pExtDoc->GetTxtCollFromPool( nHeadLine ); + pNd->ChgFmtColl( pMyColl ); + } + if( !pNd->Len() && + pNd->StartOfSectionIndex()+2 < pNd->EndOfSectionIndex() ) + { + bDelete = sal_True; + pExtDoc->GetNodes().Delete( aIndx ); + } + } + if( !bDelete ) + ++aIndx; + } + ::EndProgress( GetDocShell() ); + } +} + + // loesche den nicht sichtbaren Content aus dem Document, wie z.B.: + // versteckte Bereiche, versteckte Absaetze +bool SwDoc::RemoveInvisibleContent() +{ + sal_Bool bRet = sal_False; + GetIDocumentUndoRedo().StartUndo( UNDO_UI_DELETE_INVISIBLECNTNT, NULL ); + + { + SwTxtNode* pTxtNd; + SwClientIter aIter( *GetSysFldType( RES_HIDDENPARAFLD ) ); + for( SwFmtFld* pFmtFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + pFmtFld; pFmtFld = (SwFmtFld*)aIter.Next() ) + { + if( pFmtFld->GetTxtFld() && + 0 != ( pTxtNd = (SwTxtNode*)pFmtFld->GetTxtFld()->GetpTxtNode() ) && + pTxtNd->GetpSwpHints() && pTxtNd->HasHiddenParaField() && + &pTxtNd->GetNodes() == &GetNodes() ) + { + bRet = sal_True; + SwPaM aPam( *pTxtNd, 0, *pTxtNd, pTxtNd->GetTxt().Len() ); + + // Remove hidden paragraph or delete contents: + // Delete contents if + // 1. removing the paragraph would result in an empty section or + // 2. if the paragraph is the last paragraph in the section and + // there is no paragraph in front of the paragraph: + if ( ( 2 == pTxtNd->EndOfSectionIndex() - pTxtNd->StartOfSectionIndex() ) || + ( 1 == pTxtNd->EndOfSectionIndex() - pTxtNd->GetIndex() && + !GetNodes()[ pTxtNd->GetIndex() - 1 ]->GetTxtNode() ) ) + { + DeleteRange( aPam ); + } + else + { + aPam.DeleteMark(); + DelFullPara( aPam ); + } + } + } + } + + // + // Remove any hidden paragraph (hidden text attribute) + // + for( sal_uLong n = GetNodes().Count(); n; ) + { + SwTxtNode* pTxtNd = GetNodes()[ --n ]->GetTxtNode(); + if ( pTxtNd ) + { + bool bRemoved = false; + SwPaM aPam( *pTxtNd, 0, *pTxtNd, pTxtNd->GetTxt().Len() ); + if ( pTxtNd->HasHiddenCharAttribute( true ) ) + { + bRemoved = sal_True; + bRet = sal_True; + + // Remove hidden paragraph or delete contents: + // Delete contents if + // 1. removing the paragraph would result in an empty section or + // 2. if the paragraph is the last paragraph in the section and + // there is no paragraph in front of the paragraph: + + if ( ( 2 == pTxtNd->EndOfSectionIndex() - pTxtNd->StartOfSectionIndex() ) || + ( 1 == pTxtNd->EndOfSectionIndex() - pTxtNd->GetIndex() && + !GetNodes()[ pTxtNd->GetIndex() - 1 ]->GetTxtNode() ) ) + { + DeleteRange( aPam ); + } + else + { + aPam.DeleteMark(); + DelFullPara( aPam ); + } + } + else if ( pTxtNd->HasHiddenCharAttribute( false ) ) + { + bRemoved = sal_True; + bRet = sal_True; + SwScriptInfo::DeleteHiddenRanges( *pTxtNd ); + } + + // --> FME 2006-01-11 #120473# + // Footnotes/Frames may have been removed, therefore we have + // to reset n: + if ( bRemoved ) + n = aPam.GetPoint()->nNode.GetIndex(); + // <-- + } + } + + { + // dann noch alle versteckten Bereiche loeschen/leeren + SwSectionFmts aSectFmts; + SwSectionFmts& rSectFmts = GetSections(); + sal_uInt16 n; + + for( n = rSectFmts.Count(); n; ) + { + SwSectionFmt* pSectFmt = rSectFmts[ --n ]; + // don't add sections in Undo/Redo + if( !pSectFmt->IsInNodesArr()) + continue; + SwSection* pSect = pSectFmt->GetSection(); + if( pSect->CalcHiddenFlag() ) + { + SwSection* pParent = pSect, *pTmp; + while( 0 != (pTmp = pParent->GetParent() )) + { + if( pTmp->IsHiddenFlag() ) + pSect = pTmp; + pParent = pTmp; + } + + if( USHRT_MAX == aSectFmts.GetPos( pSect->GetFmt() ) ) + aSectFmts.Insert( pSect->GetFmt(), 0 ); + } + if( pSect->GetCondition().Len() ) + { + SwSectionData aSectionData( *pSect ); + aSectionData.SetCondition( aEmptyStr ); + aSectionData.SetHidden( false ); + UpdateSection( n, aSectionData ); + } + } + + if( 0 != ( n = aSectFmts.Count() )) + { + while( n ) + { + SwSectionFmt* pSectFmt = aSectFmts[ --n ]; + SwSectionNode* pSectNd = pSectFmt->GetSectionNode(); + if( pSectNd ) + { + bRet = sal_True; + SwPaM aPam( *pSectNd ); + + if( pSectNd->StartOfSectionNode()->StartOfSectionIndex() == + pSectNd->GetIndex() - 1 && + pSectNd->StartOfSectionNode()->EndOfSectionIndex() == + pSectNd->EndOfSectionIndex() + 1 ) + { + // nur den Inhalt loeschen + SwCntntNode* pCNd = GetNodes().GoNext( + &aPam.GetPoint()->nNode ); + aPam.GetPoint()->nContent.Assign( pCNd, 0 ); + aPam.SetMark(); + aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode(); + pCNd = GetNodes().GoPrevious( + &aPam.GetPoint()->nNode ); + aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + + DeleteRange( aPam ); + } + else + { + // die gesamte Section loeschen + aPam.SetMark(); + aPam.GetPoint()->nNode = *pSectNd->EndOfSectionNode(); + DelFullPara( aPam ); + } + + } + } + aSectFmts.Remove( 0, aSectFmts.Count() ); + } + } + + if( bRet ) + SetModified(); + GetIDocumentUndoRedo().EndUndo( UNDO_UI_DELETE_INVISIBLECNTNT, NULL ); + return bRet; +} +/*-- 25.08.2010 14:18:12--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool SwDoc::HasInvisibleContent() const +{ + sal_Bool bRet = sal_False; + + SwClientIter aIter( *GetSysFldType( RES_HIDDENPARAFLD ) ); + if( aIter.First( TYPE( SwFmtFld ) ) ) + bRet = sal_True; + + // + // Search for any hidden paragraph (hidden text attribute) + // + if( ! bRet ) + { + for( sal_uLong n = GetNodes().Count(); !bRet && (n > 0); ) + { + SwTxtNode* pTxtNd = GetNodes()[ --n ]->GetTxtNode(); + if ( pTxtNd ) + { + SwPaM aPam( *pTxtNd, 0, *pTxtNd, pTxtNd->GetTxt().Len() ); + if( pTxtNd->HasHiddenCharAttribute( true ) || ( pTxtNd->HasHiddenCharAttribute( false ) ) ) + { + bRet = sal_True; + } + } + } + } + + if( ! bRet ) + { + const SwSectionFmts& rSectFmts = GetSections(); + sal_uInt16 n; + + for( n = rSectFmts.Count(); !bRet && (n > 0); ) + { + SwSectionFmt* pSectFmt = rSectFmts[ --n ]; + // don't add sections in Undo/Redo + if( !pSectFmt->IsInNodesArr()) + continue; + SwSection* pSect = pSectFmt->GetSection(); + if( pSect->IsHidden() ) + bRet = sal_True; + } + } + return bRet; +} + +bool SwDoc::RestoreInvisibleContent() +{ + bool bRet = false; + SwUndoId nLastUndoId(UNDO_EMPTY); + if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId) + && (UNDO_UI_DELETE_INVISIBLECNTNT == nLastUndoId)) + { + GetIDocumentUndoRedo().Undo(); + GetIDocumentUndoRedo().ClearRedo(); + bRet = true; + } + return bRet; +} + +/*-- 11.06.2004 08:34:04--------------------------------------------------- + + -----------------------------------------------------------------------*/ +sal_Bool SwDoc::ConvertFieldsToText() +{ + sal_Bool bRet = sal_False; + LockExpFlds(); + GetIDocumentUndoRedo().StartUndo( UNDO_UI_REPLACE, NULL ); + + const SwFldTypes* pMyFldTypes = GetFldTypes(); + sal_uInt16 nCount = pMyFldTypes->Count(); + //go backward, field types are removed + for(sal_uInt16 nType = nCount; nType > 0; --nType) + { + const SwFieldType *pCurType = pMyFldTypes->GetObject(nType - 1); + + if ( RES_POSTITFLD == pCurType->Which() ) + continue; + + SwClientIter aIter( *(SwFieldType*)pCurType ); + const SwFmtFld* pCurFldFmt = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + ::std::vector<const SwFmtFld*> aFieldFmts; + while (pCurFldFmt) + { + aFieldFmts.push_back(pCurFldFmt); + pCurFldFmt = (SwFmtFld*)aIter.Next(); + } + ::std::vector<const SwFmtFld*>::iterator aBegin = aFieldFmts.begin(); + ::std::vector<const SwFmtFld*>::iterator aEnd = aFieldFmts.end(); + while(aBegin != aEnd) + { + const SwTxtFld *pTxtFld = (*aBegin)->GetTxtFld(); + // skip fields that are currently not in the document + // e.g. fields in undo or redo array + + sal_Bool bSkip = !pTxtFld || + !pTxtFld->GetpTxtNode()->GetNodes().IsDocNodes(); + + if (!bSkip) + { + sal_Bool bInHeaderFooter = IsInHeaderFooter(SwNodeIndex(*pTxtFld->GetpTxtNode())); + const SwFmtFld& rFmtFld = pTxtFld->GetFld(); + const SwField* pField = rFmtFld.GetFld(); + + //#i55595# some fields have to be excluded in headers/footers + sal_uInt16 nWhich = pField->GetTyp()->Which(); + if(!bInHeaderFooter || + (nWhich != RES_PAGENUMBERFLD && + nWhich != RES_CHAPTERFLD && + nWhich != RES_GETEXPFLD&& + nWhich != RES_SETEXPFLD&& + nWhich != RES_INPUTFLD&& + nWhich != RES_REFPAGEGETFLD&& + nWhich != RES_REFPAGESETFLD)) + { + String sText = pField->ExpandField(true); + //database fields should not convert their command into text + if( RES_DBFLD == pCurType->Which() && !static_cast<const SwDBField*>(pField)->IsInitialized()) + sText.Erase(); + + //now remove the field and insert the string + SwPaM aPam1(*pTxtFld->GetpTxtNode(), *pTxtFld->GetStart()); + aPam1.Move(); + //insert first to keep the field's attributes + InsertString( aPam1, sText ); + SwPaM aPam2(*pTxtFld->GetpTxtNode(), *pTxtFld->GetStart()); + aPam2.SetMark(); + aPam2.Move(); + DeleteAndJoin(aPam2);//remove the field + } + } + ++aBegin; + } + } + + if( bRet ) + SetModified(); + GetIDocumentUndoRedo().EndUndo( UNDO_UI_REPLACE, NULL ); + UnlockExpFlds(); + return bRet; + +} + +bool SwDoc::IsVisibleLinks() const +{ + return mbVisibleLinks; +} + +void SwDoc::SetVisibleLinks(bool bFlag) +{ + mbVisibleLinks = bFlag; +} + +sfx2::LinkManager& SwDoc::GetLinkManager() +{ + return *pLinkMgr; +} + +const sfx2::LinkManager& SwDoc::GetLinkManager() const +{ + return *pLinkMgr; +} + +void SwDoc::SetLinksUpdated(const bool bNewLinksUpdated) +{ + mbLinksUpdated = bNewLinksUpdated; +} + +bool SwDoc::LinksUpdated() const +{ + return mbLinksUpdated; +} + + // embedded alle lokalen Links (Bereiche/Grafiken) +::sfx2::SvBaseLink* lcl_FindNextRemovableLink( const ::sfx2::SvBaseLinks& rLinks, sfx2::LinkManager& rLnkMgr ) +{ + for( sal_uInt16 n = 0; n < rLinks.Count(); ++n ) + { + ::sfx2::SvBaseLink* pLnk = &(*rLinks[ n ]); + if( pLnk && + ( OBJECT_CLIENT_GRF == pLnk->GetObjType() || + OBJECT_CLIENT_FILE == pLnk->GetObjType() ) && + pLnk->ISA( SwBaseLink ) ) + { + ::sfx2::SvBaseLinkRef xLink = pLnk; + + String sFName; + rLnkMgr.GetDisplayNames( xLink, 0, &sFName, 0, 0 ); + + INetURLObject aURL( sFName ); + if( INET_PROT_FILE == aURL.GetProtocol() || + INET_PROT_CID == aURL.GetProtocol() ) + return pLnk; + } + } + return 0; +} +bool SwDoc::EmbedAllLinks() +{ + sal_Bool bRet = sal_False; + sfx2::LinkManager& rLnkMgr = GetLinkManager(); + const ::sfx2::SvBaseLinks& rLinks = rLnkMgr.GetLinks(); + if( rLinks.Count() ) + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + ::sfx2::SvBaseLink* pLnk = 0; + while( 0 != (pLnk = lcl_FindNextRemovableLink( rLinks, rLnkMgr ) ) ) + { + ::sfx2::SvBaseLinkRef xLink = pLnk; + // dem Link sagen, das er aufgeloest wird! + xLink->Closed(); + + // falls einer vergessen hat sich auszutragen + if( xLink.Is() ) + rLnkMgr.Remove( xLink ); + + bRet = sal_True; + } + + GetIDocumentUndoRedo().DelAllUndoObj(); + SetModified(); + } + return bRet; +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +sal_Bool SwDoc::IsInsTblFormatNum() const +{ + return SW_MOD()->IsInsTblFormatNum(get(IDocumentSettingAccess::HTML_MODE)); +} + +sal_Bool SwDoc::IsInsTblChangeNumFormat() const +{ + return SW_MOD()->IsInsTblChangeNumFormat(get(IDocumentSettingAccess::HTML_MODE)); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +sal_Bool SwDoc::IsInsTblAlignNum() const +{ + return SW_MOD()->IsInsTblAlignNum(get(IDocumentSettingAccess::HTML_MODE)); +} + + // setze das InsertDB als Tabelle Undo auf: +void SwDoc::AppendUndoForInsertFromDB( const SwPaM& rPam, sal_Bool bIsTable ) +{ + if( bIsTable ) + { + const SwTableNode* pTblNd = rPam.GetPoint()->nNode.GetNode().FindTableNode(); + if( pTblNd ) + { + SwUndoCpyTbl* pUndo = new SwUndoCpyTbl; + pUndo->SetTableSttIdx( pTblNd->GetIndex() ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + else if( rPam.HasMark() ) + { + SwUndoCpyDoc* pUndo = new SwUndoCpyDoc( rPam ); + pUndo->SetInsertRange( rPam, sal_False ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } +} + +void SwDoc::ChgTOX(SwTOXBase & rTOX, const SwTOXBase & rNew) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().DelAllUndoObj(); + + SwUndo * pUndo = new SwUndoTOXChange(&rTOX, rNew); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + rTOX = rNew; + + if (rTOX.ISA(SwTOXBaseSection)) + { + static_cast<SwTOXBaseSection &>(rTOX).Update(); + static_cast<SwTOXBaseSection &>(rTOX).UpdatePageNum(); + } +} + +// #111827# +String SwDoc::GetPaMDescr(const SwPaM & rPam) const +{ + String aResult; + bool bOK = false; + + if (rPam.GetNode(sal_True) == rPam.GetNode(sal_False)) + { + SwTxtNode * pTxtNode = rPam.GetNode(sal_True)->GetTxtNode(); + + if (0 != pTxtNode) + { + xub_StrLen nStart = rPam.Start()->nContent.GetIndex(); + xub_StrLen nEnd = rPam.End()->nContent.GetIndex(); + + aResult += String(SW_RES(STR_START_QUOTE)); + aResult += ShortenString(pTxtNode->GetTxt(). + Copy(nStart, nEnd - nStart), + nUndoStringLength, + String(SW_RES(STR_LDOTS))); + aResult += String(SW_RES(STR_END_QUOTE)); + + bOK = true; + } + } + else if (0 != rPam.GetNode(sal_True)) + { + if (0 != rPam.GetNode(sal_False)) + aResult += String(SW_RES(STR_PARAGRAPHS)); + + bOK = true; + } + + if (! bOK) + aResult += String("??", RTL_TEXTENCODING_ASCII_US); + + return aResult; +} + +// -> #111840# +SwField * SwDoc::GetField(const SwPosition & rPos) +{ + SwTxtFld * const pAttr = GetTxtFld(rPos); + + return (pAttr) ? const_cast<SwField *>( pAttr->GetFld().GetFld() ) : 0; +} + +SwTxtFld * SwDoc::GetTxtFld(const SwPosition & rPos) +{ + SwTxtNode * const pNode = rPos.nNode.GetNode().GetTxtNode(); + + return (pNode) + ? static_cast<SwTxtFld*>( pNode->GetTxtAttrForCharAt( + rPos.nContent.GetIndex(), RES_TXTATR_FIELD) ) + : 0; +} +// <- #111840# + +bool SwDoc::ContainsHiddenChars() const +{ + for( sal_uLong n = GetNodes().Count(); n; ) + { + SwNode* pNd = GetNodes()[ --n ]; + if ( ND_TEXTNODE == pNd->GetNodeType() && + ((SwTxtNode*)pNd)->HasHiddenCharAttribute( false ) ) + return true; + } + + return false; +} + +SwUnoCrsr* SwDoc::CreateUnoCrsr( const SwPosition& rPos, sal_Bool bTblCrsr ) +{ + SwUnoCrsr* pNew; + if( bTblCrsr ) + pNew = new SwUnoTableCrsr( rPos ); + else + pNew = new SwUnoCrsr( rPos ); + + pUnoCrsrTbl->Insert( pNew, pUnoCrsrTbl->Count() ); + return pNew; +} + +void SwDoc::ChkCondColls() +{ + for (sal_uInt16 n = 0; n < pTxtFmtCollTbl->Count(); n++) + { + SwTxtFmtColl *pColl = (*pTxtFmtCollTbl)[n]; + + if (RES_CONDTXTFMTCOLL == pColl->Which()) + { + SwClientIter aIter(*pColl); + + SwClient * pClient = aIter.First(TYPE(SwTxtNode)); + while (pClient) + { + SwTxtNode * pTxtNode = static_cast<SwTxtNode *>(pClient); + + pTxtNode->ChkCondColl(); + + pClient = aIter.Next(); + } + } + } +} + +#ifdef FUTURE_VBA +uno::Reference< script::vba::XVBAEventProcessor > +SwDoc::GetVbaEventProcessor() +{ + if( !mxVbaEvents.is() && pDocShell && ooo::vba::isAlienWordDoc( *pDocShell ) ) + { + try + { + uno::Reference< frame::XModel > xModel( pDocShell->GetModel(), uno::UNO_SET_THROW ); + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xModel; + mxVbaEvents.set( ooo::vba::createVBAUnoAPIServiceWithArgs( pDocShell, "com.sun.star.script.vba.VBATextEventProcessor" , aArgs ), uno::UNO_QUERY_THROW ); + } + catch( uno::Exception& ) + { + } + } + return mxVbaEvents; +} +#endif + +void SwDoc::setExternalData(::sw::tExternalDataType eType, + ::sw::tExternalDataPointer pPayload) +{ + m_externalData[eType] = pPayload; +} + +::sw::tExternalDataPointer SwDoc::getExternalData(::sw::tExternalDataType eType) +{ + return m_externalData[eType]; +} diff --git a/sw/source/core/doc/docbasic.cxx b/sw/source/core/doc/docbasic.cxx new file mode 100644 index 000000000000..77665e55fbce --- /dev/null +++ b/sw/source/core/doc/docbasic.cxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#ifndef _RTL_USTRING_HXX //autogen +#include <rtl/ustring.hxx> +#endif +#include <svtools/imap.hxx> +#include <svtools/imapobj.hxx> +#include <basic/sbx.hxx> +#include <frmfmt.hxx> +#include <fmtinfmt.hxx> +#include <fmturl.hxx> +#include <frmatr.hxx> +#include <docary.hxx> +#include <doc.hxx> +#ifndef _DOCSH_HXX +#include <docsh.hxx> +#endif +#include <swevent.hxx> + +using namespace ::com::sun::star::uno; +using ::rtl::OUString; + +static Sequence<Any> *lcl_docbasic_convertArgs( SbxArray& rArgs ) +{ + Sequence<Any> *pRet = 0; + + sal_uInt16 nCount = rArgs.Count(); + if( nCount > 1 ) + { + nCount--; + pRet = new Sequence<Any>( nCount ); + Any *pUnoArgs = pRet->getArray(); + for( sal_uInt16 i=0; i<nCount; i++ ) + { + SbxVariable *pVar = rArgs.Get( i+1 ); + switch( pVar->GetType() ) + { + case SbxSTRING: + pUnoArgs[i] <<= OUString( pVar->GetString() ); + break; + case SbxCHAR: + pUnoArgs[i] <<= (sal_Int16)pVar->GetChar() ; + break; + case SbxUSHORT: + pUnoArgs[i] <<= (sal_Int16)pVar->GetUShort(); + break; + case SbxLONG: + pUnoArgs[i] <<= (sal_Int32)pVar->GetLong(); + break; + default: + pUnoArgs[i].setValue(0, ::getVoidCppuType()); + break; + } + } + } + + return pRet; +} + +sal_Bool SwDoc::ExecMacro( const SvxMacro& rMacro, String* pRet, SbxArray* pArgs ) +{ + ErrCode eErr = 0; + switch( rMacro.GetScriptType() ) + { + case STARBASIC: + { + SbxBaseRef aRef; + SbxValue* pRetValue = new SbxValue; + aRef = pRetValue; + eErr = pDocShell->CallBasic( rMacro.GetMacName(), + rMacro.GetLibName(), + pArgs, pRet ? pRetValue : 0 ); + + if( pRet && SbxNULL < pRetValue->GetType() && + SbxVOID != pRetValue->GetType() ) + // gueltiger Wert, also setzen + *pRet = pRetValue->GetString(); + } + break; + case JAVASCRIPT: + // ignore JavaScript calls + break; + case EXTENDED_STYPE: + { + Sequence<Any> *pUnoArgs = 0; + if( pArgs ) + { + // better to rename the local function to lcl_translateBasic2Uno and + // a much shorter routine can be found in sfx2/source/doc/objmisc.cxx + pUnoArgs = lcl_docbasic_convertArgs( *pArgs ); + } + + if (!pUnoArgs) + { + pUnoArgs = new Sequence< Any > (0); + } + + // TODO - return value is not handled + Any aRet; + Sequence< sal_Int16 > aOutArgsIndex; + Sequence< Any > aOutArgs; + + OSL_TRACE( "SwDoc::ExecMacro URL is %s", ByteString( rMacro.GetMacName(), + RTL_TEXTENCODING_UTF8).GetBuffer() ); + + eErr = pDocShell->CallXScript( + rMacro.GetMacName(), *pUnoArgs, aRet, aOutArgsIndex, aOutArgs); + + //*pRet = pRetValue->GetString(); + // use the AnyConverter to return a String if appropriate? + + // need to call something like lcl_translateUno2Basic + // pArgs = lcl_translateUno2Basic( pUnoArgs ); + + delete pUnoArgs; + break; + } + } + + return 0 == eErr; +} + + + +sal_uInt16 SwDoc::CallEvent( sal_uInt16 nEvent, const SwCallMouseEvent& rCallEvent, + sal_Bool bCheckPtr, SbxArray* pArgs, const Link* ) +{ + if( !pDocShell ) // ohne DocShell geht das nicht! + return 0; + + sal_uInt16 nRet = 0; + const SvxMacroTableDtor* pTbl = 0; + switch( rCallEvent.eType ) + { + case EVENT_OBJECT_INETATTR: + if( bCheckPtr ) + { + const SfxPoolItem* pItem; + sal_uInt32 n, nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_INETFMT ); + for( n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = GetAttrPool().GetItem2( RES_TXTATR_INETFMT, n ) ) + && rCallEvent.PTR.pINetAttr == pItem ) + { + bCheckPtr = sal_False; // als Flag missbrauchen + break; + } + } + if( !bCheckPtr ) + pTbl = rCallEvent.PTR.pINetAttr->GetMacroTbl(); + break; + + case EVENT_OBJECT_URLITEM: + case EVENT_OBJECT_IMAGE: + { + const SwFrmFmtPtr pFmt = (SwFrmFmtPtr)rCallEvent.PTR.pFmt; + if( bCheckPtr ) + { + sal_uInt16 nPos = GetSpzFrmFmts()->GetPos( pFmt ); + if( USHRT_MAX != nPos ) + bCheckPtr = sal_False; // als Flag missbrauchen + } + if( !bCheckPtr ) + pTbl = &pFmt->GetMacro().GetMacroTable(); + } + break; + + case EVENT_OBJECT_IMAGEMAP: + { + const IMapObject* pIMapObj = rCallEvent.PTR.IMAP.pIMapObj; + if( bCheckPtr ) + { + const SwFrmFmtPtr pFmt = (SwFrmFmtPtr)rCallEvent.PTR.IMAP.pFmt; + sal_uInt16 nPos = GetSpzFrmFmts()->GetPos( pFmt ); + const ImageMap* pIMap; + if( USHRT_MAX != nPos && + 0 != (pIMap = pFmt->GetURL().GetMap()) ) + { + for( nPos = pIMap->GetIMapObjectCount(); nPos; ) + if( pIMapObj == pIMap->GetIMapObject( --nPos )) + { + bCheckPtr = sal_False; // als Flag missbrauchen + break; + } + } + } + if( !bCheckPtr ) + pTbl = &pIMapObj->GetMacroTable(); + } + break; + default: + break; + } + + if( pTbl ) + { + nRet = 0x1; + if( pTbl->IsKeyValid( nEvent ) ) + { + const SvxMacro& rMacro = *pTbl->Get( nEvent ); + if( STARBASIC == rMacro.GetScriptType() ) + { + nRet += 0 == pDocShell->CallBasic( rMacro.GetMacName(), + rMacro.GetLibName(), pArgs ) ? 1 : 0; + } + else if( EXTENDED_STYPE == rMacro.GetScriptType() ) + { + Sequence<Any> *pUnoArgs = 0; + + if( pArgs ) + { + pUnoArgs = lcl_docbasic_convertArgs( *pArgs ); + } + + if (!pUnoArgs) + { + pUnoArgs = new Sequence <Any> (0); + } + + Any aRet; + Sequence< sal_Int16 > aOutArgsIndex; + Sequence< Any > aOutArgs; + + OSL_TRACE( "SwDoc::CallEvent URL is %s", ByteString( + rMacro.GetMacName(), RTL_TEXTENCODING_UTF8).GetBuffer() ); + + nRet += 0 == pDocShell->CallXScript( + rMacro.GetMacName(), *pUnoArgs,aRet, aOutArgsIndex, aOutArgs) ? 1 : 0; + + //*pRet = pRetValue->GetString(); + // use the AnyConverter to return a String if appropriate? + + // need to call something like lcl_translateUno2Basic + // pArgs = lcl_translateUno2Basic( pUnoArgs ); + + delete pUnoArgs; + } + // JavaScript calls are ignored + } + } + return nRet; +} + + + + diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx new file mode 100644 index 000000000000..50fb0e7b98f7 --- /dev/null +++ b/sw/source/core/doc/docbm.cxx @@ -0,0 +1,1746 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <MarkManager.hxx> +#include <bookmrk.hxx> +#include <boost/bind.hpp> +#include <cntfrm.hxx> +#include <crossrefbookmark.hxx> +#include <dcontact.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <xmloff/odffields.hxx> +#include <editsh.hxx> +#include <errhdl.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <functional> +#include <hintids.hxx> +#include <mvsave.hxx> +#include <ndtxt.hxx> +#include <node.hxx> +#include <pam.hxx> +#include <redline.hxx> +#include <rolbck.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <sortedobjs.hxx> +#include <sfx2/linkmgr.hxx> +#include <swserv.hxx> +#include <swundo.hxx> +#include <tools/pstm.hxx> +#include <unocrsr.hxx> +#include <viscrs.hxx> +#include <stdio.h> + + +using namespace ::std; +using namespace ::boost; +using namespace ::sw::mark; + +namespace +{ + static bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return pIdx ? ( rPos.nNode > rNdIdx || ( rPos.nNode == rNdIdx && rPos.nContent >= pIdx->GetIndex() )) : rPos.nNode >= rNdIdx; + } + + static bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return rPos.nNode < rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent < pIdx->GetIndex() ); + } + + static bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst, + const IDocumentMarkAccess::pMark_t& rpSecond) + { + return rpFirst->GetMarkStart() < rpSecond->GetMarkStart(); + } + + static bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst, + const IDocumentMarkAccess::pMark_t& rpSecond) + { + return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd(); + } + + static void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks, + const IDocumentMarkAccess::pMark_t& pMark) + { + io_vMarks.insert( + lower_bound( + io_vMarks.begin(), + io_vMarks.end(), + pMark, + &lcl_MarkOrderingByStart), + pMark); + } + + static inline auto_ptr<SwPosition> lcl_PositionFromCntntNode(SwCntntNode * const pCntntNode, const bool bAtEnd=false) + { + auto_ptr<SwPosition> pResult(new SwPosition(*pCntntNode)); + pResult->nContent.Assign(pCntntNode, bAtEnd ? pCntntNode->Len() : 0); + return pResult; + } + + // return a position at the begin of rEnd, if it is a CntntNode + // else set it to the begin of the Node after rEnd, if there is one + // else set it to the end of the node before rStt + // else set it to the CntntNode of the Pos outside the Range + static inline auto_ptr<SwPosition> lcl_FindExpelPosition(const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + const SwPosition& rOtherPosition) + { + SwCntntNode * pNode = rEnd.GetNode().GetCntntNode(); + SwNodeIndex aStt = SwNodeIndex(rStt); + SwNodeIndex aEnd = SwNodeIndex(rEnd); + bool bAtEnd = false; + if(!pNode) + pNode = rEnd.GetNodes().GoNext(&aEnd), bAtEnd = false; + if(!pNode) + pNode = rStt.GetNodes().GoPrevious(&aStt), bAtEnd = true; + if(pNode) + return lcl_PositionFromCntntNode(pNode, bAtEnd); + return auto_ptr<SwPosition>(new SwPosition(rOtherPosition)); + }; + + static IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) + { + IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound( + rMarks.begin(), + rMarks.end(), + rPos, + bind(&IMark::StartsAfter, _2, _1)); // finds the first that is starting after + if(pMarkAfter == rMarks.end()) return NULL; + return pMarkAfter->get(); + }; + + static IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos) + { + // candidates from which to choose the mark before + IDocumentMarkAccess::container_t vCandidates; + // no need to consider marks starting after rPos + IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound( + rMarks.begin(), + rMarks.end(), + rPos, + bind(&IMark::StartsAfter, _2, _1)); + vCandidates.reserve(pCandidatesEnd - rMarks.begin()); + // only marks ending before are candidates + remove_copy_if( + rMarks.begin(), + pCandidatesEnd, + back_inserter(vCandidates), + bind(logical_not<bool>(), bind(&IMark::EndsBefore, _1, rPos))); + // no candidate left => we are in front of the first mark or there are none + if(!vCandidates.size()) return NULL; + // return the highest (last) candidate using mark end ordering + return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get(); + } + + static bool lcl_FixCorrectedMark(bool bChangedPos, bool bChangedOPos, MarkBase* io_pMark) + { + if( (bChangedPos || bChangedOPos) && io_pMark->IsExpanded() && + io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() != + io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() ) + { + if(!bChangedOPos) + io_pMark->SetMarkPos(io_pMark->GetOtherMarkPos()); + io_pMark->ClearOtherMarkPos(); + DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark); + if(pDdeBkmk && pDdeBkmk->IsServer()) + pDdeBkmk->SetRefObject(NULL); + return true; + } + return false; + } + + static IDocumentMarkAccess::iterator_t lcl_FindMark( + IDocumentMarkAccess::container_t& rMarks, + const IDocumentMarkAccess::pMark_t& rpMarkToFind) + { + IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( + rMarks.begin(), rMarks.end(), + rpMarkToFind, &lcl_MarkOrderingByStart); + // since there are usually not too many marks on the same start + // position, we are not doing a bisect search for the upper bound + // but instead start to iterate from pMarkLow directly + while(ppCurrentMark != rMarks.end() && **ppCurrentMark == *rpMarkToFind) + { + if(ppCurrentMark->get() == rpMarkToFind.get()) + { + //OSL_TRACE("found mark named '%s'", + // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); + return ppCurrentMark; + } + ++ppCurrentMark; + } + // reached a mark starting on a later start pos or the end of the + // vector => not found + return rMarks.end(); + }; + + static IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos( + IDocumentMarkAccess::container_t& rMarks, + const SwPosition& rPos, + const IDocumentMarkAccess::MarkType eType) + { + for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound( + rMarks.begin(), rMarks.end(), + rPos, + bind(&IMark::StartsBefore, _1, _2)); + ppCurrentMark != rMarks.end(); + ++ppCurrentMark) + { + // Once we reach a mark starting after the target pos + // we do not need to continue + if(ppCurrentMark->get()->StartsAfter(rPos)) + break; + if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType) + { + //OSL_TRACE("found mark named '%s'", + // ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr()); + return ppCurrentMark; + } + } + // reached a mark starting on a later start pos or the end of the + // vector => not found + return rMarks.end(); + }; + + static IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName( + const ::rtl::OUString& rName, + IDocumentMarkAccess::const_iterator_t ppMarksBegin, + IDocumentMarkAccess::const_iterator_t ppMarksEnd) + { + return find_if( + ppMarksBegin, + ppMarksEnd, + bind(&::rtl::OUString::equals, bind(&IMark::GetName, _1), rName)); + } + +#if 0 + static void lcl_DebugMarks(IDocumentMarkAccess::container_t vMarks) + { + OSL_TRACE("%d Marks", vMarks.size()); + for(IDocumentMarkAccess::iterator_t ppMark = vMarks.begin(); + ppMark != vMarks.end(); + ppMark++) + { + IMark* pMark = ppMark->get(); + ::rtl::OString sName = ::rtl::OUStringToOString(pMark->GetName(), RTL_TEXTENCODING_UTF8); + const SwPosition* const pStPos = &pMark->GetMarkStart(); + const SwPosition* const pEndPos = &pMark->GetMarkEnd(); + OSL_TRACE("%s %s %d,%d %d,%d", + typeid(*pMark).name(), + sName.getStr(), + pStPos->nNode.GetIndex(), + pStPos->nContent.GetIndex(), + pEndPos->nNode.GetIndex(), + pEndPos->nContent.GetIndex()); + } + }; +#endif +} + +IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk) +{ + const std::type_info* const pMarkTypeInfo = &typeid(rBkmk); + // not using dynamic_cast<> here for performance + if(*pMarkTypeInfo == typeid(UnoMark)) + return UNO_BOOKMARK; + else if(*pMarkTypeInfo == typeid(DdeBookmark)) + return DDE_BOOKMARK; + else if(*pMarkTypeInfo == typeid(Bookmark)) + return BOOKMARK; + else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark)) + return CROSSREF_HEADING_BOOKMARK; + else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark)) + return CROSSREF_NUMITEM_BOOKMARK; + else if(*pMarkTypeInfo == typeid(TextFieldmark)) + return TEXT_FIELDMARK; + else if(*pMarkTypeInfo == typeid(CheckboxFieldmark)) + return CHECKBOX_FIELDMARK; + else if(*pMarkTypeInfo == typeid(NavigatorReminder)) + return NAVIGATOR_REMINDER; + else + { + OSL_ENSURE(false, + "IDocumentMarkAccess::GetType(..)" + " - unknown MarkType. This needs to be fixed!"); + return UNO_BOOKMARK; + } +} + +namespace sw { namespace mark +{ + MarkManager::MarkManager(SwDoc& rDoc) + : m_pDoc(&rDoc) + { } +#if OSL_DEBUG_LEVEL > 1 + void MarkManager::dumpFieldmarks( ) const + { + const_iterator_t pIt = m_vFieldmarks.begin(); + for (; pIt != m_vFieldmarks.end( ); pIt++) + { + rtl::OUString str = (*pIt)->ToString(); + OSL_TRACE("%s\n", + ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr()); + } + } +#endif + ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, + const ::rtl::OUString& rName, + const IDocumentMarkAccess::MarkType eType) + { +#if 0 + { + ::rtl::OString sName = ::rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8); + const SwPosition* const pPos1 = rPaM.GetPoint(); + const SwPosition* pPos2 = pPos1; + if(rPaM.HasMark()) + pPos2 = rPaM.GetMark(); + OSL_TRACE("%s %d,%d %d,%d", + sName.getStr(), + pPos1->nNode.GetIndex(), + pPos1->nContent.GetIndex(), + pPos2->nNode.GetIndex(), + pPos2->nContent.GetIndex()); + } +#endif + // see for example _SaveCntntIdx, Shells + OSL_PRECOND(m_vMarks.size() < USHRT_MAX, + "MarkManager::makeMark(..)" + " - more than USHRT_MAX marks are not supported correctly"); + // There should only be one CrossRefBookmark per Textnode per Type + OSL_PRECOND( + (eType != CROSSREF_NUMITEM_BOOKMARK && eType != CROSSREF_HEADING_BOOKMARK) + || (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.GetPoint(), eType) == m_vBookmarks.end()), + "MarkManager::makeMark(..)" + " - creating duplicate CrossRefBookmark"); + + // create mark + pMark_t pMark; + switch(eType) + { + case IDocumentMarkAccess::TEXT_FIELDMARK: + pMark = shared_ptr<IMark>(new TextFieldmark(rPaM)); + break; + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + pMark = shared_ptr<IMark>(new CheckboxFieldmark(rPaM)); + break; + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + pMark = shared_ptr<IMark>(new NavigatorReminder(rPaM)); + break; + case IDocumentMarkAccess::BOOKMARK: + pMark = shared_ptr<IMark>(new Bookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::DDE_BOOKMARK: + pMark = shared_ptr<IMark>(new DdeBookmark(rPaM)); + break; + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + pMark = shared_ptr<IMark>(new CrossRefHeadingBookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + pMark = shared_ptr<IMark>(new CrossRefNumItemBookmark(rPaM, KeyCode(), rName, ::rtl::OUString())); + break; + case IDocumentMarkAccess::UNO_BOOKMARK: + pMark = shared_ptr<IMark>(new UnoMark(rPaM)); + break; + } + OSL_ENSURE(pMark.get(), + "MarkManager::makeMark(..)" + " - Mark was not created."); + MarkBase* pMarkBase = dynamic_cast<MarkBase*>(pMark.get()); + + if(pMark->GetMarkPos() != pMark->GetMarkStart()) + pMarkBase->Swap(); + + // for performance reasons, we trust UnoMarks to have a (generated) unique name + if(eType != IDocumentMarkAccess::UNO_BOOKMARK) + pMarkBase->SetName(getUniqueMarkName(pMarkBase->GetName())); + + // register mark + lcl_InsertMarkSorted(m_vMarks, pMark); + switch(eType) + { + case IDocumentMarkAccess::BOOKMARK: + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + // if(dynamic_cast<IBookmark*>) + lcl_InsertMarkSorted(m_vBookmarks, pMark); + break; + case IDocumentMarkAccess::TEXT_FIELDMARK: + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + // if(dynamic_cast<IFieldmark*> + lcl_InsertMarkSorted(m_vFieldmarks, pMark); + break; + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + case IDocumentMarkAccess::DDE_BOOKMARK: + case IDocumentMarkAccess::UNO_BOOKMARK: + // no special array for these + break; + } + pMarkBase->InitDoc(m_pDoc); +#if 0 + OSL_TRACE("--- makeType ---"); + OSL_TRACE("Marks"); + lcl_DebugMarks(m_vMarks); + OSL_TRACE("Bookmarks"); + lcl_DebugMarks(m_vBookmarks); + OSL_TRACE("Fieldmarks"); + lcl_DebugMarks(m_vFieldmarks); +#endif + return pMark.get(); + } + + ::sw::mark::IFieldmark* MarkManager::makeFieldBookmark( const SwPaM& rPaM, + const rtl::OUString& rName, + const rtl::OUString& rType ) + { + sw::mark::IMark* pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::TEXT_FIELDMARK ); + sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); + pFieldMark->SetFieldname( rType ); + + return pFieldMark; + } + + ::sw::mark::IFieldmark* MarkManager::makeNoTextFieldBookmark( const SwPaM& rPaM, + const rtl::OUString& rName, + const rtl::OUString& rType) + { + sw::mark::IMark* pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::CHECKBOX_FIELDMARK ); + sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); + pFieldMark->SetFieldname( rType ); + + return pFieldMark; + } + + ::sw::mark::IMark* MarkManager::getMarkForTxtNode(const SwTxtNode& rTxtNode, + const IDocumentMarkAccess::MarkType eType) + { + SwPosition aPos(rTxtNode); + aPos.nContent.Assign(&(const_cast<SwTxtNode&>(rTxtNode)), 0); + const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType); + if(ppExistingMark != m_vBookmarks.end()) + return ppExistingMark->get(); + const SwPaM aPaM(aPos); + return makeMark(aPaM, ::rtl::OUString(), eType); + } + + void MarkManager::repositionMark( ::sw::mark::IMark* const io_pMark, + const SwPaM& rPaM) + { + OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark); + pMarkBase->SetMarkPos(*(rPaM.GetPoint())); + if(rPaM.HasMark()) + pMarkBase->SetOtherMarkPos(*(rPaM.GetMark())); + else + pMarkBase->ClearOtherMarkPos(); + + if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart()) + pMarkBase->Swap(); + + sortMarks(); + } + + bool MarkManager::renameMark(::sw::mark::IMark* io_pMark, const ::rtl::OUString& rNewName) + { + OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + if(io_pMark->GetName() == rNewName) + return true; + if(findMark(rNewName) != getMarksEnd()) + return false; + dynamic_cast< ::sw::mark::MarkBase* >(io_pMark)->SetName(rNewName); + return true; + } + + void MarkManager::correctMarksAbsolute(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset) + { + const SwNode* const pOldNode = &rOldNode.GetNode(); + SwPosition aNewPos(rNewPos); + aNewPos.nContent += nOffset; + bool isSortingNeeded = false; + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // is on position ?? + bool bChangedPos = false, bChangedOPos = false; + ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) + { + pMark->SetMarkPos(aNewPos); + bChangedPos = true; + } + if (pMark->IsExpanded() && + &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) + { + pMark->SetMarkPos(aNewPos); + bChangedOPos= true; + } + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); + } + // restore sorting if needed + if(isSortingNeeded) + sortMarks(); +#if 0 + OSL_TRACE("correctMarksAbsolute"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset) + { + const SwNode* const pOldNode = &rOldNode.GetNode(); + SwPosition aNewPos(rNewPos); + aNewPos.nContent += nOffset; + bool isSortingNeeded = false; + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // is on position ?? + bool bChangedPos = false, bChangedOPos = false; + ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode) + { + SwPosition aNewPosRel(aNewPos); + aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex(); + pMark->SetMarkPos(aNewPosRel); + bChangedPos = true; + } + if(pMark->IsExpanded() && + &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode) + { + SwPosition aNewPosRel(aNewPos); + aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex(); + pMark->SetOtherMarkPos(aNewPosRel); + bChangedOPos = true; + } + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark); + } + // restore sorting if needed + if(isSortingNeeded) + sortMarks(); +#if 0 + OSL_TRACE("correctMarksRelative"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::deleteMarks( + const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + ::std::vector<SaveBookmark>* pSaveBkmk, + const SwIndex* pSttIdx, + const SwIndex* pEndIdx ) + { + vector<const_iterator_t> vMarksToDelete; + bool isSortingNeeded = false; + // copy all bookmarks in the move area to a vector storing all position data as offset + // reassignment is performed after the move + for(iterator_t ppMark = m_vMarks.begin(); + ppMark != m_vMarks.end(); + ppMark++) + { + // navigator marks should not be moved + // TODO: Check if this might make them invalid + if(IDocumentMarkAccess::GetType(**ppMark) == NAVIGATOR_REMINDER) + continue; + + ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get()); + // on position ?? + bool isPosInRange = (lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx) && + lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx)); + bool isOtherPosInRange = (pMark->IsExpanded() && + lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx) && + lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx)); + // special case: completely in range, touching the end? + if(pEndIdx && + ((isOtherPosInRange + && pMark->GetMarkPos().nNode == rEnd + && pMark->GetMarkPos().nContent == *pEndIdx) + || (isPosInRange + && pMark->IsExpanded() + && pMark->GetOtherMarkPos().nNode == rEnd + && pMark->GetOtherMarkPos().nContent == *pEndIdx))) + { + isPosInRange = true, isOtherPosInRange = true; + } + + if(isPosInRange && (isOtherPosInRange || !pMark->IsExpanded())) + { + // completely in range + + // --> OD 2009-08-07 #i92125# + bool bKeepCrossRefBkmk( false ); + { + if ( rStt == rEnd && + ( IDocumentMarkAccess::GetType(*pMark) == + IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK || + IDocumentMarkAccess::GetType(*pMark) == + IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) ) + { + bKeepCrossRefBkmk = true; + } + } + if ( !bKeepCrossRefBkmk ) + { + if(pSaveBkmk) + pSaveBkmk->push_back(SaveBookmark(true, true, *pMark, rStt, pSttIdx)); + vMarksToDelete.push_back(ppMark); + } + // <-- + } + else if(isPosInRange ^ isOtherPosInRange) + { + // the bookmark is partitially in the range + // move position of that is in the range out of it + auto_ptr<SwPosition> pNewPos; + if(pEndIdx) + pNewPos = auto_ptr<SwPosition>(new SwPosition( + rEnd, + *pEndIdx)); + else + pNewPos = lcl_FindExpelPosition( + rStt, + rEnd, + isPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos()); + + // --> OD 2009-08-06 #i92125# + // no move of position for cross-reference bookmarks, + // if move occurs inside a certain node + if ( ( IDocumentMarkAccess::GetType(*pMark) != + IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK && + IDocumentMarkAccess::GetType(*pMark) != + IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) || + pMark->GetMarkPos().nNode != pNewPos->nNode ) + { + if(isPosInRange) + pMark->SetMarkPos(*pNewPos); + else + pMark->SetOtherMarkPos(*pNewPos); + + // illegal selection? collapse the mark and restore sorting later + isSortingNeeded |= lcl_FixCorrectedMark(isPosInRange, isOtherPosInRange, pMark); + } + // <-- + } + } + + // we just remembered the iterators to delete, so we do not need to search + // for the shared_ptr<> (the entry in m_vMarks) again + // reverse iteration, since erasing an entry invalidates iterators + // behind it (the iterators in vMarksToDelete are sorted) + for(vector<const_iterator_t>::reverse_iterator pppMark = vMarksToDelete.rbegin(); + pppMark != vMarksToDelete.rend(); + pppMark++) + { + deleteMark(*pppMark); + } + if(isSortingNeeded) + sortMarks(); +#if 0 + OSL_TRACE("deleteMarks"); + lcl_DebugMarks(m_vMarks); +#endif + } + + void MarkManager::deleteMark(const const_iterator_t ppMark) + { + if(ppMark == m_vMarks.end()) return; + + switch(IDocumentMarkAccess::GetType(**ppMark)) + { + case IDocumentMarkAccess::BOOKMARK: + case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK: + case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK: + // if(dynamic_cast<IBookmark*>) + { + IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark); + OSL_ENSURE(ppBookmark != m_vBookmarks.end(), + "<MarkManager::deleteMark(..)>" + " - Bookmark not found."); + m_vBookmarks.erase(ppBookmark); + break; + } + case IDocumentMarkAccess::TEXT_FIELDMARK: + case IDocumentMarkAccess::CHECKBOX_FIELDMARK: + // if(dynamic_cast<IFieldmark*> + { + IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark); + OSL_ENSURE(ppFieldmark != m_vFieldmarks.end(), + "<MarkManager::deleteMark(..)>" + " - Bookmark not found."); + m_vFieldmarks.erase(ppFieldmark); + break; + } + case IDocumentMarkAccess::NAVIGATOR_REMINDER: + case IDocumentMarkAccess::DDE_BOOKMARK: + case IDocumentMarkAccess::UNO_BOOKMARK: + // no special array for these + break; + } + DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get()); + if(pDdeBookmark) + pDdeBookmark->DeregisterFromDoc(m_pDoc); + m_vMarks.erase(m_vMarks.begin() + (ppMark - m_vMarks.begin())); // clumsy const-cast + } + + void MarkManager::deleteMark(const IMark* const pMark) + { + OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc, + "<MarkManager::repositionMark(..)>" + " - Mark is not in my doc."); + // finds the last Mark that is starting before pMark + // (pMarkLow < pMark) + iterator_t pMarkLow = lower_bound( + m_vMarks.begin(), m_vMarks.end(), + pMark->GetMarkStart(), + bind(&IMark::StartsBefore, _1, _2)); + // finds the first Mark that pMark is starting before + // (pMark < pMarkHigh) + //iterator_t pMarkHigh = upper_bound( + // pMarkLow, m_vMarks.end(), + // pMark->GetMarkStart(), + // bind(&IMark::StartsBefore, _2, _1)); + // since it should be rare that pMark isnt found at all + // we skip the bisect search on the upper bound + iterator_t pMarkHigh = m_vMarks.end(); + iterator_t pMarkFound = find_if( + pMarkLow, pMarkHigh, + bind(equal_to<const IMark*>(), bind(&shared_ptr<IMark>::get, _1), pMark)); + if(pMarkFound != pMarkHigh) + deleteMark(pMarkFound); + } + + void MarkManager::clearAllMarks() + { + m_vFieldmarks.clear(); + m_vBookmarks.clear(); +#ifdef DEBUG + for(iterator_t pBkmk = m_vMarks.begin(); + pBkmk != m_vMarks.end(); + ++pBkmk) + OSL_ENSURE(pBkmk->unique(), + "<MarkManager::clearAllMarks(..)>" + " - a Bookmark is still in use."); +#endif + m_vMarks.clear(); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const ::rtl::OUString& rName) const + { + return lcl_FindMarkByName(rName, m_vMarks.begin(), m_vMarks.end()); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const ::rtl::OUString& rName) const + { + return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end()); + } + + IDocumentMarkAccess::const_iterator_t MarkManager::getMarksBegin() const + { return m_vMarks.begin(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getMarksEnd() const + { return m_vMarks.end(); } + + sal_Int32 MarkManager::getMarksCount() const + { return m_vMarks.size(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const + { return m_vBookmarks.begin(); } + + IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const + { return m_vBookmarks.end(); } + + sal_Int32 MarkManager::getBookmarksCount() const + { return m_vBookmarks.size(); } + + IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const + { + const_iterator_t pFieldmark = find_if( + m_vFieldmarks.begin(), + m_vFieldmarks.end( ), + bind(&IMark::IsCoveringPosition, _1, rPos)); + if(pFieldmark == m_vFieldmarks.end()) return NULL; + return dynamic_cast<IFieldmark*>(pFieldmark->get()); + } + + IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const + { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); } + + IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const + { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); } + + ::rtl::OUString MarkManager::getUniqueMarkName(const ::rtl::OUString& rName) const + { + OSL_ENSURE(rName.getLength(), + "<MarkManager::getUniqueMarkName(..)>" + " - a name should be proposed"); + if(findMark(rName) == getMarksEnd()) return rName; + ::rtl::OUStringBuffer sBuf; + ::rtl::OUString sTmp; + for(sal_Int32 nCnt = 1; nCnt < SAL_MAX_INT32; nCnt++) + { + sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear(); + if(findMark(sTmp) == getMarksEnd()) break; + } + return sTmp; + } + + void MarkManager::sortMarks() + { + sort(m_vMarks.begin(), m_vMarks.end(), &lcl_MarkOrderingByStart); + sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart); + sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart); + } + +}} // namespace ::sw::mark + + +// old implementation + +//SV_IMPL_OP_PTRARR_SORT(SwBookmarks, SwBookmarkPtr) + +#define PCURCRSR (_pCurrCrsr) +#define FOREACHPAM_START(pSttCrsr) \ + {\ + SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \ + do { + +#define FOREACHPAM_END() \ + } while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \ + } +#define PCURSH ((SwCrsrShell*)_pStartShell) +#define FOREACHSHELL_START( pEShell ) \ + {\ + ViewShell *_pStartShell = pEShell; \ + do { \ + if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \ + { + +#define FOREACHSHELL_END( pEShell ) \ + } \ + } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \ + } + +namespace +{ + // Aufbau vom Array: 2 longs, + // 1. Long enthaelt Type und Position im DocArray, + // 2. die ContentPosition + // + // CntntType -- + // 0x8000 = Bookmark Pos1 + // 0x8001 = Bookmark Pos2 + // 0x2000 = Absatzgebundener Rahmen + // 0x2001 = Auto-Absatzgebundener Rahmen, der umgehaengt werden soll + // 0x1000 = Redline Mark + // 0x1001 = Redline Point + // 0x0800 = Crsr aus der CrsrShell Mark + // 0x0801 = Crsr aus der CrsrShell Point + // 0x0400 = UnoCrsr Mark + // 0x0401 = UnoCrsr Point + // + + class _SwSaveTypeCountContent + { + union { + struct { sal_uInt16 nType, nCount; } TC; + sal_uLong nTypeCount; + } TYPECOUNT; + xub_StrLen nContent; + + public: + _SwSaveTypeCountContent() { TYPECOUNT.nTypeCount = 0; nContent = 0; } + _SwSaveTypeCountContent( sal_uInt16 nType ) + { + SetTypeAndCount( nType, 0 ); + nContent = 0; + } + _SwSaveTypeCountContent( const SvULongs& rArr, sal_uInt16& rPos ) + { + TYPECOUNT.nTypeCount = rArr[ rPos++ ]; + nContent = static_cast<xub_StrLen>(rArr[ rPos++ ]); + } + void Add( SvULongs& rArr ) + { + rArr.Insert( TYPECOUNT.nTypeCount, rArr.Count() ); + rArr.Insert( nContent, rArr.Count() ); + } + + void SetType( sal_uInt16 n ) { TYPECOUNT.TC.nType = n; } + sal_uInt16 GetType() const { return TYPECOUNT.TC.nType; } + void IncType() { ++TYPECOUNT.TC.nType; } + void DecType() { --TYPECOUNT.TC.nType; } + + void SetCount( sal_uInt16 n ) { TYPECOUNT.TC.nCount = n; } + sal_uInt16 GetCount() const { return TYPECOUNT.TC.nCount; } + sal_uInt16 IncCount() { return ++TYPECOUNT.TC.nCount; } + sal_uInt16 DecCount() { return --TYPECOUNT.TC.nCount; } + + void SetTypeAndCount( sal_uInt16 nT, sal_uInt16 nC ) + { TYPECOUNT.TC.nCount = nC; TYPECOUNT.TC.nType = nT; } + + void SetContent( xub_StrLen n ) { nContent = n; } + xub_StrLen GetContent() const { return nContent; } + }; + + // #i59534: If a paragraph will be splitted we have to restore some redline positions + // This help function checks a position compared with a node and an content index + + static const int BEFORE_NODE = 0; // Position before the given node index + static const int BEFORE_SAME_NODE = 1; // Same node index but content index before given content index + static const int SAME_POSITION = 2; // Same node index and samecontent index + static const int BEHIND_SAME_NODE = 3; // Same node index but content index behind given content index + static const int BEHIND_NODE = 4; // Position behind the given node index + + static int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, xub_StrLen nCntnt ) + { + sal_uLong nIndex = rPos.nNode.GetIndex(); + int nReturn = BEFORE_NODE; + if( nIndex == nNode ) + { + xub_StrLen nCntIdx = rPos.nContent.GetIndex(); + if( nCntIdx < nCntnt ) + nReturn = BEFORE_SAME_NODE; + else if( nCntIdx == nCntnt ) + nReturn = SAME_POSITION; + else + nReturn = BEHIND_SAME_NODE; + } + else if( nIndex > nNode ) + nReturn = BEHIND_NODE; + return nReturn; + } + + + static inline int lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx ) + { + return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() ); + } + + static void lcl_ChkPaM( SvULongs& rSaveArr, sal_uLong nNode, xub_StrLen nCntnt, + const SwPaM& rPam, _SwSaveTypeCountContent& rSave, + sal_Bool bChkSelDirection ) + { + // SelektionsRichtung beachten + bool bBound1IsStart = !bChkSelDirection ? sal_True : + ( *rPam.GetPoint() < *rPam.GetMark() + ? rPam.GetPoint() == &rPam.GetBound() + : rPam.GetMark() == &rPam.GetBound()); + + const SwPosition* pPos = &rPam.GetBound( sal_True ); + if( pPos->nNode.GetIndex() == nNode && + ( bBound1IsStart ? pPos->nContent.GetIndex() < nCntnt + : pPos->nContent.GetIndex() <= nCntnt )) + { + rSave.SetContent( pPos->nContent.GetIndex() ); + rSave.Add( rSaveArr ); + } + + pPos = &rPam.GetBound( sal_False ); + if( pPos->nNode.GetIndex() == nNode && + ( (bBound1IsStart && bChkSelDirection) + ? pPos->nContent.GetIndex() <= nCntnt + : pPos->nContent.GetIndex() < nCntnt )) + { + rSave.SetContent( pPos->nContent.GetIndex() ); + rSave.IncType(); + rSave.Add( rSaveArr ); + rSave.DecType(); + } + } + +} + + +// IDocumentMarkAccess for SwDoc + +IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() + { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } + +const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const + { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); } + +// SaveBookmark + +SaveBookmark::SaveBookmark( + bool bSavePos, + bool bSaveOtherPos, + const IMark& rBkmk, + const SwNodeIndex & rMvPos, + const SwIndex* pIdx) + : m_aName(rBkmk.GetName()) + , m_aShortName() + , m_aCode() + , m_bSavePos(bSavePos) + , m_bSaveOtherPos(bSaveOtherPos) + , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk)) +{ + const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk); + if(pBookmark) + { + m_aShortName = pBookmark->GetShortName(); + m_aCode = pBookmark->GetKeyCode(); + + ::sfx2::Metadatable const*const pMetadatable( + dynamic_cast< ::sfx2::Metadatable const* >(pBookmark)); + if (pMetadatable) + { + m_pMetadataUndo = pMetadatable->CreateUndo(); + } + } + m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex(); + m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex(); + + if(m_bSavePos) + { + m_nNode1 -= rMvPos.GetIndex(); + if(pIdx && !m_nNode1) + m_nCntnt1 -= pIdx->GetIndex(); + } + + if(rBkmk.IsExpanded()) + { + m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex(); + m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex(); + + if(m_bSaveOtherPos) + { + m_nNode2 -= rMvPos.GetIndex(); + if(pIdx && !m_nNode2) + m_nCntnt2 -= pIdx->GetIndex(); + } + } + else + m_nNode2 = ULONG_MAX, m_nCntnt2 = STRING_NOTFOUND; +} + +void SaveBookmark::SetInDoc( + SwDoc* pDoc, + const SwNodeIndex& rNewPos, + const SwIndex* pIdx) +{ + SwPaM aPam(rNewPos.GetNode()); + if(pIdx) + aPam.GetPoint()->nContent = *pIdx; + + if(ULONG_MAX != m_nNode2) + { + aPam.SetMark(); + + if(m_bSaveOtherPos) + { + aPam.GetMark()->nNode += m_nNode2; + if(pIdx && !m_nNode2) + aPam.GetMark()->nContent += m_nCntnt2; + else + aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2); + } + else + { + aPam.GetMark()->nNode = m_nNode2; + aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2); + } + } + + if(m_bSavePos) + { + aPam.GetPoint()->nNode += m_nNode1; + + if(pIdx && !m_nNode1) + aPam.GetPoint()->nContent += m_nCntnt1; + else + aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); + } + else + { + aPam.GetPoint()->nNode = m_nNode1; + aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1); + } + + if(!aPam.HasMark() + || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, sal_True)) + { + ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType)); + if(pBookmark) + { + pBookmark->SetKeyCode(m_aCode); + pBookmark->SetShortName(m_aShortName); + if (m_pMetadataUndo) + { + ::sfx2::Metadatable * const pMeta( + dynamic_cast< ::sfx2::Metadatable* >(pBookmark)); + OSL_ENSURE(pMeta, "metadata undo, but not metadatable?"); + if (pMeta) + { + pMeta->RestoreMetadata(m_pMetadataUndo); + } + } + } + } +} + +// _DelBookmarks, _{Save,Restore}CntntIdx + +void _DelBookmarks( + const SwNodeIndex& rStt, + const SwNodeIndex& rEnd, + ::std::vector<SaveBookmark> * pSaveBkmk, + const SwIndex* pSttIdx, + const SwIndex* pEndIdx) +{ + // illegal range ?? + if(rStt.GetIndex() > rEnd.GetIndex() + || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex()))) + return; + SwDoc* const pDoc = rStt.GetNode().GetDoc(); + + pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx); + + // kopiere alle Redlines, die im Move Bereich stehen in ein + // Array, das alle Angaben auf die Position als Offset speichert. + // Die neue Zuordung erfolgt nach dem Moven. + SwRedlineTbl& rTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl(); + for(sal_uInt16 nCnt = 0; nCnt < rTbl.Count(); ++nCnt ) + { + // liegt auf der Position ?? + SwRedline* pRedl = rTbl[ nCnt ]; + + SwPosition *pRStt = &pRedl->GetBound(sal_True), + *pREnd = &pRedl->GetBound(sal_False); + if( *pRStt > *pREnd ) + { + SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp; + } + + if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx )) + { + pRStt->nNode = rEnd; + if( pEndIdx ) + pRStt->nContent = *pEndIdx; + else + { + sal_Bool bStt = sal_True; + SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) ) + { + bStt = sal_False; + pRStt->nNode = rStt; + if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) ) + { + pRStt->nNode = pREnd->nNode; + pCNd = pRStt->nNode.GetNode().GetCntntNode(); + } + } + xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); + pRStt->nContent.Assign( pCNd, nTmp ); + } + } + if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx )) + { + pREnd->nNode = rStt; + if( pSttIdx ) + pREnd->nContent = *pSttIdx; + else + { + sal_Bool bStt = sal_False; + SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode(); + if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) ) + { + bStt = sal_True; + pREnd->nNode = rEnd; + if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) ) + { + pREnd->nNode = pRStt->nNode; + pCNd = pREnd->nNode.GetNode().GetCntntNode(); + } + } + xub_StrLen nTmp = bStt ? 0 : pCNd->Len(); + pREnd->nContent.Assign( pCNd, nTmp ); + } + } + } +} + +void _SaveCntntIdx(SwDoc* pDoc, + sal_uLong nNode, + xub_StrLen nCntnt, + SvULongs& rSaveArr, + sal_uInt8 nSaveFly) +{ + // 1. Bookmarks + _SwSaveTypeCountContent aSave; + aSave.SetTypeAndCount( 0x8000, 0 ); + + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + const sal_Int32 nBkmks = pMarkAccess->getMarksCount(); + for(; aSave.GetCount() < nBkmks; aSave.IncCount()) + { + bool bEqual = false; + bool bLower = false; + const ::sw::mark::IMark* pBkmk = (pMarkAccess->getMarksBegin() + aSave.GetCount())->get(); + if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode + && pBkmk->GetMarkPos().nContent.GetIndex() <= nCntnt) + { + if(pBkmk->GetMarkPos().nContent.GetIndex() < nCntnt) + { + bLower = true; // a hint for the other position... + aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); + aSave.Add(rSaveArr); + } + else // if a bookmark position is equal nCntnt, the other position + bEqual = true; // has to decide if it is added to the array + } + + if(pBkmk->IsExpanded() + && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode + && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nCntnt) + { + if(bLower || pBkmk->GetOtherMarkPos().nContent.GetIndex() < nCntnt) + { + if(bEqual) + { // the other position is before, the (main) position is equal + aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex()); + aSave.Add(rSaveArr); + } + aSave.SetContent(pBkmk->GetOtherMarkPos().nContent.GetIndex()); + aSave.IncType(); + aSave.Add(rSaveArr); + aSave.DecType(); + } + } + } + + // 2. Redlines + aSave.SetTypeAndCount( 0x1000, 0 ); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + for( ; aSave.GetCount() < rRedlTbl.Count(); aSave.IncCount() ) + { + const SwRedline* pRdl = rRedlTbl[ aSave.GetCount() ]; + int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nCntnt ); + int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nCntnt ) : + nPointPos; + // #i59534: We have to store the positions inside the same node before the insert position + // and the one at the insert position if the corresponding Point/Mark position is before + // the insert position. + if( nPointPos == BEFORE_SAME_NODE || + ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) ) + { + aSave.SetContent( pRdl->GetPoint()->nContent.GetIndex() ); + aSave.IncType(); + aSave.Add( rSaveArr ); + aSave.DecType(); + } + if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE || + ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) ) + { + aSave.SetContent( pRdl->GetMark()->nContent.GetIndex() ); + aSave.Add( rSaveArr ); + } + } + + // 4. Absatzgebundene Objekte + { + SwCntntNode *pNode = pDoc->GetNodes()[nNode]->GetCntntNode(); + if( pNode ) + { + + SwFrm* pFrm = pNode->GetFrm(); +#if OSL_DEBUG_LEVEL > 1 + static sal_Bool bViaDoc = sal_False; + if( bViaDoc ) + pFrm = NULL; +#endif + if( pFrm ) // gibt es ein Layout? Dann ist etwas billiger... + { + if( pFrm->GetDrawObjs() ) + { + const SwSortedObjs& rDObj = *pFrm->GetDrawObjs(); + for( sal_uInt32 n = rDObj.Count(); n; ) + { + SwAnchoredObject* pObj = rDObj[ --n ]; + const SwFrmFmt& rFmt = pObj->GetFrmFmt(); + const SwFmtAnchor& rAnchor = rFmt.GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if ( pAPos && + ( ( nSaveFly && + FLY_AT_PARA == rAnchor.GetAnchorId() ) || + ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) ) + { + aSave.SetType( 0x2000 ); + aSave.SetContent( pAPos->nContent.GetIndex() ); + + OSL_ENSURE( nNode == pAPos->nNode.GetIndex(), + "_SaveCntntIdx: Wrong Node-Index" ); + if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) + { + if( nCntnt <= aSave.GetContent() ) + { + if( SAVEFLY_SPLIT == nSaveFly ) + aSave.IncType(); // = 0x2001; + else + continue; + } + } + aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); + while( aSave.GetCount() && + &rFmt != (*pDoc->GetSpzFrmFmts())[ + aSave.DecCount() ] ) + ; // nothing + OSL_ENSURE( &rFmt == (*pDoc->GetSpzFrmFmts())[ + aSave.GetCount() ], + "_SaveCntntIdx: Lost FrameFormat" ); + aSave.Add( rSaveArr ); + } + } + } + } + else // Schade, kein Layout, dann ist es eben etwas teurer... + { + for( aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() ); + aSave.GetCount() ; ) + { + SwFrmFmt* pFrmFmt = (*pDoc->GetSpzFrmFmts())[ + aSave.DecCount() ]; + if ( RES_FLYFRMFMT != pFrmFmt->Which() && + RES_DRAWFRMFMT != pFrmFmt->Which() ) + continue; + + const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) && + ( FLY_AT_PARA == rAnchor.GetAnchorId() || + FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) + { + aSave.SetType( 0x2000 ); + aSave.SetContent( pAPos->nContent.GetIndex() ); + if ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) + { + if( nCntnt <= aSave.GetContent() ) + { + if( SAVEFLY_SPLIT == nSaveFly ) + aSave.IncType(); // = 0x2001; + else + continue; + } + } + aSave.Add( rSaveArr ); + } + } + } + } + } + // 5. CrsrShell + { + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + aSave.SetTypeAndCount( 0x800, 0 ); + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *_pStkCrsr, + aSave, sal_False ); + aSave.IncCount(); + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, + aSave, sal_False ); + aSave.IncCount(); + FOREACHPAM_END() + + FOREACHSHELL_END( pShell ) + } + } + // 6. UnoCrsr + { + aSave.SetTypeAndCount( 0x400, 0 ); + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + FOREACHPAM_START( rTbl[ n ] ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False ); + aSave.IncCount(); + FOREACHPAM_END() + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]); + if( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False ); + aSave.IncCount(); + FOREACHPAM_END() + } + } + } +} + + +void _RestoreCntntIdx(SwDoc* pDoc, + SvULongs& rSaveArr, + sal_uLong nNode, + xub_StrLen nOffset, + sal_Bool bAuto) +{ + SwCntntNode* pCNd = pDoc->GetNodes()[ nNode ]->GetCntntNode(); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); + IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + sal_uInt16 n = 0; + while( n < rSaveArr.Count() ) + { + _SwSaveTypeCountContent aSave( rSaveArr, n ); + SwPosition* pPos = 0; + switch( aSave.GetType() ) + { + case 0x8000: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetMarkPos()); + aNewPos.nNode = *pCNd; + aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); + pMark->SetMarkPos(aNewPos); + } + break; + case 0x8001: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetOtherMarkPos()); + aNewPos.nNode = *pCNd; + aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset); + pMark->SetOtherMarkPos(aNewPos); + } + break; + case 0x1001: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); + break; + case 0x1000: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); + break; + case 0x2000: + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); + if( rFlyAnchor.GetCntntAnchor() ) + { + SwFmtAnchor aNew( rFlyAnchor ); + SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); + aNewPos.nNode = *pCNd; + if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) + { + aNewPos.nContent.Assign( pCNd, + aSave.GetContent() + nOffset ); + } + else + { + aNewPos.nContent.Assign( 0, 0 ); + } + aNew.SetAnchor( &aNewPos ); + pFrmFmt->SetFmtAttr( aNew ); + } + } + break; + case 0x2001: + if( bAuto ) + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + SfxPoolItem *pAnchor = (SfxPoolItem*)&pFrmFmt->GetAnchor(); + pFrmFmt->SwModify::Modify( pAnchor, pAnchor ); + } + break; + + case 0x0800: + case 0x0801: + { + sal_uInt16 nCnt = 0; + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + if( aSave.GetCount() == nCnt ) + { + pPos = &_pStkCrsr->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + if( pPos ) + break; + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + FOREACHSHELL_END( pShell ) + } + } + break; + + case 0x0400: + case 0x0401: + { + sal_uInt16 nCnt = 0; + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) + { + FOREACHPAM_START( rTbl[ i ] ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); + if ( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + } + if ( pPos ) + break; + } + } + break; + } + + if( pPos ) + { + pPos->nNode = *pCNd; + pPos->nContent.Assign( pCNd, aSave.GetContent() + nOffset ); + } + } +} + +void _RestoreCntntIdx(SvULongs& rSaveArr, + const SwNode& rNd, + xub_StrLen nLen, + xub_StrLen nChkLen) +{ + const SwDoc* pDoc = rNd.GetDoc(); + const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl(); + const SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts(); + const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess(); + SwCntntNode* pCNd = (SwCntntNode*)rNd.GetCntntNode(); + + sal_uInt16 n = 0; + while( n < rSaveArr.Count() ) + { + _SwSaveTypeCountContent aSave( rSaveArr, n ); + if( aSave.GetContent() >= nChkLen ) + rSaveArr[ n-1 ] -= nChkLen; + else + { + SwPosition* pPos = 0; + switch( aSave.GetType() ) + { + case 0x8000: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetMarkPos()); + aNewPos.nNode = rNd; + aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); + pMark->SetMarkPos(aNewPos); + } + break; + case 0x8001: + { + MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getMarksBegin()[aSave.GetCount()].get()); + SwPosition aNewPos(pMark->GetOtherMarkPos()); + aNewPos.nNode = rNd; + aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen)); + pMark->SetOtherMarkPos(aNewPos); + } + break; + case 0x1001: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint(); + break; + case 0x1000: + pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark(); + break; + case 0x2000: + case 0x2001: + { + SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ]; + const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor(); + if( rFlyAnchor.GetCntntAnchor() ) + { + SwFmtAnchor aNew( rFlyAnchor ); + SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() ); + aNewPos.nNode = rNd; + if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() ) + { + aNewPos.nContent.Assign( pCNd, Min( + aSave.GetContent(), nLen ) ); + } + else + { + aNewPos.nContent.Assign( 0, 0 ); + } + aNew.SetAnchor( &aNewPos ); + pFrmFmt->SetFmtAttr( aNew ); + } + } + break; + + case 0x0800: + case 0x0801: + { + sal_uInt16 nCnt = 0; + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + if( aSave.GetCount() == nCnt ) + { + pPos = &_pStkCrsr->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + if( pPos ) + break; + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0800 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + FOREACHSHELL_END( pShell ) + } + } + break; + + case 0x0400: + case 0x0401: + { + sal_uInt16 nCnt = 0; + const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl(); + for( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) + { + FOREACHPAM_START( rTbl[ i ] ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + if( pPos ) + break; + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]); + if ( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + if( aSave.GetCount() == nCnt ) + { + pPos = &PCURCRSR->GetBound( 0x0400 == + aSave.GetType() ); + break; + } + ++nCnt; + FOREACHPAM_END() + } + if ( pPos ) + break; + } + } + break; + } + + if( pPos ) + { + pPos->nNode = rNd; + pPos->nContent.Assign( pCNd, Min( aSave.GetContent(), nLen ) ); + } + n -= 2; + rSaveArr.Remove( n, 2 ); + } + } +} diff --git a/sw/source/core/doc/docchart.cxx b/sw/source/core/doc/docchart.cxx new file mode 100644 index 000000000000..1d1890521acf --- /dev/null +++ b/sw/source/core/doc/docchart.cxx @@ -0,0 +1,277 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <com/sun/star/frame/XModel.hpp> + +#include <com/sun/star/chart2/XChartDocument.hpp> + +#include <float.h> +#include <hintids.hxx> +#include <vcl/window.hxx> +#include <doc.hxx> +#include <docary.hxx> +#include <ndindex.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <ndole.hxx> +#include <calc.hxx> +#include <frmfmt.hxx> +#include <cellfml.hxx> +#include <viewsh.hxx> +#include <ndole.hxx> +#include <calbck.hxx> +#include <cntfrm.hxx> +#include <swtblfmt.hxx> +#include <tblsel.hxx> +#include <cellatr.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <unochart.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::uno; + + +void SwTable::UpdateCharts() const +{ + GetFrmFmt()->GetDoc()->UpdateCharts( GetFrmFmt()->GetName() ); +} + +sal_Bool SwTable::IsTblComplexForChart( const String& rSelection, + SwChartLines* pGetCLines ) const +{ + const SwTableBox* pSttBox, *pEndBox; + if( 2 < rSelection.Len() ) + { + // spitze Klammern am Anfang & Ende enfernen + String sBox( rSelection ); + if( '<' == sBox.GetChar( 0 ) ) sBox.Erase( 0, 1 ); + if( '>' == sBox.GetChar( sBox.Len()-1 ) ) sBox.Erase( sBox.Len()-1 ); + + xub_StrLen nTrenner = sBox.Search( ':' ); + ASSERT( STRING_NOTFOUND != nTrenner, "keine gueltige Selektion" ); + + pSttBox = GetTblBox( sBox.Copy( 0, nTrenner )); + pEndBox = GetTblBox( sBox.Copy( nTrenner+1 )); + } + else + { + const SwTableLines* pLns = &GetTabLines(); + pSttBox = (*pLns)[ 0 ]->GetTabBoxes()[ 0 ]; + while( !pSttBox->GetSttNd() ) + // bis zur Content Box! + pSttBox = pSttBox->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ]; + + const SwTableBoxes* pBoxes = &(*pLns)[ pLns->Count()-1 ]->GetTabBoxes(); + pEndBox = (*pBoxes)[ pBoxes->Count()-1 ]; + while( !pEndBox->GetSttNd() ) + { + // bis zur Content Box! + pLns = &pEndBox->GetTabLines(); + pBoxes = &(*pLns)[ pLns->Count()-1 ]->GetTabBoxes(); + pEndBox = (*pBoxes)[ pBoxes->Count()-1 ]; + } + } + + return !pSttBox || !pEndBox || !::ChkChartSel( *pSttBox->GetSttNd(), + *pEndBox->GetSttNd(), pGetCLines ); +} + + + +IMPL_LINK( SwDoc, DoUpdateAllCharts, Timer *, EMPTYARG ) +{ + ViewShell* pVSh; + GetEditShell( &pVSh ); + if( pVSh ) + { + const SwFrmFmts& rTblFmts = *GetTblFrmFmts(); + for( sal_uInt16 n = 0; n < rTblFmts.Count(); ++n ) + { + SwTable* pTmpTbl; + const SwTableNode* pTblNd; + SwFrmFmt* pFmt = rTblFmts[ n ]; + + if( 0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) && + 0 != ( pTblNd = pTmpTbl->GetTableNode() ) && + pTblNd->GetNodes().IsDocNodes() ) + { + _UpdateCharts( *pTmpTbl, *pVSh ); + } + } + } + return 0; +} + +void SwDoc::_UpdateCharts( const SwTable& rTbl, ViewShell& /*rVSh*/ ) const +{ + String aName( rTbl.GetFrmFmt()->GetName() ); + SwOLENode *pONd; + SwStartNode *pStNd; + SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) + { + aIdx++; + SwFrm* pFrm; + if( 0 != ( pONd = aIdx.GetNode().GetOLENode() ) && + aName.Equals( pONd->GetChartTblName() ) && + 0 != ( pFrm = pONd->GetFrm() ) ) + { + SwChartDataProvider *pPCD = GetChartDataProvider(); + if (pPCD) + pPCD->InvalidateTable( &rTbl ); + // following this the framework will now take care of repainting + // the chart or it's replacement image... + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } +} + +void SwDoc::UpdateCharts( const String &rName ) const +{ + SwTable* pTmpTbl = SwTable::FindTable( FindTblFmtByName( rName ) ); + if( pTmpTbl ) + { + ViewShell* pVSh; + GetEditShell( &pVSh ); + + if( pVSh ) + _UpdateCharts( *pTmpTbl, *pVSh ); + } +} + +void SwDoc::SetTableName( SwFrmFmt& rTblFmt, const String &rNewName ) +{ +// sal_Bool bStop = 1; + + const String aOldName( rTblFmt.GetName() ); + + sal_Bool bNameFound = 0 == rNewName.Len(); + if( !bNameFound ) + { + SwFrmFmt* pFmt; + const SwFrmFmts& rTbl = *GetTblFrmFmts(); + for( sal_uInt16 i = rTbl.Count(); i; ) + if( !( pFmt = rTbl[ --i ] )->IsDefault() && + pFmt->GetName() == rNewName && IsUsed( *pFmt ) ) + { + bNameFound = sal_True; + break; + } + } + + if( !bNameFound ) + rTblFmt.SetName( rNewName, sal_True ); + else + rTblFmt.SetName( GetUniqueTblName(), sal_True ); + + SwStartNode *pStNd; + SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while ( 0 != (pStNd = aIdx.GetNode().GetStartNode()) ) + { + aIdx++; + SwOLENode *pNd = aIdx.GetNode().GetOLENode(); + if( pNd && aOldName == pNd->GetChartTblName() ) + { + pNd->SetChartTblName( rNewName ); + + ViewShell* pVSh; + GetEditShell( &pVSh ); + + SwTable* pTable = SwTable::FindTable( &rTblFmt ); + SwChartDataProvider *pPCD = GetChartDataProvider(); + if (pPCD) + pPCD->InvalidateTable( pTable ); + // following this the framework will now take care of repainting + // the chart or it's replacement image... + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } + SetModified(); +} + + +SwChartDataProvider * SwDoc::GetChartDataProvider( bool bCreate ) const +{ + // since there must be only one instance of this object per document + // we need a mutex here + vos::OGuard aGuard( Application::GetSolarMutex() ); + + if (bCreate && !aChartDataProviderImplRef.get()) + { + aChartDataProviderImplRef = comphelper::ImplementationReference< SwChartDataProvider + , chart2::data::XDataProvider >( new SwChartDataProvider( this ) ); + } + return aChartDataProviderImplRef.get(); +} + + +void SwDoc::CreateChartInternalDataProviders( const SwTable *pTable ) +{ + if (pTable) + { + String aName( pTable->GetFrmFmt()->GetName() ); + SwOLENode *pONd; + SwStartNode *pStNd; + SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); + while (0 != (pStNd = aIdx.GetNode().GetStartNode())) + { + aIdx++; + if( 0 != ( pONd = aIdx.GetNode().GetOLENode() ) && + aName.Equals( pONd->GetChartTblName() ) /* OLE node is chart? */ && + 0 != (pONd->GetFrm()) /* chart frame is not hidden */ ) + { + uno::Reference < embed::XEmbeddedObject > xIP = pONd->GetOLEObj().GetOleRef(); + if ( svt::EmbeddedObjectRef::TryRunningState( xIP ) ) + { + uno::Reference< chart2::XChartDocument > xChart( xIP->getComponent(), UNO_QUERY ); + if (xChart.is()) + xChart->createInternalDataProvider( sal_True ); + + // there may be more than one chart for each table thus we need to continue the loop... + } + } + aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); + } + } +} + + +SwChartLockController_Helper & SwDoc::GetChartControllerHelper() +{ + if (!pChartControllerHelper) + { + pChartControllerHelper = new SwChartLockController_Helper( this ); + } + return *pChartControllerHelper; +} + diff --git a/sw/source/core/doc/doccomp.cxx b/sw/source/core/doc/doccomp.cxx new file mode 100644 index 000000000000..e0c550dff020 --- /dev/null +++ b/sw/source/core/doc/doccomp.cxx @@ -0,0 +1,1883 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <tools/list.hxx> +#include <vcl/vclenum.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/udlnitem.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <redline.hxx> +#include <UndoRedline.hxx> +#include <section.hxx> +#include <tox.hxx> +#include <docsh.hxx> + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +using namespace ::com::sun::star; + + +class CompareLine +{ +public: + CompareLine() {} + virtual ~CompareLine(); + + virtual sal_uLong GetHashValue() const = 0; + virtual sal_Bool Compare( const CompareLine& rLine ) const = 0; +}; + +DECLARE_LIST( CompareList, CompareLine* ) + +class CompareData +{ + sal_uLong* pIndex; + sal_Bool* pChangedFlag; + +protected: + CompareList aLines; + sal_uLong nSttLineNum; + + // Anfang und Ende beschneiden und alle anderen in das + // LinesArray setzen + virtual void CheckRanges( CompareData& ) = 0; + +public: + CompareData(); + virtual ~CompareData(); + + // gibt es unterschiede? + sal_Bool HasDiffs( const CompareData& rData ) const; + + // startet das Vergleichen und Erzeugen der Unterschiede zweier + // Dokumente + void CompareLines( CompareData& rData ); + // lasse die Unterschiede anzeigen - ruft die beiden Methoden + // ShowInsert / ShowDelete. Diese bekommen die Start und EndLine-Nummer + // uebergeben. Die Abbildung auf den tatsaechline Inhalt muss die + // Ableitung uebernehmen! + sal_uLong ShowDiffs( const CompareData& rData ); + + virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd ); + virtual void ShowDelete( const CompareData& rData, sal_uLong nStt, + sal_uLong nEnd, sal_uLong nInsPos ); + virtual void CheckForChangesInLine( const CompareData& rData, + sal_uLong& nStt, sal_uLong& nEnd, + sal_uLong& nThisStt, sal_uLong& nThisEnd ); + + // Eindeutigen Index fuer eine Line setzen. Gleiche Lines haben den + // selben Index; auch in den anderen CompareData! + void SetIndex( sal_uLong nLine, sal_uLong nIndex ); + sal_uLong GetIndex( sal_uLong nLine ) const + { return nLine < aLines.Count() ? pIndex[ nLine ] : 0; } + + // setze/erfrage ob eine Zeile veraendert ist + void SetChanged( sal_uLong nLine, sal_Bool bFlag = sal_True ); + sal_Bool GetChanged( sal_uLong nLine ) const + { + return (pChangedFlag && nLine < aLines.Count()) + ? pChangedFlag[ nLine ] + : 0; + } + + sal_uLong GetLineCount() const { return aLines.Count(); } + sal_uLong GetLineOffset() const { return nSttLineNum; } + const CompareLine* GetLine( sal_uLong nLine ) const + { return aLines.GetObject( nLine ); } + void InsertLine( CompareLine* pLine ) + { aLines.Insert( pLine, LIST_APPEND ); } +}; + +class Hash +{ + struct _HashData + { + sal_uLong nNext, nHash; + const CompareLine* pLine; + + _HashData() + : nNext( 0 ), nHash( 0 ), pLine(0) {} + }; + + sal_uLong* pHashArr; + _HashData* pDataArr; + sal_uLong nCount, nPrime; + +public: + Hash( sal_uLong nSize ); + ~Hash(); + + void CalcHashValue( CompareData& rData ); + + sal_uLong GetCount() const { return nCount; } +}; + +class Compare +{ +public: + class MovedData + { + sal_uLong* pIndex; + sal_uLong* pLineNum; + sal_uLong nCount; + + public: + MovedData( CompareData& rData, sal_Char* pDiscard ); + ~MovedData(); + + sal_uLong GetIndex( sal_uLong n ) const { return pIndex[ n ]; } + sal_uLong GetLineNum( sal_uLong n ) const { return pLineNum[ n ]; } + sal_uLong GetCount() const { return nCount; } + }; + +private: + // Suche die verschobenen Lines + class CompareSequence + { + CompareData &rData1, &rData2; + const MovedData &rMoved1, &rMoved2; + long *pMemory, *pFDiag, *pBDiag; + + void Compare( sal_uLong nStt1, sal_uLong nEnd1, sal_uLong nStt2, sal_uLong nEnd2 ); + sal_uLong CheckDiag( sal_uLong nStt1, sal_uLong nEnd1, + sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost ); + public: + CompareSequence( CompareData& rData1, CompareData& rData2, + const MovedData& rD1, const MovedData& rD2 ); + ~CompareSequence(); + }; + + + static void CountDifference( const CompareData& rData, sal_uLong* pCounts ); + static void SetDiscard( const CompareData& rData, + sal_Char* pDiscard, sal_uLong* pCounts ); + static void CheckDiscard( sal_uLong nLen, sal_Char* pDiscard ); + static sal_uLong SetChangedFlag( CompareData& rData, sal_Char* pDiscard, int bFirst ); + static void ShiftBoundaries( CompareData& rData1, CompareData& rData2 ); + +public: + Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 ); +}; + +// ==================================================================== + +CompareLine::~CompareLine() {} + +// ---------------------------------------------------------------------- + +CompareData::CompareData() + : pIndex( 0 ), pChangedFlag( 0 ), nSttLineNum( 0 ) +{ +} + +CompareData::~CompareData() +{ + delete[] pIndex; + delete[] pChangedFlag; +} + +void CompareData::SetIndex( sal_uLong nLine, sal_uLong nIndex ) +{ + if( !pIndex ) + { + pIndex = new sal_uLong[ aLines.Count() ]; + memset( pIndex, 0, aLines.Count() * sizeof( sal_uLong ) ); + } + if( nLine < aLines.Count() ) + pIndex[ nLine ] = nIndex; +} + +void CompareData::SetChanged( sal_uLong nLine, sal_Bool bFlag ) +{ + if( !pChangedFlag ) + { + pChangedFlag = new sal_Bool[ aLines.Count() +1 ]; + memset( pChangedFlag, 0, aLines.Count() +1 * sizeof( sal_Bool ) ); + } + if( nLine < aLines.Count() ) + pChangedFlag[ nLine ] = bFlag; +} + +void CompareData::CompareLines( CompareData& rData ) +{ + CheckRanges( rData ); + + sal_uLong nDifferent; + { + Hash aH( GetLineCount() + rData.GetLineCount() + 1 ); + aH.CalcHashValue( *this ); + aH.CalcHashValue( rData ); + nDifferent = aH.GetCount(); + } + { + Compare aComp( nDifferent, *this, rData ); + } +} + +sal_uLong CompareData::ShowDiffs( const CompareData& rData ) +{ + sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount(); + sal_uLong nStt1 = 0, nStt2 = 0; + sal_uLong nCnt = 0; + + while( nStt1 < nLen1 || nStt2 < nLen2 ) + { + if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) ) + { + sal_uLong nSav1 = nStt1, nSav2 = nStt2; + while( nStt1 < nLen1 && rData.GetChanged( nStt1 )) ++nStt1; + while( nStt2 < nLen2 && GetChanged( nStt2 )) ++nStt2; + + // rData ist das Original, + // this ist das, in das die Veraenderungen sollen + if( nSav2 != nStt2 && nSav1 != nStt1 ) + CheckForChangesInLine( rData, nSav1, nStt1, nSav2, nStt2 ); + + if( nSav2 != nStt2 ) + ShowInsert( nSav2, nStt2 ); + + if( nSav1 != nStt1 ) + ShowDelete( rData, nSav1, nStt1, nStt2 ); + ++nCnt; + } + ++nStt1, ++nStt2; + } + return nCnt; +} + +sal_Bool CompareData::HasDiffs( const CompareData& rData ) const +{ + sal_Bool bRet = sal_False; + sal_uLong nLen1 = rData.GetLineCount(), nLen2 = GetLineCount(); + sal_uLong nStt1 = 0, nStt2 = 0; + + while( nStt1 < nLen1 || nStt2 < nLen2 ) + { + if( rData.GetChanged( nStt1 ) || GetChanged( nStt2 ) ) + { + bRet = sal_True; + break; + } + ++nStt1, ++nStt2; + } + return bRet; +} + +void CompareData::ShowInsert( sal_uLong, sal_uLong ) +{ +} + +void CompareData::ShowDelete( const CompareData&, sal_uLong, sal_uLong, sal_uLong ) +{ +} + +void CompareData::CheckForChangesInLine( const CompareData& , + sal_uLong&, sal_uLong&, sal_uLong&, sal_uLong& ) +{ +} + +// ---------------------------------------------------------------------- + +Hash::Hash( sal_uLong nSize ) + : nCount( 1 ) +{ + +static const sal_uLong primes[] = +{ + 509, + 1021, + 2039, + 4093, + 8191, + 16381, + 32749, + 65521, + 131071, + 262139, + 524287, + 1048573, + 2097143, + 4194301, + 8388593, + 16777213, + 33554393, + 67108859, /* Preposterously large . . . */ + 134217689, + 268435399, + 536870909, + 1073741789, + 2147483647, + 0 +}; + int i; + + pDataArr = new _HashData[ nSize ]; + pDataArr[0].nNext = 0; + pDataArr[0].nHash = 0, + pDataArr[0].pLine = 0; + + for( i = 0; primes[i] < nSize / 3; i++) + if( !primes[i] ) + { + pHashArr = 0; + return; + } + nPrime = primes[ i ]; + pHashArr = new sal_uLong[ nPrime ]; + memset( pHashArr, 0, nPrime * sizeof( sal_uLong ) ); +} + +Hash::~Hash() +{ + delete[] pHashArr; + delete[] pDataArr; +} + +void Hash::CalcHashValue( CompareData& rData ) +{ + if( pHashArr ) + { + for( sal_uLong n = 0; n < rData.GetLineCount(); ++n ) + { + const CompareLine* pLine = rData.GetLine( n ); + ASSERT( pLine, "wo ist die Line?" ); + sal_uLong nH = pLine->GetHashValue(); + + sal_uLong* pFound = &pHashArr[ nH % nPrime ]; + sal_uLong i; + for( i = *pFound; ; i = pDataArr[i].nNext ) + if( !i ) + { + i = nCount++; + pDataArr[i].nNext = *pFound; + pDataArr[i].nHash = nH; + pDataArr[i].pLine = pLine; + *pFound = i; + break; + } + else if( pDataArr[i].nHash == nH && + pDataArr[i].pLine->Compare( *pLine )) + break; + + rData.SetIndex( n, i ); + } + } +} + +// ---------------------------------------------------------------------- + +Compare::Compare( sal_uLong nDiff, CompareData& rData1, CompareData& rData2 ) +{ + MovedData *pMD1, *pMD2; + // Suche die unterschiedlichen Lines + { + sal_Char* pDiscard1 = new sal_Char[ rData1.GetLineCount() ]; + sal_Char* pDiscard2 = new sal_Char[ rData2.GetLineCount() ]; + + sal_uLong* pCount1 = new sal_uLong[ nDiff ]; + sal_uLong* pCount2 = new sal_uLong[ nDiff ]; + memset( pCount1, 0, nDiff * sizeof( sal_uLong )); + memset( pCount2, 0, nDiff * sizeof( sal_uLong )); + + // stelle fest, welche Indizies in den CompareData mehrfach vergeben wurden + CountDifference( rData1, pCount1 ); + CountDifference( rData2, pCount2 ); + + // alle die jetzt nur einmal vorhanden sind, sind eingefuegt oder + // geloescht worden. Alle die im anderen auch vorhanden sind, sind + // verschoben worden + SetDiscard( rData1, pDiscard1, pCount2 ); + SetDiscard( rData2, pDiscard2, pCount1 ); + + // die Arrays koennen wir wieder vergessen + delete [] pCount1; delete [] pCount2; + + CheckDiscard( rData1.GetLineCount(), pDiscard1 ); + CheckDiscard( rData2.GetLineCount(), pDiscard2 ); + + pMD1 = new MovedData( rData1, pDiscard1 ); + pMD2 = new MovedData( rData2, pDiscard2 ); + + // die Arrays koennen wir wieder vergessen + delete [] pDiscard1; delete [] pDiscard2; + } + + { + CompareSequence aTmp( rData1, rData2, *pMD1, *pMD2 ); + } + + ShiftBoundaries( rData1, rData2 ); + + delete pMD1; + delete pMD2; +} + + + +void Compare::CountDifference( const CompareData& rData, sal_uLong* pCounts ) +{ + sal_uLong nLen = rData.GetLineCount(); + for( sal_uLong n = 0; n < nLen; ++n ) + { + sal_uLong nIdx = rData.GetIndex( n ); + ++pCounts[ nIdx ]; + } +} + +void Compare::SetDiscard( const CompareData& rData, + sal_Char* pDiscard, sal_uLong* pCounts ) +{ + sal_uLong nLen = rData.GetLineCount(); + + // berechne Max in Abhanegigkeit zur LineAnzahl + sal_uInt16 nMax = 5; + sal_uLong n; + + for( n = nLen / 64; ( n = n >> 2 ) > 0; ) + nMax <<= 1; + + for( n = 0; n < nLen; ++n ) + { + sal_uLong nIdx = rData.GetIndex( n ); + if( nIdx ) + { + nIdx = pCounts[ nIdx ]; + pDiscard[ n ] = !nIdx ? 1 : nIdx > nMax ? 2 : 0; + } + else + pDiscard[ n ] = 0; + } +} + +void Compare::CheckDiscard( sal_uLong nLen, sal_Char* pDiscard ) +{ + for( sal_uLong n = 0; n < nLen; ++n ) + { + if( 2 == pDiscard[ n ] ) + pDiscard[n] = 0; + else if( pDiscard[ n ] ) + { + sal_uLong j; + sal_uLong length; + sal_uLong provisional = 0; + + /* Find end of this run of discardable lines. + Count how many are provisionally discardable. */ + for (j = n; j < nLen; j++) + { + if( !pDiscard[j] ) + break; + if( 2 == pDiscard[j] ) + ++provisional; + } + + /* Cancel provisional discards at end, and shrink the run. */ + while( j > n && 2 == pDiscard[j - 1] ) + pDiscard[ --j ] = 0, --provisional; + + /* Now we have the length of a run of discardable lines + whose first and last are not provisional. */ + length = j - n; + + /* If 1/4 of the lines in the run are provisional, + cancel discarding of all provisional lines in the run. */ + if (provisional * 4 > length) + { + while (j > n) + if (pDiscard[--j] == 2) + pDiscard[j] = 0; + } + else + { + sal_uLong consec; + sal_uLong minimum = 1; + sal_uLong tem = length / 4; + + /* MINIMUM is approximate square root of LENGTH/4. + A subrun of two or more provisionals can stand + when LENGTH is at least 16. + A subrun of 4 or more can stand when LENGTH >= 64. */ + while ((tem = tem >> 2) > 0) + minimum *= 2; + minimum++; + + /* Cancel any subrun of MINIMUM or more provisionals + within the larger run. */ + for (j = 0, consec = 0; j < length; j++) + if (pDiscard[n + j] != 2) + consec = 0; + else if (minimum == ++consec) + /* Back up to start of subrun, to cancel it all. */ + j -= consec; + else if (minimum < consec) + pDiscard[n + j] = 0; + + /* Scan from beginning of run + until we find 3 or more nonprovisionals in a row + or until the first nonprovisional at least 8 lines in. + Until that point, cancel any provisionals. */ + for (j = 0, consec = 0; j < length; j++) + { + if (j >= 8 && pDiscard[n + j] == 1) + break; + if (pDiscard[n + j] == 2) + consec = 0, pDiscard[n + j] = 0; + else if (pDiscard[n + j] == 0) + consec = 0; + else + consec++; + if (consec == 3) + break; + } + + /* I advances to the last line of the run. */ + n += length - 1; + + /* Same thing, from end. */ + for (j = 0, consec = 0; j < length; j++) + { + if (j >= 8 && pDiscard[n - j] == 1) + break; + if (pDiscard[n - j] == 2) + consec = 0, pDiscard[n - j] = 0; + else if (pDiscard[n - j] == 0) + consec = 0; + else + consec++; + if (consec == 3) + break; + } + } + } + } +} + +// ---------------------------------------------------------------------- + +Compare::MovedData::MovedData( CompareData& rData, sal_Char* pDiscard ) + : pIndex( 0 ), pLineNum( 0 ), nCount( 0 ) +{ + sal_uLong nLen = rData.GetLineCount(); + sal_uLong n; + + for( n = 0; n < nLen; ++n ) + if( pDiscard[ n ] ) + rData.SetChanged( n ); + else + ++nCount; + + if( nCount ) + { + pIndex = new sal_uLong[ nCount ]; + pLineNum = new sal_uLong[ nCount ]; + + for( n = 0, nCount = 0; n < nLen; ++n ) + if( !pDiscard[ n ] ) + { + pIndex[ nCount ] = rData.GetIndex( n ); + pLineNum[ nCount++ ] = n; + } + } +} + +Compare::MovedData::~MovedData() +{ + delete pIndex; + delete pLineNum; +} + +// ---------------------------------------------------------------------- + + // Suche die verschobenen Lines +Compare::CompareSequence::CompareSequence( + CompareData& rD1, CompareData& rD2, + const MovedData& rMD1, const MovedData& rMD2 ) + : rData1( rD1 ), rData2( rD2 ), rMoved1( rMD1 ), rMoved2( rMD2 ) +{ + sal_uLong nSize = rMD1.GetCount() + rMD2.GetCount() + 3; + pMemory = new long[ nSize * 2 ]; + pFDiag = pMemory + ( rMD2.GetCount() + 1 ); + pBDiag = pMemory + ( nSize + rMD2.GetCount() + 1 ); + + Compare( 0, rMD1.GetCount(), 0, rMD2.GetCount() ); +} + +Compare::CompareSequence::~CompareSequence() +{ + delete pMemory; +} + +void Compare::CompareSequence::Compare( sal_uLong nStt1, sal_uLong nEnd1, + sal_uLong nStt2, sal_uLong nEnd2 ) +{ + /* Slide down the bottom initial diagonal. */ + while( nStt1 < nEnd1 && nStt2 < nEnd2 && + rMoved1.GetIndex( nStt1 ) == rMoved2.GetIndex( nStt2 )) + ++nStt1, ++nStt2; + + /* Slide up the top initial diagonal. */ + while( nEnd1 > nStt1 && nEnd2 > nStt2 && + rMoved1.GetIndex( nEnd1 - 1 ) == rMoved2.GetIndex( nEnd2 - 1 )) + --nEnd1, --nEnd2; + + /* Handle simple cases. */ + if( nStt1 == nEnd1 ) + while( nStt2 < nEnd2 ) + rData2.SetChanged( rMoved2.GetLineNum( nStt2++ )); + + else if (nStt2 == nEnd2) + while (nStt1 < nEnd1) + rData1.SetChanged( rMoved1.GetLineNum( nStt1++ )); + + else + { + sal_uLong c, d, b; + + /* Find a point of correspondence in the middle of the files. */ + + d = CheckDiag( nStt1, nEnd1, nStt2, nEnd2, &c ); + b = pBDiag[ d ]; + + if( 1 != c ) + { + /* Use that point to split this problem into two subproblems. */ + Compare( nStt1, b, nStt2, b - d ); + /* This used to use f instead of b, + but that is incorrect! + It is not necessarily the case that diagonal d + has a snake from b to f. */ + Compare( b, nEnd1, b - d, nEnd2 ); + } + } +} + +sal_uLong Compare::CompareSequence::CheckDiag( sal_uLong nStt1, sal_uLong nEnd1, + sal_uLong nStt2, sal_uLong nEnd2, sal_uLong* pCost ) +{ + const long dmin = nStt1 - nEnd2; /* Minimum valid diagonal. */ + const long dmax = nEnd1 - nStt2; /* Maximum valid diagonal. */ + const long fmid = nStt1 - nStt2; /* Center diagonal of top-down search. */ + const long bmid = nEnd1 - nEnd2; /* Center diagonal of bottom-up search. */ + + long fmin = fmid, fmax = fmid; /* Limits of top-down search. */ + long bmin = bmid, bmax = bmid; /* Limits of bottom-up search. */ + + long c; /* Cost. */ + long odd = (fmid - bmid) & 1; /* True if southeast corner is on an odd + diagonal with respect to the northwest. */ + + pFDiag[fmid] = nStt1; + pBDiag[bmid] = nEnd1; + + for (c = 1;; ++c) + { + long d; /* Active diagonal. */ + long big_snake = 0; + + /* Extend the top-down search by an edit step in each diagonal. */ + fmin > dmin ? pFDiag[--fmin - 1] = -1 : ++fmin; + fmax < dmax ? pFDiag[++fmax + 1] = -1 : --fmax; + for (d = fmax; d >= fmin; d -= 2) + { + long x, y, oldx, tlo = pFDiag[d - 1], thi = pFDiag[d + 1]; + + if (tlo >= thi) + x = tlo + 1; + else + x = thi; + oldx = x; + y = x - d; + while( sal_uLong(x) < nEnd1 && sal_uLong(y) < nEnd2 && + rMoved1.GetIndex( x ) == rMoved2.GetIndex( y )) + ++x, ++y; + if (x - oldx > 20) + big_snake = 1; + pFDiag[d] = x; + if( odd && bmin <= d && d <= bmax && pBDiag[d] <= pFDiag[d] ) + { + *pCost = 2 * c - 1; + return d; + } + } + + /* Similar extend the bottom-up search. */ + bmin > dmin ? pBDiag[--bmin - 1] = INT_MAX : ++bmin; + bmax < dmax ? pBDiag[++bmax + 1] = INT_MAX : --bmax; + for (d = bmax; d >= bmin; d -= 2) + { + long x, y, oldx, tlo = pBDiag[d - 1], thi = pBDiag[d + 1]; + + if (tlo < thi) + x = tlo; + else + x = thi - 1; + oldx = x; + y = x - d; + while( sal_uLong(x) > nStt1 && sal_uLong(y) > nStt2 && + rMoved1.GetIndex( x - 1 ) == rMoved2.GetIndex( y - 1 )) + --x, --y; + if (oldx - x > 20) + big_snake = 1; + pBDiag[d] = x; + if (!odd && fmin <= d && d <= fmax && pBDiag[d] <= pFDiag[d]) + { + *pCost = 2 * c; + return d; + } + } + } +} + +void Compare::ShiftBoundaries( CompareData& rData1, CompareData& rData2 ) +{ + for( int iz = 0; iz < 2; ++iz ) + { + CompareData* pData = &rData1; + CompareData* pOtherData = &rData2; + + sal_uLong i = 0; + sal_uLong j = 0; + sal_uLong i_end = pData->GetLineCount(); + sal_uLong preceding = ULONG_MAX; + sal_uLong other_preceding = ULONG_MAX; + + while (1) + { + sal_uLong start, other_start; + + /* Scan forwards to find beginning of another run of changes. + Also keep track of the corresponding point in the other file. */ + + while( i < i_end && !pData->GetChanged( i ) ) + { + while( pOtherData->GetChanged( j++ )) + /* Non-corresponding lines in the other file + will count as the preceding batch of changes. */ + other_preceding = j; + i++; + } + + if (i == i_end) + break; + + start = i; + other_start = j; + + while (1) + { + /* Now find the end of this run of changes. */ + + while( pData->GetChanged( ++i )) + ; + + /* If the first changed line matches the following unchanged one, + and this run does not follow right after a previous run, + and there are no lines deleted from the other file here, + then classify the first changed line as unchanged + and the following line as changed in its place. */ + + /* You might ask, how could this run follow right after another? + Only because the previous run was shifted here. */ + + if( i != i_end && + pData->GetIndex( start ) == pData->GetIndex( i ) && + !pOtherData->GetChanged( j ) && + !( start == preceding || other_start == other_preceding )) + { + pData->SetChanged( start++, 0 ); + pData->SetChanged( i ); + /* Since one line-that-matches is now before this run + instead of after, we must advance in the other file + to keep in synch. */ + ++j; + } + else + break; + } + + preceding = i; + other_preceding = j; + } + + pData = &rData2; + pOtherData = &rData1; + } +} + +/* */ + +class SwCompareLine : public CompareLine +{ + const SwNode& rNode; +public: + SwCompareLine( const SwNode& rNd ); + virtual ~SwCompareLine(); + + virtual sal_uLong GetHashValue() const; + virtual sal_Bool Compare( const CompareLine& rLine ) const; + + static sal_uLong GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal ); + static sal_Bool CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd ); + static sal_Bool CompareTxtNd( const SwTxtNode& rDstNd, + const SwTxtNode& rSrcNd ); + + sal_Bool ChangesInLine( const SwCompareLine& rLine, + SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const; + + const SwNode& GetNode() const { return rNode; } + + const SwNode& GetEndNode() const; + + // fuers Debugging! + String GetText() const; +}; + +class SwCompareData : public CompareData +{ + SwDoc& rDoc; + SwPaM *pInsRing, *pDelRing; + + sal_uLong PrevIdx( const SwNode* pNd ); + sal_uLong NextIdx( const SwNode* pNd ); + + virtual void CheckRanges( CompareData& ); + virtual void ShowInsert( sal_uLong nStt, sal_uLong nEnd ); + virtual void ShowDelete( const CompareData& rData, sal_uLong nStt, + sal_uLong nEnd, sal_uLong nInsPos ); + + virtual void CheckForChangesInLine( const CompareData& rData, + sal_uLong& nStt, sal_uLong& nEnd, + sal_uLong& nThisStt, sal_uLong& nThisEnd ); + +public: + SwCompareData( SwDoc& rD ) : rDoc( rD ), pInsRing(0), pDelRing(0) {} + virtual ~SwCompareData(); + + void SetRedlinesToDoc( sal_Bool bUseDocInfo ); +}; + +// ---------------------------------------------------------------- + +SwCompareLine::SwCompareLine( const SwNode& rNd ) + : rNode( rNd ) +{ +} + +SwCompareLine::~SwCompareLine() +{ +} + +sal_uLong SwCompareLine::GetHashValue() const +{ + sal_uLong nRet = 0; + switch( rNode.GetNodeType() ) + { + case ND_TEXTNODE: + nRet = GetTxtNodeHashValue( (SwTxtNode&)rNode, nRet ); + break; + + case ND_TABLENODE: + { + const SwNode* pEndNd = rNode.EndOfSectionNode(); + SwNodeIndex aIdx( rNode ); + while( &aIdx.GetNode() != pEndNd ) + { + if( aIdx.GetNode().IsTxtNode() ) + nRet = GetTxtNodeHashValue( (SwTxtNode&)aIdx.GetNode(), nRet ); + aIdx++; + } + } + break; + + case ND_SECTIONNODE: + { + String sStr( GetText() ); + for( xub_StrLen n = 0; n < sStr.Len(); ++n ) + ( nRet <<= 1 ) += sStr.GetChar( n ); + } + break; + + case ND_GRFNODE: + case ND_OLENODE: + // feste Id ? sollte aber nie auftauchen + break; + } + return nRet; +} + +const SwNode& SwCompareLine::GetEndNode() const +{ + const SwNode* pNd = &rNode; + switch( rNode.GetNodeType() ) + { + case ND_TABLENODE: + pNd = rNode.EndOfSectionNode(); + break; + + case ND_SECTIONNODE: + { + const SwSectionNode& rSNd = (SwSectionNode&)rNode; + const SwSection& rSect = rSNd.GetSection(); + if( CONTENT_SECTION != rSect.GetType() || rSect.IsProtect() ) + pNd = rNode.EndOfSectionNode(); + } + break; + } + return *pNd; +} + +sal_Bool SwCompareLine::Compare( const CompareLine& rLine ) const +{ + return CompareNode( rNode, ((SwCompareLine&)rLine).rNode ); +} + +namespace +{ + static String SimpleTableToText(const SwNode &rNode) + { + String sRet; + const SwNode* pEndNd = rNode.EndOfSectionNode(); + SwNodeIndex aIdx( rNode ); + while (&aIdx.GetNode() != pEndNd) + { + if (aIdx.GetNode().IsTxtNode()) + { + if (sRet.Len()) + { + sRet.Append( '\n' ); + } + sRet.Append( aIdx.GetNode().GetTxtNode()->GetExpandTxt() ); + } + aIdx++; + } + return sRet; + } +} + +sal_Bool SwCompareLine::CompareNode( const SwNode& rDstNd, const SwNode& rSrcNd ) +{ + if( rSrcNd.GetNodeType() != rDstNd.GetNodeType() ) + return sal_False; + + sal_Bool bRet = sal_False; + + switch( rDstNd.GetNodeType() ) + { + case ND_TEXTNODE: + bRet = CompareTxtNd( (SwTxtNode&)rDstNd, (SwTxtNode&)rSrcNd ); + break; + + case ND_TABLENODE: + { + const SwTableNode& rTSrcNd = (SwTableNode&)rSrcNd; + const SwTableNode& rTDstNd = (SwTableNode&)rDstNd; + + bRet = ( rTSrcNd.EndOfSectionIndex() - rTSrcNd.GetIndex() ) == + ( rTDstNd.EndOfSectionIndex() - rTDstNd.GetIndex() ); + + // --> #i107826#: compare actual table content + if (bRet) + { + bRet = (SimpleTableToText(rSrcNd) == SimpleTableToText(rDstNd)); + } + // <-- + } + break; + + case ND_SECTIONNODE: + { + const SwSectionNode& rSSrcNd = (SwSectionNode&)rSrcNd, + & rSDstNd = (SwSectionNode&)rDstNd; + const SwSection& rSrcSect = rSSrcNd.GetSection(), + & rDstSect = rSDstNd.GetSection(); + SectionType eSrcSectType = rSrcSect.GetType(), + eDstSectType = rDstSect.GetType(); + switch( eSrcSectType ) + { + case CONTENT_SECTION: + bRet = CONTENT_SECTION == eDstSectType && + rSrcSect.IsProtect() == rDstSect.IsProtect(); + if( bRet && rSrcSect.IsProtect() ) + { + // the only have they both the same size + bRet = ( rSSrcNd.EndOfSectionIndex() - rSSrcNd.GetIndex() ) == + ( rSDstNd.EndOfSectionIndex() - rSDstNd.GetIndex() ); + } + break; + + case TOX_HEADER_SECTION: + case TOX_CONTENT_SECTION: + if( TOX_HEADER_SECTION == eDstSectType || + TOX_CONTENT_SECTION == eDstSectType ) + { + // the same type of TOX? + const SwTOXBase* pSrcTOX = rSrcSect.GetTOXBase(); + const SwTOXBase* pDstTOX = rDstSect.GetTOXBase(); + bRet = pSrcTOX && pDstTOX + && pSrcTOX->GetType() == pDstTOX->GetType() + && pSrcTOX->GetTitle() == pDstTOX->GetTitle() + && pSrcTOX->GetTypeName() == pDstTOX->GetTypeName() +// && pSrcTOX->GetTOXName() == pDstTOX->GetTOXName() + ; + } + break; + + case DDE_LINK_SECTION: + case FILE_LINK_SECTION: + bRet = eSrcSectType == eDstSectType && + rSrcSect.GetLinkFileName() == + rDstSect.GetLinkFileName(); + break; + } + } + break; + + case ND_ENDNODE: + bRet = rSrcNd.StartOfSectionNode()->GetNodeType() == + rDstNd.StartOfSectionNode()->GetNodeType(); + + // --> #i107826#: compare actual table content + if (bRet && rSrcNd.StartOfSectionNode()->GetNodeType() == ND_TABLENODE) + { + bRet = CompareNode( + *rSrcNd.StartOfSectionNode(), *rDstNd.StartOfSectionNode()); + } + // <-- + + break; + } + return bRet; +} + +String SwCompareLine::GetText() const +{ + String sRet; + switch( rNode.GetNodeType() ) + { + case ND_TEXTNODE: + sRet = ((SwTxtNode&)rNode).GetExpandTxt(); + break; + + case ND_TABLENODE: + { + sRet = SimpleTableToText(rNode); + sRet.InsertAscii( "Tabelle: ", 0 ); + } + break; + + case ND_SECTIONNODE: + { + sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Section - Node:" )); + + const SwSectionNode& rSNd = (SwSectionNode&)rNode; + const SwSection& rSect = rSNd.GetSection(); + switch( rSect.GetType() ) + { + case CONTENT_SECTION: + if( rSect.IsProtect() ) + sRet.Append( String::CreateFromInt32( + rSNd.EndOfSectionIndex() - rSNd.GetIndex() )); + break; + + case TOX_HEADER_SECTION: + case TOX_CONTENT_SECTION: + { + const SwTOXBase* pTOX = rSect.GetTOXBase(); + if( pTOX ) + sRet.Append( pTOX->GetTitle() ) + .Append( pTOX->GetTypeName() ) +// .Append( pTOX->GetTOXName() ) + .Append( String::CreateFromInt32( pTOX->GetType() )); + } + break; + + case DDE_LINK_SECTION: + case FILE_LINK_SECTION: + sRet += rSect.GetLinkFileName(); + break; + } + } + break; + + case ND_GRFNODE: + sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "Grafik - Node:" )); + break; + case ND_OLENODE: + sRet.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "OLE - Node:" )); + break; + } + return sRet; +} + +sal_uLong SwCompareLine::GetTxtNodeHashValue( const SwTxtNode& rNd, sal_uLong nVal ) +{ + String sStr( rNd.GetExpandTxt() ); + for( xub_StrLen n = 0; n < sStr.Len(); ++n ) + ( nVal <<= 1 ) += sStr.GetChar( n ); + return nVal; +} + +sal_Bool SwCompareLine::CompareTxtNd( const SwTxtNode& rDstNd, + const SwTxtNode& rSrcNd ) +{ + sal_Bool bRet = sal_False; + // erstmal ganz einfach! + if( rDstNd.GetTxt() == rSrcNd.GetTxt() ) + { + // der Text ist gleich, aber sind die "Sonderattribute" (0xFF) auch + // dieselben?? + bRet = sal_True; + } + return bRet; +} + +sal_Bool SwCompareLine::ChangesInLine( const SwCompareLine& rLine, + SwPaM *& rpInsRing, SwPaM*& rpDelRing ) const +{ + sal_Bool bRet = sal_False; + if( ND_TEXTNODE == rNode.GetNodeType() && + ND_TEXTNODE == rLine.GetNode().GetNodeType() ) + { + SwTxtNode& rDestNd = *(SwTxtNode*)rNode.GetTxtNode(); + const SwTxtNode& rSrcNd = *rLine.GetNode().GetTxtNode(); + + xub_StrLen nDEnd = rDestNd.GetTxt().Len(), nSEnd = rSrcNd.GetTxt().Len(); + xub_StrLen nStt; + xub_StrLen nEnd; + + for( nStt = 0, nEnd = Min( nDEnd, nSEnd ); nStt < nEnd; ++nStt ) + if( rDestNd.GetTxt().GetChar( nStt ) != + rSrcNd.GetTxt().GetChar( nStt ) ) + break; + + while( nStt < nDEnd && nStt < nSEnd ) + { + --nDEnd, --nSEnd; + if( rDestNd.GetTxt().GetChar( nDEnd ) != + rSrcNd.GetTxt().GetChar( nSEnd ) ) + { + ++nDEnd, ++nSEnd; + break; + } + } + + if( nStt || !nDEnd || !nSEnd || nDEnd < rDestNd.GetTxt().Len() || + nSEnd < rSrcNd.GetTxt().Len() ) + { + // jetzt ist zwischen nStt bis nDEnd das neu eingefuegte + // und zwischen nStt und nSEnd das geloeschte + SwDoc* pDoc = rDestNd.GetDoc(); + SwPaM aPam( rDestNd, nDEnd ); + if( nStt != nDEnd ) + { + SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpInsRing ); + if( !rpInsRing ) + rpInsRing = pTmp; + + pTmp->SetMark(); + pTmp->GetMark()->nContent = nStt; + } + + if( nStt != nSEnd ) + { + { + ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo()); + SwPaM aCpyPam( rSrcNd, nStt ); + aCpyPam.SetMark(); + aCpyPam.GetPoint()->nContent = nSEnd; + aCpyPam.GetDoc()->CopyRange( aCpyPam, *aPam.GetPoint(), + false ); + } + + SwPaM* pTmp = new SwPaM( *aPam.GetPoint(), rpDelRing ); + if( !rpDelRing ) + rpDelRing = pTmp; + + pTmp->SetMark(); + pTmp->GetMark()->nContent = nDEnd; + + if( rpInsRing ) + { + SwPaM* pCorr = (SwPaM*)rpInsRing->GetPrev(); + if( *pCorr->GetPoint() == *pTmp->GetPoint() ) + *pCorr->GetPoint() = *pTmp->GetMark(); + } + } + bRet = sal_True; + } + } + return bRet; +} + +// ---------------------------------------------------------------- + +SwCompareData::~SwCompareData() +{ + if( pDelRing ) + { + while( pDelRing->GetNext() != pDelRing ) + delete pDelRing->GetNext(); + delete pDelRing; + } + if( pInsRing ) + { + while( pInsRing->GetNext() != pInsRing ) + delete pInsRing->GetNext(); + delete pInsRing; + } +} + +sal_uLong SwCompareData::NextIdx( const SwNode* pNd ) +{ + if( pNd->IsStartNode() ) + { + const SwSectionNode* pSNd; + if( pNd->IsTableNode() || + ( 0 != (pSNd = pNd->GetSectionNode() ) && + ( CONTENT_SECTION != pSNd->GetSection().GetType() || + pSNd->GetSection().IsProtect() ) ) ) + pNd = pNd->EndOfSectionNode(); + } + return pNd->GetIndex() + 1; +} + +sal_uLong SwCompareData::PrevIdx( const SwNode* pNd ) +{ + if( pNd->IsEndNode() ) + { + const SwSectionNode* pSNd; + if( pNd->StartOfSectionNode()->IsTableNode() || + ( 0 != (pSNd = pNd->StartOfSectionNode()->GetSectionNode() ) && + ( CONTENT_SECTION != pSNd->GetSection().GetType() || + pSNd->GetSection().IsProtect() ) ) ) + pNd = pNd->StartOfSectionNode(); + } + return pNd->GetIndex() - 1; +} + + +void SwCompareData::CheckRanges( CompareData& rData ) +{ + const SwNodes& rSrcNds = ((SwCompareData&)rData).rDoc.GetNodes(); + const SwNodes& rDstNds = rDoc.GetNodes(); + + const SwNode& rSrcEndNd = rSrcNds.GetEndOfContent(); + const SwNode& rDstEndNd = rDstNds.GetEndOfContent(); + + sal_uLong nSrcSttIdx = NextIdx( rSrcEndNd.StartOfSectionNode() ); + sal_uLong nSrcEndIdx = rSrcEndNd.GetIndex(); + + sal_uLong nDstSttIdx = NextIdx( rDstEndNd.StartOfSectionNode() ); + sal_uLong nDstEndIdx = rDstEndNd.GetIndex(); + + while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx ) + { + const SwNode* pSrcNd = rSrcNds[ nSrcSttIdx ]; + const SwNode* pDstNd = rDstNds[ nDstSttIdx ]; + if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd )) + break; + + nSrcSttIdx = NextIdx( pSrcNd ); + nDstSttIdx = NextIdx( pDstNd ); + } + + nSrcEndIdx = PrevIdx( &rSrcEndNd ); + nDstEndIdx = PrevIdx( &rDstEndNd ); + while( nSrcSttIdx < nSrcEndIdx && nDstSttIdx < nDstEndIdx ) + { + const SwNode* pSrcNd = rSrcNds[ nSrcEndIdx ]; + const SwNode* pDstNd = rDstNds[ nDstEndIdx ]; + if( !SwCompareLine::CompareNode( *pSrcNd, *pDstNd )) + break; + + nSrcEndIdx = PrevIdx( pSrcNd ); + nDstEndIdx = PrevIdx( pDstNd ); + } + + while( nSrcSttIdx <= nSrcEndIdx ) + { + const SwNode* pNd = rSrcNds[ nSrcSttIdx ]; + rData.InsertLine( new SwCompareLine( *pNd ) ); + nSrcSttIdx = NextIdx( pNd ); + } + + while( nDstSttIdx <= nDstEndIdx ) + { + const SwNode* pNd = rDstNds[ nDstSttIdx ]; + InsertLine( new SwCompareLine( *pNd ) ); + nDstSttIdx = NextIdx( pNd ); + } +} + + +void SwCompareData::ShowInsert( sal_uLong nStt, sal_uLong nEnd ) +{ + SwPaM* pTmp = new SwPaM( ((SwCompareLine*)GetLine( nStt ))->GetNode(), 0, + ((SwCompareLine*)GetLine( nEnd-1 ))->GetEndNode(), 0, + pInsRing ); + if( !pInsRing ) + pInsRing = pTmp; + + // #i65201#: These SwPaMs are calculated smaller than needed, see comment below + +} + +void SwCompareData::ShowDelete( const CompareData& rData, sal_uLong nStt, + sal_uLong nEnd, sal_uLong nInsPos ) +{ + SwNodeRange aRg( + ((SwCompareLine*)rData.GetLine( nStt ))->GetNode(), 0, + ((SwCompareLine*)rData.GetLine( nEnd-1 ))->GetEndNode(), 1 ); + + sal_uInt16 nOffset = 0; + const CompareLine* pLine; + if( GetLineCount() == nInsPos ) + { + pLine = GetLine( nInsPos-1 ); + nOffset = 1; + } + else + pLine = GetLine( nInsPos ); + + const SwNode* pLineNd; + if( pLine ) + { + if( nOffset ) + pLineNd = &((SwCompareLine*)pLine)->GetEndNode(); + else + pLineNd = &((SwCompareLine*)pLine)->GetNode(); + } + else + { + pLineNd = &rDoc.GetNodes().GetEndOfContent(); + nOffset = 0; + } + + SwNodeIndex aInsPos( *pLineNd, nOffset ); + SwNodeIndex aSavePos( aInsPos, -1 ); + + ((SwCompareData&)rData).rDoc.CopyWithFlyInFly( aRg, 0, aInsPos ); + rDoc.SetModified(); + aSavePos++; + + // #i65201#: These SwPaMs are calculated when the (old) delete-redlines are hidden, + // they will be inserted when the delete-redlines are shown again. + // To avoid unwanted insertions of delete-redlines into these new redlines, what happens + // especially at the end of the document, I reduce the SwPaM by one node. + // Before the new redlines are inserted, they have to expand again. + SwPaM* pTmp = new SwPaM( aSavePos.GetNode(), aInsPos.GetNode(), 0, -1, pDelRing ); + if( !pDelRing ) + pDelRing = pTmp; + + if( pInsRing ) + { + SwPaM* pCorr = (SwPaM*)pInsRing->GetPrev(); + if( *pCorr->GetPoint() == *pTmp->GetPoint() ) + { + SwNodeIndex aTmpPos( pTmp->GetMark()->nNode, -1 ); + *pCorr->GetPoint() = SwPosition( aTmpPos ); + } + } +} + +void SwCompareData::CheckForChangesInLine( const CompareData& rData, + sal_uLong& rStt, sal_uLong& rEnd, + sal_uLong& rThisStt, sal_uLong& rThisEnd ) +{ + while( rStt < rEnd && rThisStt < rThisEnd ) + { + SwCompareLine* pDstLn = (SwCompareLine*)GetLine( rThisStt ); + SwCompareLine* pSrcLn = (SwCompareLine*)rData.GetLine( rStt ); + if( !pDstLn->ChangesInLine( *pSrcLn, pInsRing, pDelRing ) ) + break; + + ++rStt; + ++rThisStt; + } +} + +void SwCompareData::SetRedlinesToDoc( sal_Bool bUseDocInfo ) +{ + SwPaM* pTmp = pDelRing; + + // Bug #83296#: get the Author / TimeStamp from the "other" + // document info + sal_uInt16 nAuthor = rDoc.GetRedlineAuthor(); + DateTime aTimeStamp; + SwDocShell *pDocShell(rDoc.GetDocShell()); + DBG_ASSERT(pDocShell, "no SwDocShell"); + if (pDocShell) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pDocShell->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); + + if( bUseDocInfo && xDocProps.is() ) { + String aTmp( 1 == xDocProps->getEditingCycles() + ? xDocProps->getAuthor() + : xDocProps->getModifiedBy() ); + util::DateTime uDT( 1 == xDocProps->getEditingCycles() + ? xDocProps->getCreationDate() + : xDocProps->getModificationDate() ); + Date d(uDT.Day, uDT.Month, uDT.Year); + Time t(uDT.Hours, uDT.Minutes, uDT.Seconds, uDT.HundredthSeconds); + DateTime aDT(d,t); + + if( aTmp.Len() ) + { + nAuthor = rDoc.InsertRedlineAuthor( aTmp ); + aTimeStamp = aDT; + } + } + } + + if( pTmp ) + { + SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_DELETE, nAuthor, aTimeStamp, + aEmptyStr, 0, 0 ); + do { + // #i65201#: Expand again, see comment above. + if( pTmp->GetPoint()->nContent == 0 ) + { + pTmp->GetPoint()->nNode++; + pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); + } + // --> mst 2010-05-17 #i101009# + // prevent redlines that end on structural end node + if (& rDoc.GetNodes().GetEndOfContent() == + & pTmp->GetPoint()->nNode.GetNode()) + { + pTmp->GetPoint()->nNode--; + SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); + pTmp->GetPoint()->nContent.Assign( pContentNode, + (pContentNode) ? pContentNode->Len() : 0 ); + } + // <-- + + rDoc.DeleteRedline( *pTmp, false, USHRT_MAX ); + + if (rDoc.GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_False )) ; + rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); + } + rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true ); + + } while( pDelRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); + } + + pTmp = pInsRing; + if( pTmp ) + { + do { + if( pTmp->GetPoint()->nContent == 0 ) + { + pTmp->GetPoint()->nNode++; + pTmp->GetPoint()->nContent.Assign( pTmp->GetCntntNode(), 0 ); + } + // --> mst 2010-05-17 #i101009# + // prevent redlines that end on structural end node + if (& rDoc.GetNodes().GetEndOfContent() == + & pTmp->GetPoint()->nNode.GetNode()) + { + pTmp->GetPoint()->nNode--; + SwCntntNode *const pContentNode( pTmp->GetCntntNode() ); + pTmp->GetPoint()->nContent.Assign( pContentNode, + (pContentNode) ? pContentNode->Len() : 0 ); + } + // <-- + } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); + SwRedlineData aRedlnData( nsRedlineType_t::REDLINE_INSERT, nAuthor, aTimeStamp, + aEmptyStr, 0, 0 ); + + // zusammenhaengende zusammenfassen + if( pTmp->GetNext() != pInsRing ) + { + const SwCntntNode* pCNd; + do { + SwPosition& rSttEnd = *pTmp->End(), + & rEndStt = *((SwPaM*)pTmp->GetNext())->Start(); + if( rSttEnd == rEndStt || + (!rEndStt.nContent.GetIndex() && + rEndStt.nNode.GetIndex() - 1 == rSttEnd.nNode.GetIndex() && + 0 != ( pCNd = rSttEnd.nNode.GetNode().GetCntntNode() ) + ? rSttEnd.nContent.GetIndex() == pCNd->Len() + : 0 )) + { + if( pTmp->GetNext() == pInsRing ) + { + // liegen hintereinander also zusammen fassen + rEndStt = *pTmp->Start(); + delete pTmp; + pTmp = pInsRing; + } + else + { + // liegen hintereinander also zusammen fassen + rSttEnd = *((SwPaM*)pTmp->GetNext())->End(); + delete pTmp->GetNext(); + } + } + else + pTmp = (SwPaM*)pTmp->GetNext(); + } while( pInsRing != pTmp ); + } + + do { + if( rDoc.AppendRedline( new SwRedline( aRedlnData, *pTmp ), true) && + rDoc.GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo(new SwUndoCompDoc( *pTmp, sal_True )); + rDoc.GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } while( pInsRing != ( pTmp = (SwPaM*)pTmp->GetNext() )); + } +} + +/* */ + + + + // returnt (?die Anzahl der Unterschiede?) ob etwas unterschiedlich ist +long SwDoc::CompareDoc( const SwDoc& rDoc ) +{ + if( &rDoc == this ) + return 0; + + long nRet = 0; + + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); + sal_Bool bDocWasModified = IsModified(); + SwDoc& rSrcDoc = (SwDoc&)rDoc; + sal_Bool bSrcModified = rSrcDoc.IsModified(); + + RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); + rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_INSERT ); + SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT)); + + SwCompareData aD0( rSrcDoc ); + SwCompareData aD1( *this ); + + aD1.CompareLines( aD0 ); + + nRet = aD1.ShowDiffs( aD0 ); + + if( nRet ) + { + SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | + nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + aD1.SetRedlinesToDoc( !bDocWasModified ); + SetModified(); + } + + rSrcDoc.SetRedlineMode( eSrcRedlMode ); + SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + if( !bSrcModified ) + rSrcDoc.ResetModified(); + + GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); + + return nRet; +} + + +class _SaveMergeRedlines : public Ring +{ + const SwRedline* pSrcRedl; + SwRedline* pDestRedl; +public: + _SaveMergeRedlines( const SwNode& rDstNd, + const SwRedline& rSrcRedl, Ring* pRing ); + sal_uInt16 InsertRedline(); + + SwRedline* GetDestRedline() { return pDestRedl; } +}; + +_SaveMergeRedlines::_SaveMergeRedlines( const SwNode& rDstNd, + const SwRedline& rSrcRedl, Ring* pRing ) + : Ring( pRing ), pSrcRedl( &rSrcRedl ) +{ + SwPosition aPos( rDstNd ); + + const SwPosition* pStt = rSrcRedl.Start(); + if( rDstNd.IsCntntNode() ) + aPos.nContent.Assign( ((SwCntntNode*)&rDstNd), pStt->nContent.GetIndex() ); + pDestRedl = new SwRedline( rSrcRedl.GetRedlineData(), aPos ); + + if( nsRedlineType_t::REDLINE_DELETE == pDestRedl->GetType() ) + { + // den Bereich als geloescht kennzeichnen + const SwPosition* pEnd = pStt == rSrcRedl.GetPoint() + ? rSrcRedl.GetMark() + : rSrcRedl.GetPoint(); + + pDestRedl->SetMark(); + pDestRedl->GetPoint()->nNode += pEnd->nNode.GetIndex() - + pStt->nNode.GetIndex(); + pDestRedl->GetPoint()->nContent.Assign( pDestRedl->GetCntntNode(), + pEnd->nContent.GetIndex() ); + } +} + +sal_uInt16 _SaveMergeRedlines::InsertRedline() +{ + sal_uInt16 nIns = 0; + SwDoc* pDoc = pDestRedl->GetDoc(); + + if( nsRedlineType_t::REDLINE_INSERT == pDestRedl->GetType() ) + { + // der Teil wurde eingefuegt, also kopiere ihn aus dem SourceDoc + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodeIndex aSaveNd( pDestRedl->GetPoint()->nNode, -1 ); + xub_StrLen nSaveCnt = pDestRedl->GetPoint()->nContent.GetIndex(); + + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + + pSrcRedl->GetDoc()->CopyRange( + *const_cast<SwPaM*>(static_cast<const SwPaM*>(pSrcRedl)), + *pDestRedl->GetPoint(), false ); + + pDoc->SetRedlineMode_intern( eOld ); + + pDestRedl->SetMark(); + aSaveNd++; + pDestRedl->GetMark()->nNode = aSaveNd; + pDestRedl->GetMark()->nContent.Assign( aSaveNd.GetNode().GetCntntNode(), + nSaveCnt ); + + if( GetPrev() != this ) + { + SwPaM* pTmpPrev = ((_SaveMergeRedlines*)GetPrev())->pDestRedl; + if( pTmpPrev && *pTmpPrev->GetPoint() == *pDestRedl->GetPoint() ) + *pTmpPrev->GetPoint() = *pDestRedl->GetMark(); + } + } + else + { + //JP 21.09.98: Bug 55909 + // falls im Doc auf gleicher Pos aber schon ein geloeschter oder + // eingefuegter ist, dann muss dieser gesplittet werden! + SwPosition* pDStt = pDestRedl->GetMark(), + * pDEnd = pDestRedl->GetPoint(); + sal_uInt16 n = 0; + + // zur StartPos das erste Redline suchen + if( !pDoc->GetRedline( *pDStt, &n ) && n ) + --n; + + const SwRedlineTbl& rRedlineTbl = pDoc->GetRedlineTbl(); + for( ; n < rRedlineTbl.Count(); ++n ) + { + SwRedline* pRedl = rRedlineTbl[ n ]; + SwPosition* pRStt = pRedl->Start(), + * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark() + : pRedl->GetPoint(); + if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() || + nsRedlineType_t::REDLINE_INSERT == pRedl->GetType() ) + { + SwComparePosition eCmpPos = ComparePosition( *pDStt, *pDEnd, *pRStt, *pREnd ); + switch( eCmpPos ) + { + case POS_COLLIDE_START: + case POS_BEHIND: + break; + + case POS_INSIDE: + case POS_EQUAL: + delete pDestRedl, pDestRedl = 0; + // break; -> kein break !!!! + + case POS_COLLIDE_END: + case POS_BEFORE: + n = rRedlineTbl.Count(); + break; + + case POS_OUTSIDE: + { + SwRedline* pCpyRedl = new SwRedline( + pDestRedl->GetRedlineData(), *pDStt ); + pCpyRedl->SetMark(); + *pCpyRedl->GetPoint() = *pRStt; + + SwUndoCompDoc *const pUndo = + (pDoc->GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoCompDoc( *pCpyRedl ) : 0; + + // now modify doc: append redline, undo (and count) + pDoc->AppendRedline( pCpyRedl, true ); + if( pUndo ) + { + pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo); + } + ++nIns; + + *pDStt = *pREnd; + + // dann solle man neu anfangen + n = USHRT_MAX; + } + break; + + case POS_OVERLAP_BEFORE: + *pDEnd = *pRStt; + break; + + case POS_OVERLAP_BEHIND: + *pDStt = *pREnd; + break; + } + } + else if( *pDEnd <= *pRStt ) + break; + } + + } + + if( pDestRedl ) + { + SwUndoCompDoc *const pUndo = (pDoc->GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoCompDoc( *pDestRedl ) : 0; + + // now modify doc: append redline, undo (and count) + bool bRedlineAccepted = pDoc->AppendRedline( pDestRedl, true ); + if( pUndo ) + { + pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + ++nIns; + + // if AppendRedline has deleted our redline, we may not keep a + // reference to it + if( ! bRedlineAccepted ) + pDestRedl = NULL; + } + return nIns; +} + +// merge zweier Dokumente +long SwDoc::MergeDoc( const SwDoc& rDoc ) +{ + if( &rDoc == this ) + return 0; + + long nRet = 0; + + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); + + SwDoc& rSrcDoc = (SwDoc&)rDoc; + sal_Bool bSrcModified = rSrcDoc.IsModified(); + + RedlineMode_t eSrcRedlMode = rSrcDoc.GetRedlineMode(); + rSrcDoc.SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); + SetRedlineMode( nsRedlineMode_t::REDLINE_SHOW_DELETE ); + + SwCompareData aD0( rSrcDoc ); + SwCompareData aD1( *this ); + + aD1.CompareLines( aD0 ); + + if( !aD1.HasDiffs( aD0 ) ) + { + // jetzt wollen wir alle Redlines aus dem SourceDoc zu uns bekommen + + // suche alle Insert - Redlines aus dem SourceDoc und bestimme + // deren Position im DestDoc + _SaveMergeRedlines* pRing = 0; + const SwRedlineTbl& rSrcRedlTbl = rSrcDoc.GetRedlineTbl(); + sal_uLong nEndOfExtra = rSrcDoc.GetNodes().GetEndOfExtras().GetIndex(); + sal_uLong nMyEndOfExtra = GetNodes().GetEndOfExtras().GetIndex(); + for( sal_uInt16 n = 0; n < rSrcRedlTbl.Count(); ++n ) + { + const SwRedline* pRedl = rSrcRedlTbl[ n ]; + sal_uLong nNd = pRedl->GetPoint()->nNode.GetIndex(); + RedlineType_t eType = pRedl->GetType(); + if( nEndOfExtra < nNd && + ( nsRedlineType_t::REDLINE_INSERT == eType || nsRedlineType_t::REDLINE_DELETE == eType )) + { + const SwNode* pDstNd = GetNodes()[ + nMyEndOfExtra + nNd - nEndOfExtra ]; + + // Position gefunden. Dann muss im DestDoc auch + // in der Line das Redline eingefuegt werden + _SaveMergeRedlines* pTmp = new _SaveMergeRedlines( + *pDstNd, *pRedl, pRing ); + if( !pRing ) + pRing = pTmp; + } + } + + if( pRing ) + { + // dann alle ins DestDoc ueber nehmen + rSrcDoc.SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + SetRedlineMode((RedlineMode_t)( + nsRedlineMode_t::REDLINE_ON | + nsRedlineMode_t::REDLINE_SHOW_INSERT | + nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + _SaveMergeRedlines* pTmp = pRing; + + do { + nRet += pTmp->InsertRedline(); + } while( pRing != ( pTmp = (_SaveMergeRedlines*)pTmp->GetNext() )); + + while( pRing != pRing->GetNext() ) + delete pRing->GetNext(); + delete pRing; + } + } + + rSrcDoc.SetRedlineMode( eSrcRedlMode ); + if( !bSrcModified ) + rSrcDoc.ResetModified(); + + SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)); + + GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); + + return nRet; +} + + diff --git a/sw/source/core/doc/doccorr.cxx b/sw/source/core/doc/doccorr.cxx new file mode 100644 index 000000000000..3477619fba33 --- /dev/null +++ b/sw/source/core/doc/doccorr.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <doc.hxx> +#include <node.hxx> +#include <rootfrm.hxx> +#include <editsh.hxx> +#include <viscrs.hxx> +#include <IMark.hxx> +#include <bookmrk.hxx> +#include <redline.hxx> +#include <mvsave.hxx> +#include <docary.hxx> +#include <unocrsr.hxx> +#include <swundo.hxx> +#include <hints.hxx> + +/* */ + +/* + * MACROS um ueber alle CrsrShells zu iterieren + */ +#define PCURSH ((SwCrsrShell*)_pStartShell) +#define FOREACHSHELL_START( pEShell ) \ + {\ + ViewShell *_pStartShell = pEShell; \ + do { \ + if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \ + { + +#define FOREACHSHELL_END( pEShell ) \ + } \ + } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \ + } + +#define PCURCRSR (_pCurrCrsr) +#define FOREACHPAM_START(pSttCrsr) \ + {\ + SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \ + do { + +#define FOREACHPAM_END() \ + } while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \ + } + +namespace +{ + // find the relevant section in which the SwUnoCrsr may wander. + // returns NULL if no restrictions apply + static const SwStartNode* lcl_FindUnoCrsrSection( const SwNode& rNode ) + { + const SwStartNode* pStartNode = rNode.StartOfSectionNode(); + while( ( pStartNode != NULL ) && + ( pStartNode->StartOfSectionNode() != pStartNode ) && + ( pStartNode->GetStartNodeType() == SwNormalStartNode ) ) + pStartNode = pStartNode->StartOfSectionNode(); + + return pStartNode; + } + + static inline bool lcl_PosCorrAbs(SwPosition & rPos, + const SwPosition& rStart, + const SwPosition& rEnd, + const SwPosition& rNewPos) + { + if ((rStart <= rPos) && (rPos <= rEnd)) + { + rPos = rNewPos; + return true; + } + return false; + }; + + static inline bool lcl_PaMCorrAbs(SwPaM & rPam, + const SwPosition& rStart, + const SwPosition& rEnd, + const SwPosition& rNewPos) + { + bool bRet = false; + bRet |= lcl_PosCorrAbs(rPam.GetBound(true ), rStart, rEnd, rNewPos); + bRet |= lcl_PosCorrAbs(rPam.GetBound(false), rStart, rEnd, rNewPos); + return bRet; + }; + + static inline void lcl_PaMCorrRel1(SwPaM * pPam, + SwNode const * const pOldNode, + const SwPosition& rNewPos, + const xub_StrLen nCntIdx) + { + for(int nb = 0; nb < 2; ++nb) + if(&((pPam)->GetBound(sal_Bool(nb)).nNode.GetNode()) == pOldNode) + { + (pPam)->GetBound(sal_Bool(nb)).nNode = rNewPos.nNode; + (pPam)->GetBound(sal_Bool(nb)).nContent.Assign( + const_cast<SwIndexReg*>(rNewPos.nContent.GetIdxReg()), + nCntIdx + (pPam)->GetBound(sal_Bool(nb)).nContent.GetIndex()); + } + } +} + + +void PaMCorrAbs( const SwPaM& rRange, + const SwPosition& rNewPos ) +{ + SwPosition const aStart( *rRange.Start() ); + SwPosition const aEnd( *rRange.End() ); + SwPosition const aNewPos( rNewPos ); + SwDoc *const pDoc = aStart.nNode.GetNode().GetDoc(); + SwCrsrShell *const pShell = pDoc->GetEditShell(); + + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + lcl_PaMCorrAbs( *_pStkCrsr, aStart, aEnd, aNewPos ); + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos ); + FOREACHPAM_END() + + if( PCURSH->IsTableMode() ) + lcl_PaMCorrAbs( *PCURSH->GetTblCrs(), aStart, aEnd, aNewPos ); + + FOREACHSHELL_END( pShell ) + } + { + SwUnoCrsrTbl& rTbl = const_cast<SwUnoCrsrTbl&>(pDoc->GetUnoCrsrTbl()); + + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + SwUnoCrsr *const pUnoCursor = rTbl[ n ]; + + bool bChange = false; // has the UNO cursor been corrected? + + // determine whether the UNO cursor will leave it's designated + // section + bool const bLeaveSection = + pUnoCursor->IsRemainInSection() && + ( lcl_FindUnoCrsrSection( aNewPos.nNode.GetNode() ) != + lcl_FindUnoCrsrSection( + pUnoCursor->GetPoint()->nNode.GetNode() ) ); + + FOREACHPAM_START( pUnoCursor ) + bChange |= lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos ); + FOREACHPAM_END() + + SwUnoTableCrsr *const pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr *>(rTbl[ n ]); + if( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + bChange |= + lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos ); + FOREACHPAM_END() + } + + // if a UNO cursor leaves its designated section, we must inform + // (and invalidate) said cursor + if (bChange && bLeaveSection) + { + // the UNO cursor has left its section. We need to notify it! + SwMsgPoolItem aHint( RES_UNOCURSOR_LEAVES_SECTION ); + pUnoCursor->Modify( &aHint, NULL ); + } + } + } +} + +void SwDoc::CorrAbs(const SwNodeIndex& rOldNode, + const SwPosition& rNewPos, + const xub_StrLen nOffset, + sal_Bool bMoveCrsr) +{ + SwCntntNode *const pCntntNode( rOldNode.GetNode().GetCntntNode() ); + SwPaM const aPam(rOldNode, 0, + rOldNode, (pCntntNode) ? pCntntNode->Len() : 0); + SwPosition aNewPos(rNewPos); + aNewPos.nContent += nOffset; + + getIDocumentMarkAccess()->correctMarksAbsolute(rOldNode, rNewPos, nOffset); + { // fix redlines + SwRedlineTbl& rTbl = *pRedlineTbl; + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + // is on position ?? + lcl_PaMCorrAbs(*rTbl[ n ], *aPam.Start(), *aPam.End(), aNewPos); + } + } + + if(bMoveCrsr) + { + ::PaMCorrAbs(aPam, aNewPos); + } +} + +void SwDoc::CorrAbs(const SwPaM& rRange, + const SwPosition& rNewPos, + sal_Bool bMoveCrsr) +{ + SwPosition aStart(*rRange.Start()); + SwPosition aEnd(*rRange.End()); + SwPosition aNewPos(rNewPos); + + _DelBookmarks(aStart.nNode, aEnd.nNode, NULL, + &aStart.nContent, &aEnd.nContent); + if(bMoveCrsr) + ::PaMCorrAbs(rRange, rNewPos); +} + +void SwDoc::CorrAbs(const SwNodeIndex& rStartNode, + const SwNodeIndex& rEndNode, + const SwPosition& rNewPos, + sal_Bool bMoveCrsr) +{ + _DelBookmarks(rStartNode, rEndNode); + + if(bMoveCrsr) + { + SwCntntNode *const pCntntNode( rEndNode.GetNode().GetCntntNode() ); + SwPaM const aPam(rStartNode, 0, + rEndNode, (pCntntNode) ? pCntntNode->Len() : 0); + ::PaMCorrAbs(aPam, rNewPos); + } +} + + + + + +void PaMCorrRel( const SwNodeIndex &rOldNode, + const SwPosition &rNewPos, + const xub_StrLen nOffset ) +{ + const SwNode* pOldNode = &rOldNode.GetNode(); + SwPosition aNewPos( rNewPos ); + const SwDoc* pDoc = pOldNode->GetDoc(); + + xub_StrLen nCntIdx = rNewPos.nContent.GetIndex() + nOffset; + + SwCrsrShell* pShell = pDoc->GetEditShell(); + if( pShell ) + { + FOREACHSHELL_START( pShell ) + SwPaM *_pStkCrsr = PCURSH->GetStkCrsr(); + if( _pStkCrsr ) + do { + lcl_PaMCorrRel1( _pStkCrsr, pOldNode, aNewPos, nCntIdx ); + } while ( (_pStkCrsr != 0 ) && + ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) ); + + FOREACHPAM_START( PCURSH->_GetCrsr() ) + lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx); + FOREACHPAM_END() + + if( PCURSH->IsTableMode() ) + lcl_PaMCorrRel1( PCURSH->GetTblCrs(), pOldNode, aNewPos, nCntIdx ); + + FOREACHSHELL_END( pShell ) + } + { + SwUnoCrsrTbl& rTbl = (SwUnoCrsrTbl&)pDoc->GetUnoCrsrTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + FOREACHPAM_START( rTbl[ n ] ) + lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx ); + FOREACHPAM_END() + + SwUnoTableCrsr* pUnoTblCrsr = + dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]); + if( pUnoTblCrsr ) + { + FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() ) + lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx ); + FOREACHPAM_END() + } + } + } +} + +void SwDoc::CorrRel(const SwNodeIndex& rOldNode, + const SwPosition& rNewPos, + const xub_StrLen nOffset, + sal_Bool bMoveCrsr) +{ + getIDocumentMarkAccess()->correctMarksRelative(rOldNode, rNewPos, nOffset); + + { // dann die Redlines korrigieren + SwRedlineTbl& rTbl = *pRedlineTbl; + SwPosition aNewPos(rNewPos); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + // liegt auf der Position ?? + lcl_PaMCorrRel1( rTbl[ n ], &rOldNode.GetNode(), aNewPos, aNewPos.nContent.GetIndex() + nOffset ); + } + } + + if(bMoveCrsr) + ::PaMCorrRel(rOldNode, rNewPos, nOffset); +} + + +SwEditShell* SwDoc::GetEditShell( ViewShell** ppSh ) const +{ + // Layout und OLE-Shells sollten vorhanden sein! + if( pLayout && pLayout->GetCurrShell() ) + { + ViewShell *pSh = pLayout->GetCurrShell(), *pVSh = pSh; + if( ppSh ) + *ppSh = pSh; + + // wir suchen uns eine EditShell, falls diese existiert + do { + if( pSh->IsA( TYPE( SwEditShell ) ) ) + return (SwEditShell*)pSh; + + } while( pVSh != ( pSh = (ViewShell*)pSh->GetNext() )); + } + else if( ppSh ) + *ppSh = 0; + + return 0; +} + +::sw::IShellCursorSupplier * SwDoc::GetIShellCursorSupplier() +{ + return GetEditShell(0); +} + diff --git a/sw/source/core/doc/docdde.cxx b/sw/source/core/doc/docdde.cxx new file mode 100644 index 000000000000..bef9ea1f254f --- /dev/null +++ b/sw/source/core/doc/docdde.cxx @@ -0,0 +1,418 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include <stdlib.h> + +#ifndef _APP_HXX +#include <vcl/svapp.hxx> +#endif +#include <tools/urlobj.hxx> + +#define _SVSTDARR_STRINGS +#include <svl/svstdarr.hxx> +#include <sfx2/linkmgr.hxx> // LinkManager +#include <unotools/charclass.hxx> +#include <fmtcntnt.hxx> +#include <doc.hxx> +#include <swserv.hxx> // fuer Server-Funktionalitaet +#include <IMark.hxx> +#include <bookmrk.hxx> +#include <section.hxx> // fuer SwSectionFmt +#include <swtable.hxx> // fuer SwTable +#include <node.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <docary.hxx> +#include <MarkManager.hxx> + +using namespace ::com::sun::star; + +namespace +{ + + static ::sw::mark::DdeBookmark* lcl_FindDdeBookmark(const IDocumentMarkAccess& rMarkAccess, const String& rName, bool bCaseSensitive) + { + //Iterating over all bookmarks, checking DdeBookmarks + const ::rtl::OUString sNameLc = bCaseSensitive ? rName : GetAppCharClass().lower(rName); + for(IDocumentMarkAccess::const_iterator_t ppMark = rMarkAccess.getMarksBegin(); + ppMark != rMarkAccess.getMarksEnd(); + ppMark++) + { + if (::sw::mark::DdeBookmark* const pBkmk = dynamic_cast< ::sw::mark::DdeBookmark*>(ppMark->get())) + { + if ( + (bCaseSensitive && (pBkmk->GetName() == sNameLc)) || + (!bCaseSensitive && GetAppCharClass().lower(pBkmk->GetName()) == String(sNameLc)) + ) + { + return pBkmk; + } + } + } + return NULL; + } +} + +struct _FindItem +{ + const String m_Item; + SwTableNode* pTblNd; + SwSectionNode* pSectNd; + + _FindItem(const String& rS) + : m_Item(rS), pTblNd(0), pSectNd(0) + {} +}; + +sal_Bool lcl_FindSection( const SwSectionFmtPtr& rpSectFmt, void* pArgs, bool bCaseSensitive ) +{ + _FindItem * const pItem( static_cast<_FindItem*>(pArgs) ); + SwSection* pSect = rpSectFmt->GetSection(); + if( pSect ) + { + String sNm( (bCaseSensitive) + ? pSect->GetSectionName() + : GetAppCharClass().lower( pSect->GetSectionName() )); + String sCompare( (bCaseSensitive) + ? pItem->m_Item + : GetAppCharClass().lower( pItem->m_Item ) ); + if( sNm == sCompare ) + { + // gefunden, als erfrage die Daten + const SwNodeIndex* pIdx; + if( 0 != (pIdx = rpSectFmt->GetCntnt().GetCntntIdx() ) && + &rpSectFmt->GetDoc()->GetNodes() == &pIdx->GetNodes() ) + { + // eine Tabelle im normalen NodesArr + pItem->pSectNd = pIdx->GetNode().GetSectionNode(); + return sal_False; + } +//nein!! // sollte der Namen schon passen, der Rest aber nicht, dann haben wir + // sie nicht. Die Namen sind immer eindeutig. + } + } + return sal_True; // dann weiter +} +sal_Bool lcl_FindSectionCaseSensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs ) +{ + return lcl_FindSection( rpSectFmt, pArgs, true ); +} +sal_Bool lcl_FindSectionCaseInsensitive( const SwSectionFmtPtr& rpSectFmt, void* pArgs ) +{ + return lcl_FindSection( rpSectFmt, pArgs, false ); +} + + + +sal_Bool lcl_FindTable( const SwFrmFmtPtr& rpTableFmt, void* pArgs ) +{ + _FindItem * const pItem( static_cast<_FindItem*>(pArgs) ); + String sNm( GetAppCharClass().lower( rpTableFmt->GetName() )); + if (sNm.Equals( pItem->m_Item )) + { + SwTable* pTmpTbl; + SwTableBox* pFBox; + if( 0 != ( pTmpTbl = SwTable::FindTable( rpTableFmt ) ) && + 0 != ( pFBox = pTmpTbl->GetTabSortBoxes()[0] ) && + pFBox->GetSttNd() && + &rpTableFmt->GetDoc()->GetNodes() == &pFBox->GetSttNd()->GetNodes() ) + { + // eine Tabelle im normalen NodesArr + pItem->pTblNd = (SwTableNode*) + pFBox->GetSttNd()->FindTableNode(); + return sal_False; + } +//nein! // sollte der Namen schon passen, der Rest aber nicht, dann haben wir + // sie nicht. Die Namen sind immer eindeutig. + } + return sal_True; // dann weiter +} + + + +bool SwDoc::GetData( const String& rItem, const String& rMimeType, + uno::Any & rValue ) const +{ + //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive + bool bCaseSensitive = true; + while( true ) + { + ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); + if(pBkmk) + return SwServerObject(*pBkmk).GetData(rValue, rMimeType); + + // haben wir ueberhaupt das Item vorraetig? + String sItem( bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); + _FindItem aPara( sItem ); + ((SwSectionFmts&)*pSectionFmtTbl).ForEach( 0, pSectionFmtTbl->Count(), + bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); + if( aPara.pSectNd ) + { + // gefunden, als erfrage die Daten + return SwServerObject( *aPara.pSectNd ).GetData( rValue, rMimeType ); + } + if( !bCaseSensitive ) + break; + bCaseSensitive = false; + } + + _FindItem aPara( GetAppCharClass().lower( rItem )); + ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach( 0, pTblFrmFmtTbl->Count(), + lcl_FindTable, &aPara ); + if( aPara.pTblNd ) + { + return SwServerObject( *aPara.pTblNd ).GetData( rValue, rMimeType ); + } + + return sal_False; +} + + + +bool SwDoc::SetData( const String& rItem, const String& rMimeType, + const uno::Any & rValue ) +{ + //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive + bool bCaseSensitive = true; + while( true ) + { + ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); + if(pBkmk) + return SwServerObject(*pBkmk).SetData(rMimeType, rValue); + + // haben wir ueberhaupt das Item vorraetig? + String sItem( bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); + _FindItem aPara( sItem ); + pSectionFmtTbl->ForEach( 0, pSectionFmtTbl->Count(), bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); + if( aPara.pSectNd ) + { + // gefunden, als erfrage die Daten + return SwServerObject( *aPara.pSectNd ).SetData( rMimeType, rValue ); + } + if( !bCaseSensitive ) + break; + bCaseSensitive = false; + } + + String sItem(GetAppCharClass().lower(rItem)); + _FindItem aPara( sItem ); + pTblFrmFmtTbl->ForEach( 0, pTblFrmFmtTbl->Count(), lcl_FindTable, &aPara ); + if( aPara.pTblNd ) + { + return SwServerObject( *aPara.pTblNd ).SetData( rMimeType, rValue ); + } + + return sal_False; +} + + + +::sfx2::SvLinkSource* SwDoc::CreateLinkSource(const String& rItem) +{ + SwServerObject* pObj = NULL; + + //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive + bool bCaseSensitive = true; + while( true ) + { + // bookmarks + ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, rItem, bCaseSensitive); + if(pBkmk && pBkmk->IsExpanded() + && (0 == (pObj = pBkmk->GetRefObject()))) + { + // mark found, but no link yet -> create hotlink + pObj = new SwServerObject(*pBkmk); + pBkmk->SetRefObject(pObj); + GetLinkManager().InsertServer(pObj); + } + if(pObj) + return pObj; + + _FindItem aPara(bCaseSensitive ? rItem : GetAppCharClass().lower(rItem)); + // sections + ((SwSectionFmts&)*pSectionFmtTbl).ForEach(0, pSectionFmtTbl->Count(), bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara); + if(aPara.pSectNd + && (0 == (pObj = aPara.pSectNd->GetSection().GetObject()))) + { + // section found, but no link yet -> create hotlink + pObj = new SwServerObject( *aPara.pSectNd ); + aPara.pSectNd->GetSection().SetRefObject( pObj ); + GetLinkManager().InsertServer(pObj); + } + if(pObj) + return pObj; + if( !bCaseSensitive ) + break; + bCaseSensitive = false; + } + + _FindItem aPara( GetAppCharClass().lower(rItem) ); + // tables + ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach(0, pTblFrmFmtTbl->Count(), lcl_FindTable, &aPara); + if(aPara.pTblNd + && (0 == (pObj = aPara.pTblNd->GetTable().GetObject()))) + { + // table found, but no link yet -> create hotlink + pObj = new SwServerObject(*aPara.pTblNd); + aPara.pTblNd->GetTable().SetRefObject(pObj); + GetLinkManager().InsertServer(pObj); + } + return pObj; +} + +sal_Bool SwDoc::SelectServerObj( const String& rStr, SwPaM*& rpPam, + SwNodeRange*& rpRange ) const +{ + // haben wir ueberhaupt das Item vorraetig? + rpPam = 0; + rpRange = 0; + + String sItem( INetURLObject::decode( rStr, INET_HEX_ESCAPE, + INetURLObject::DECODE_WITH_CHARSET, + RTL_TEXTENCODING_UTF8 )); + + xub_StrLen nPos = sItem.Search( cMarkSeperator ); + + const CharClass& rCC = GetAppCharClass(); + + // Erweiterung fuer die Bereiche, nicht nur Bookmarks/Bereiche linken, + // sondern auch Rahmen(Text!), Tabellen, Gliederungen: + if( STRING_NOTFOUND != nPos ) + { + sal_Bool bWeiter = sal_False; + String sName( sItem.Copy( 0, nPos ) ); + String sCmp( sItem.Copy( nPos + 1 )); + rCC.toLower( sItem ); + + _FindItem aPara( sName ); + + if( sCmp.EqualsAscii( pMarkToTable ) ) + { + rCC.toLower( sName ); + ((SwFrmFmts*)pTblFrmFmtTbl)->ForEach( 0, pTblFrmFmtTbl->Count(), + lcl_FindTable, &aPara ); + if( aPara.pTblNd ) + { + rpRange = new SwNodeRange( *aPara.pTblNd, 0, + *aPara.pTblNd->EndOfSectionNode(), 1 ); + return sal_True; + } + } + else if( sCmp.EqualsAscii( pMarkToFrame ) ) + { + SwNodeIndex* pIdx; + SwNode* pNd; + const SwFlyFrmFmt* pFlyFmt = FindFlyByName( sName ); + if( pFlyFmt && + 0 != ( pIdx = (SwNodeIndex*)pFlyFmt->GetCntnt().GetCntntIdx() ) && + !( pNd = &pIdx->GetNode())->IsNoTxtNode() ) + { + rpRange = new SwNodeRange( *pNd, 1, *pNd->EndOfSectionNode() ); + return sal_True; + } + } + else if( sCmp.EqualsAscii( pMarkToRegion ) ) + { + sItem = sName; // wird unten behandelt ! + bWeiter = sal_True; + } + else if( sCmp.EqualsAscii( pMarkToOutline ) ) + { + SwPosition aPos( SwNodeIndex( (SwNodes&)GetNodes() )); + if( GotoOutline( aPos, sName )) + { + SwNode* pNd = &aPos.nNode.GetNode(); + //sal_uInt8 nLvl = pNd->GetTxtNode()->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + const int nLvl = pNd->GetTxtNode()->GetAttrOutlineLevel()-1;//<-end,zhaojianwei + + const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); + sal_uInt16 nTmpPos; + rOutlNds.Seek_Entry( pNd, &nTmpPos ); + rpRange = new SwNodeRange( aPos.nNode, 0, aPos.nNode ); + + // dann suche jetzt noch das Ende vom Bereich + for( ++nTmpPos; + nTmpPos < rOutlNds.Count() && + nLvl < rOutlNds[ nTmpPos ]->GetTxtNode()-> + //GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + GetAttrOutlineLevel()-1;//<-end,zhaojianwei + ++nTmpPos ) + ; // es gibt keinen Block + + if( nTmpPos < rOutlNds.Count() ) + rpRange->aEnd = *rOutlNds[ nTmpPos ]; + else + rpRange->aEnd = GetNodes().GetEndOfContent(); + return sal_True; + } + } + + if( !bWeiter ) + return sal_False; + } + + //search for bookmarks and sections case senstive at first. If nothing is found then try again case insensitive + bool bCaseSensitive = true; + while( true ) + { + ::sw::mark::DdeBookmark* const pBkmk = lcl_FindDdeBookmark(*pMarkManager, sItem, bCaseSensitive); + if(pBkmk) + { + if(pBkmk->IsExpanded()) + rpPam = new SwPaM( + pBkmk->GetMarkPos(), + pBkmk->GetOtherMarkPos()); + return static_cast<bool>(rpPam); + } + + // + _FindItem aPara( bCaseSensitive ? sItem : rCC.lower( sItem ) ); + + if( pSectionFmtTbl->Count() ) + { + ((SwSectionFmts&)*pSectionFmtTbl).ForEach( 0, pSectionFmtTbl->Count(), + bCaseSensitive ? lcl_FindSectionCaseSensitive : lcl_FindSectionCaseInsensitive, &aPara ); + if( aPara.pSectNd ) + { + rpRange = new SwNodeRange( *aPara.pSectNd, 1, + *aPara.pSectNd->EndOfSectionNode() ); + return sal_True; + + } + } + if( !bCaseSensitive ) + break; + bCaseSensitive = false; + } + return sal_False; +} + diff --git a/sw/source/core/doc/docdesc.cxx b/sw/source/core/doc/docdesc.cxx new file mode 100644 index 000000000000..463e15bf6b6e --- /dev/null +++ b/sw/source/core/doc/docdesc.cxx @@ -0,0 +1,1018 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <vcl/virdev.hxx> +#include <svx/svdmodel.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/paperinf.hxx> +#include "editeng/frmdiritem.hxx" +#include <tools/urlobj.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/printer.hxx> +#include <unotools/localedatawrapper.hxx> +#include <com/sun/star/document/PrinterIndependentLayout.hpp> +#include <fmtfsize.hxx> +#include <fmthdft.hxx> +#include <fmtcntnt.hxx> +#include <fmtpdsc.hxx> +#include <ftninfo.hxx> +#include <fesh.hxx> +#include <ndole.hxx> +#include <mdiexp.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <pagefrm.hxx> //Fuer DelPageDesc +#include <rootfrm.hxx> //Fuer DelPageDesc +#include <ndtxt.hxx> +#include <frmtool.hxx> +#include <pagedesc.hxx> +#include <poolfmt.hxx> +#include <docsh.hxx> +#include <ndindex.hxx> +#include <ftnidx.hxx> +#include <fmtftn.hxx> +#include <txtftn.hxx> +#include <fntcache.hxx> +#include <viewsh.hxx> +#include <viewopt.hxx> +#include <fldbas.hxx> +#include <swwait.hxx> +#include <GetMetricVal.hxx> +#include <unotools/syslocale.hxx> +#include <statstr.hrc> +#include <hints.hxx> + +#include <SwUndoPageDesc.hxx> + +#include <tgrditem.hxx> + +using namespace com::sun::star; + +static void lcl_DefaultPageFmt( sal_uInt16 nPoolFmtId, + SwFrmFmt &rFmt1, + SwFrmFmt &rFmt2 ) +{ + // --> FME 2005-01-21 #i41075# Printer on demand + // This function does not require a printer anymore. + // The default page size is obtained from the application + //locale + // <-- + + SwFmtFrmSize aFrmSize( ATT_FIX_SIZE ); + const Size aPhysSize = SvxPaperInfo::GetDefaultPaperSize(); + aFrmSize.SetSize( aPhysSize ); + + //Auf Default-Raender vorbereiten. + //Raender haben eine defaultmaessige Mindestgroesse. + //wenn der Drucker einen groesseren Rand vorgibt, so + //ist mir dass auch recht. + // MIB 06/25/2002, #99397#: The HTML page desc had A4 as page size + // always. This has been changed to take the page size from the printer. + // Unfortunately, the margins of the HTML page desc are smaller than + // the margins used here in general, so one extra case is required. + // In the long term, this needs to be changed to always keep the + // margins from the page desc. + sal_Int32 nMinTop, nMinBottom, nMinLeft, nMinRight; + if( RES_POOLPAGE_HTML == nPoolFmtId ) + { + nMinRight = nMinTop = nMinBottom = GetMetricVal( CM_1 ); + nMinLeft = nMinRight * 2; + } + else if( MEASURE_METRIC == SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() ) + { + nMinTop = nMinBottom = nMinLeft = nMinRight = 1134; //2 Zentimeter + } + else + { + nMinTop = nMinBottom = 1440; //al la WW: 1Inch + nMinLeft = nMinRight = 1800; // 1,25 Inch + } + + //Raender einstellen. + SvxLRSpaceItem aLR( RES_LR_SPACE ); + SvxULSpaceItem aUL( RES_UL_SPACE ); + + aUL.SetUpper( (sal_uInt16)nMinTop ); + aUL.SetLower( (sal_uInt16)nMinBottom ); + aLR.SetRight( nMinRight ); + aLR.SetLeft( nMinLeft ); + + rFmt1.SetFmtAttr( aFrmSize ); + rFmt1.SetFmtAttr( aLR ); + rFmt1.SetFmtAttr( aUL ); + + rFmt2.SetFmtAttr( aFrmSize ); + rFmt2.SetFmtAttr( aLR ); + rFmt2.SetFmtAttr( aUL ); +} + +/************************************************************************* +|* +|* SwDoc::ChgPageDesc() +|* +|* Ersterstellung MA 25. Jan. 93 +|* Letzte Aenderung MA 01. Mar. 95 +|* +|*************************************************************************/ + +void lcl_DescSetAttr( const SwFrmFmt &rSource, SwFrmFmt &rDest, + const sal_Bool bPage = sal_True ) +{ +/////////////// !!!!!!!!!!!!!!!! +//JP 03.03.99: +// eigentlich sollte hier das Intersect von ItemSet benutzt werden, aber das +// funktioniert nicht richtig, wenn man unterschiedliche WhichRanges hat. +/////////////// !!!!!!!!!!!!!!!! + //Die interressanten Attribute uebernehmen. + sal_uInt16 __READONLY_DATA aIdArr[] = { RES_FRM_SIZE, RES_UL_SPACE, + RES_BACKGROUND, RES_SHADOW, + RES_COL, RES_COL, + RES_FRAMEDIR, RES_FRAMEDIR, + RES_TEXTGRID, RES_TEXTGRID, + // --> FME 2005-04-18 #i45539# + RES_HEADER_FOOTER_EAT_SPACING, + RES_HEADER_FOOTER_EAT_SPACING, + // <-- + RES_UNKNOWNATR_CONTAINER, + RES_UNKNOWNATR_CONTAINER, + 0 }; + + const SfxPoolItem* pItem; + for( sal_uInt16 n = 0; aIdArr[ n ]; n += 2 ) + { + for( sal_uInt16 nId = aIdArr[ n ]; nId <= aIdArr[ n+1]; ++nId ) + { + // --> FME 2005-04-18 #i45539# + // bPage == true: + // All in aIdArr except from RES_HEADER_FOOTER_EAT_SPACING + // bPage == false: + // All in aIdArr except from RES_COL and RES_PAPER_BIN: + // <-- + if( ( bPage && RES_HEADER_FOOTER_EAT_SPACING != nId ) || + ( !bPage && RES_COL != nId && RES_PAPER_BIN != nId )) + { + if( SFX_ITEM_SET == rSource.GetItemState( nId, sal_False, &pItem )) + rDest.SetFmtAttr( *pItem ); + else + rDest.ResetFmtAttr( nId ); + } + } + } + + // auch Pool-, Hilfe-Id's uebertragen + rDest.SetPoolFmtId( rSource.GetPoolFmtId() ); + rDest.SetPoolHelpId( rSource.GetPoolHelpId() ); + rDest.SetPoolHlpFileId( rSource.GetPoolHlpFileId() ); +} + + +void SwDoc::ChgPageDesc( sal_uInt16 i, const SwPageDesc &rChged ) +{ + ASSERT( i < aPageDescs.Count(), "PageDescs ueberindiziert." ); + + SwPageDesc *pDesc = aPageDescs[i]; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo(new SwUndoPageDesc(*pDesc, rChged, this)); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + //Als erstes wird ggf. gespiegelt. + if ( rChged.GetUseOn() == nsUseOnPage::PD_MIRROR ) + ((SwPageDesc&)rChged).Mirror(); + else + //sonst Werte aus Master nach Left uebertragen. + ::lcl_DescSetAttr( ((SwPageDesc&)rChged).GetMaster(), + ((SwPageDesc&)rChged).GetLeft() ); + + //NumType uebernehmen. + if( rChged.GetNumType().GetNumberingType() != pDesc->GetNumType().GetNumberingType() ) + { + pDesc->SetNumType( rChged.GetNumType() ); + // JP 30.03.99: Bug 64121 - den Seitennummernfeldern bescheid sagen, + // das sich das Num-Format geaendert hat + GetSysFldType( RES_PAGENUMBERFLD )->UpdateFlds(); + GetSysFldType( RES_REFPAGEGETFLD )->UpdateFlds(); + + // Wenn sich die Numerierungsart geaendert hat, koennte es QuoVadis/ + // ErgoSum-Texte geben, die sich auf eine geaenderte Seite beziehen, + // deshalb werden die Fussnoten invalidiert + SwFtnIdxs& rFtnIdxs = GetFtnIdxs(); + for( sal_uInt16 nPos = 0; nPos < rFtnIdxs.Count(); ++nPos ) + { + SwTxtFtn *pTxtFtn = rFtnIdxs[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + pTxtFtn->SetNumber( rFtn.GetNumber(), &rFtn.GetNumStr()); + } + } + + //Orientierung uebernehmen + pDesc->SetLandscape( rChged.GetLandscape() ); + + // #i46909# no undo if header or footer changed + bool bHeaderFooterChanged = false; + + //Header abgleichen. + const SwFmtHeader &rHead = rChged.GetMaster().GetHeader(); + if (undoGuard.UndoWasEnabled()) + { + // #i46909# no undo if header or footer changed + // hat sich an den Nodes etwas veraendert ? + const SwFmtHeader &rOldHead = pDesc->GetMaster().GetHeader(); + bHeaderFooterChanged |= + ( rHead.IsActive() != rOldHead.IsActive() || + rChged.IsHeaderShared() != pDesc->IsHeaderShared() ); + } + pDesc->GetMaster().SetFmtAttr( rHead ); + if ( rChged.IsHeaderShared() || !rHead.IsActive() ) + { + //Left teilt sich den Header mit dem Master. + pDesc->GetLeft().SetFmtAttr( pDesc->GetMaster().GetHeader() ); + } + else if ( rHead.IsActive() ) + { //Left bekommt einen eigenen Header verpasst wenn das Format nicht + //bereits einen hat. + //Wenn er bereits einen hat und dieser auf die gleiche Section + //wie der Rechte zeigt, so muss er einen eigenen bekommen. Der + //Inhalt wird sinnigerweise kopiert. + const SwFmtHeader &rLeftHead = pDesc->GetLeft().GetHeader(); + if ( !rLeftHead.IsActive() ) + { + SwFmtHeader aHead( MakeLayoutFmt( RND_STD_HEADERL, 0 ) ); + pDesc->GetLeft().SetFmtAttr( aHead ); + //Weitere Attribute (Raender, Umrandung...) uebernehmen. + ::lcl_DescSetAttr( *rHead.GetHeaderFmt(), *aHead.GetHeaderFmt(), sal_False); + } + else + { + const SwFrmFmt *pRight = rHead.GetHeaderFmt(); + const SwFmtCntnt &aRCnt = pRight->GetCntnt(); + const SwFmtCntnt &aLCnt = rLeftHead.GetHeaderFmt()->GetCntnt(); + if( !aLCnt.GetCntntIdx() ) + pDesc->GetLeft().SetFmtAttr( rChged.GetLeft().GetHeader() ); + else if( (*aRCnt.GetCntntIdx()) == (*aLCnt.GetCntntIdx()) ) + { + SwFrmFmt *pFmt = new SwFrmFmt( GetAttrPool(), "Header", + GetDfltFrmFmt() ); + ::lcl_DescSetAttr( *pRight, *pFmt, sal_False ); + //Der Bereich auf den das rechte Kopfattribut zeigt wird + //kopiert und der Index auf den StartNode in das linke + //Kopfattribut gehaengt. + SwNodeIndex aTmp( GetNodes().GetEndOfAutotext() ); + SwStartNode* pSttNd = GetNodes().MakeEmptySection( aTmp, SwHeaderStartNode ); + SwNodeRange aRange( aRCnt.GetCntntIdx()->GetNode(), 0, + *aRCnt.GetCntntIdx()->GetNode().EndOfSectionNode() ); + aTmp = *pSttNd->EndOfSectionNode(); + GetNodes()._Copy( aRange, aTmp, sal_False ); + + pFmt->SetFmtAttr( SwFmtCntnt( pSttNd ) ); + pDesc->GetLeft().SetFmtAttr( SwFmtHeader( pFmt ) ); + } + else + ::lcl_DescSetAttr( *pRight, + *(SwFrmFmt*)rLeftHead.GetHeaderFmt(), sal_False ); + + } + } + pDesc->ChgHeaderShare( rChged.IsHeaderShared() ); + + //Footer abgleichen. + const SwFmtFooter &rFoot = rChged.GetMaster().GetFooter(); + if (undoGuard.UndoWasEnabled()) + { + // #i46909# no undo if header or footer changed + // hat sich an den Nodes etwas veraendert ? + const SwFmtFooter &rOldFoot = pDesc->GetMaster().GetFooter(); + bHeaderFooterChanged |= + ( rFoot.IsActive() != rOldFoot.IsActive() || + rChged.IsFooterShared() != pDesc->IsFooterShared() ); + } + pDesc->GetMaster().SetFmtAttr( rFoot ); + if ( rChged.IsFooterShared() || !rFoot.IsActive() ) + //Left teilt sich den Header mit dem Master. + pDesc->GetLeft().SetFmtAttr( pDesc->GetMaster().GetFooter() ); + else if ( rFoot.IsActive() ) + { //Left bekommt einen eigenen Footer verpasst wenn das Format nicht + //bereits einen hat. + //Wenn er bereits einen hat und dieser auf die gleiche Section + //wie der Rechte zeigt, so muss er einen eigenen bekommen. Der + //Inhalt wird sinnigerweise kopiert. + const SwFmtFooter &rLeftFoot = pDesc->GetLeft().GetFooter(); + if ( !rLeftFoot.IsActive() ) + { + SwFmtFooter aFoot( MakeLayoutFmt( RND_STD_FOOTER, 0 ) ); + pDesc->GetLeft().SetFmtAttr( aFoot ); + //Weitere Attribute (Raender, Umrandung...) uebernehmen. + ::lcl_DescSetAttr( *rFoot.GetFooterFmt(), *aFoot.GetFooterFmt(), sal_False); + } + else + { + const SwFrmFmt *pRight = rFoot.GetFooterFmt(); + const SwFmtCntnt &aRCnt = pRight->GetCntnt(); + const SwFmtCntnt &aLCnt = rLeftFoot.GetFooterFmt()->GetCntnt(); + if( !aLCnt.GetCntntIdx() ) + pDesc->GetLeft().SetFmtAttr( rChged.GetLeft().GetFooter() ); + else if( (*aRCnt.GetCntntIdx()) == (*aLCnt.GetCntntIdx()) ) + { + SwFrmFmt *pFmt = new SwFrmFmt( GetAttrPool(), "Footer", + GetDfltFrmFmt() ); + ::lcl_DescSetAttr( *pRight, *pFmt, sal_False ); + //Der Bereich auf den das rechte Kopfattribut zeigt wird + //kopiert und der Index auf den StartNode in das linke + //Kopfattribut gehaengt. + SwNodeIndex aTmp( GetNodes().GetEndOfAutotext() ); + SwStartNode* pSttNd = GetNodes().MakeEmptySection( aTmp, SwFooterStartNode ); + SwNodeRange aRange( aRCnt.GetCntntIdx()->GetNode(), 0, + *aRCnt.GetCntntIdx()->GetNode().EndOfSectionNode() ); + aTmp = *pSttNd->EndOfSectionNode(); + GetNodes()._Copy( aRange, aTmp, sal_False ); + + pFmt->SetFmtAttr( SwFmtCntnt( pSttNd ) ); + pDesc->GetLeft().SetFmtAttr( SwFmtFooter( pFmt ) ); + } + else + ::lcl_DescSetAttr( *pRight, + *(SwFrmFmt*)rLeftFoot.GetFooterFmt(), sal_False ); + } + } + pDesc->ChgFooterShare( rChged.IsFooterShared() ); + + if ( pDesc->GetName() != rChged.GetName() ) + pDesc->SetName( rChged.GetName() ); + + // Dadurch wird ein RegisterChange ausgeloest, wenn notwendig + pDesc->SetRegisterFmtColl( rChged.GetRegisterFmtColl() ); + + //Wenn sich das UseOn oder der Follow aendern muessen die + //Absaetze das erfahren. + sal_Bool bUseOn = sal_False; + sal_Bool bFollow = sal_False; + if ( pDesc->GetUseOn() != rChged.GetUseOn() ) + { pDesc->SetUseOn( rChged.GetUseOn() ); + bUseOn = sal_True; + } + if ( pDesc->GetFollow() != rChged.GetFollow() ) + { if ( rChged.GetFollow() == &rChged ) + { if ( pDesc->GetFollow() != pDesc ) + { pDesc->SetFollow( pDesc ); + bFollow = sal_True; + } + } + else + { pDesc->SetFollow( rChged.pFollow ); + bFollow = sal_True; + } + } + + if ( (bUseOn || bFollow) && GetRootFrm() ) + //Layot benachrichtigen! + GetRootFrm()->CheckPageDescs( (SwPageFrm*)GetRootFrm()->Lower() ); + + //Jetzt noch die Seiten-Attribute uebernehmen. + ::lcl_DescSetAttr( rChged.GetMaster(), pDesc->GetMaster() ); + ::lcl_DescSetAttr( rChged.GetLeft(), pDesc->GetLeft() ); + + //Wenn sich FussnotenInfo veraendert, so werden die Seiten + //angetriggert. + if( !(pDesc->GetFtnInfo() == rChged.GetFtnInfo()) ) + { + pDesc->SetFtnInfo( rChged.GetFtnInfo() ); + SwMsgPoolItem aInfo( RES_PAGEDESC_FTNINFO ); + { + SwClientIter aIter( pDesc->GetMaster() ); + for( SwClient* pLast = aIter.First(TYPE(SwFrm)); pLast; + pLast = aIter.Next() ) + pLast->Modify( &aInfo, 0 ); + } + { + SwClientIter aIter( pDesc->GetLeft() ); + for( SwClient* pLast = aIter.First(TYPE(SwFrm)); pLast; + pLast = aIter.Next() ) + pLast->Modify( &aInfo, 0 ); + } + } + SetModified(); + + // #i46909# no undo if header or footer changed + if( bHeaderFooterChanged ) + { + GetIDocumentUndoRedo().DelAllUndoObj(); + } +} + +/************************************************************************* +|* +|* SwDoc::DelPageDesc() +|* +|* Beschreibung Alle Descriptoren, deren Follow auf den zu loeschenden +|* zeigen muessen angepasst werden. +|* Ersterstellung MA 25. Jan. 93 +|* Letzte Aenderung JP 04.09.95 +|* +|*************************************************************************/ + +void lcl_RemoveFrms( SwFrmFmt& rFmt, sal_Bool& rbFtnsRemoved ) +{ + SwClientIter aIter( rFmt ); + SwFrm *pFrm; + for( pFrm = (SwFrm*)aIter.First(TYPE(SwFrm)); pFrm; + pFrm = (SwFrm*)aIter.Next() ) + if ( !rbFtnsRemoved && pFrm->IsPageFrm() && + ((SwPageFrm*)pFrm)->IsFtnPage() ) + { + rFmt.getIDocumentLayoutAccess()->GetRootFrm()->RemoveFtns( 0, sal_False, sal_True ); + rbFtnsRemoved = sal_True; + } + else + { + pFrm->Cut(); + delete pFrm; + } +} + +// #i7983# +void SwDoc::PreDelPageDesc(SwPageDesc * pDel) +{ + if (0 == pDel) + return; + + SwFmtPageDesc aDfltDesc( aPageDescs[0] ); + SwClientIter aIter( *pDel ); + SwClient* pLast; + while( 0 != ( pLast = aIter.GoRoot() )) + { + if( pLast->ISA( SwFmtPageDesc ) ) + { + const SwModify* pMod = ((SwFmtPageDesc*)pLast)->GetDefinedIn(); + if ( pMod ) + { + if( pMod->ISA( SwCntntNode ) ) + ((SwCntntNode*)pMod)->SetAttr( aDfltDesc ); + else if( pMod->ISA( SwFmt )) + ((SwFmt*)pMod)->SetFmtAttr( aDfltDesc ); + else + { + ASSERT( !this, "was ist das fuer ein Mofify-Obj?" ); + aPageDescs[0]->Add( pLast ); + } + } + else //Es kann noch eine Undo-Kopie existieren + aPageDescs[0]->Add( pLast ); + } + + sal_Bool bFtnInf = sal_False; + if ( sal_True == (bFtnInf = pLast == pFtnInfo->GetPageDescDep()) || + pLast == pEndNoteInfo->GetPageDescDep() ) + { + aPageDescs[0]->Add( pLast ); + if ( GetRootFrm() ) + GetRootFrm()->CheckFtnPageDescs( !bFtnInf ); + } + } + + for ( sal_uInt16 j = 0; j < aPageDescs.Count(); ++j ) + { + if ( aPageDescs[j]->GetFollow() == pDel ) + { + aPageDescs[j]->SetFollow( 0 ); + //Clients des PageDesc sind die Attribute, denen sagen wir bescheid. + //die Attribute wiederum reichen die Meldung an die Absaetze weiter. + + //Layot benachrichtigen! + if( GetRootFrm() ) // ist nicht immer vorhanden!! (Orginizer) + GetRootFrm()->CheckPageDescs( (SwPageFrm*)GetRootFrm()->Lower() ); + } + } + + if( GetRootFrm() ) // ist nicht immer vorhanden!! (Orginizer) + { + //Wenn jetzt noch irgendwelche Seiten auf die FrmFmt'e (Master und Left) + //Zeigen (z.B. irgendwelche Fussnotenseiten), so muessen die Seiten + //vernichtet werden. + + // Wenn wir auf Endnotenseiten stossen, schmeissen wir alle Fussnoten weg, + // anders kann die Reihenfolge der Seiten (FollowsPageDescs usw.) + // nicht garantiert werden. + sal_Bool bFtnsRemoved = sal_False; + + ::lcl_RemoveFrms( pDel->GetMaster(), bFtnsRemoved ); + ::lcl_RemoveFrms( pDel->GetLeft(), bFtnsRemoved ); + } +} + +// #116530# +void SwDoc::BroadcastStyleOperation(String rName, SfxStyleFamily eFamily, + sal_uInt16 nOp) +{ + if (pDocShell) + { + SfxStyleSheetBasePool * pPool = pDocShell->GetStyleSheetPool(); + + if (pPool) + { + pPool->SetSearchMask(eFamily, SFXSTYLEBIT_ALL ); + SfxStyleSheetBase * pBase = pPool->Find(rName); + + if (pBase != NULL) + pPool->Broadcast(SfxStyleSheetHint( nOp, *pBase )); + } + } +} + +void SwDoc::DelPageDesc( sal_uInt16 i, sal_Bool bBroadcast ) +{ + ASSERT( i < aPageDescs.Count(), "PageDescs ueberindiziert." ); + ASSERT( i != 0, "Default Pagedesc loeschen is nicht." ); + if ( i == 0 ) + return; + + SwPageDesc *pDel = aPageDescs[i]; + + // -> #116530# + if (bBroadcast) + BroadcastStyleOperation(pDel->GetName(), SFX_STYLE_FAMILY_PAGE, + SFX_STYLESHEET_ERASED); + // <- #116530# + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo(new SwUndoPageDescDelete(*pDel, this)); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + PreDelPageDesc(pDel); // #i7983# + + aPageDescs.Remove( i ); + delete pDel; + SetModified(); +} + + + +/************************************************************************* +|* +|* SwDoc::MakePageDesc() +|* +|* Ersterstellung MA 25. Jan. 93 +|* Letzte Aenderung MA 20. Aug. 93 +|* +|*************************************************************************/ + +sal_uInt16 SwDoc::MakePageDesc( const String &rName, const SwPageDesc *pCpy, + sal_Bool bRegardLanguage, sal_Bool bBroadcast) // #116530# +{ + SwPageDesc *pNew; + if( pCpy ) + { + pNew = new SwPageDesc( *pCpy ); + pNew->SetName( rName ); + if( rName != pCpy->GetName() ) + { + pNew->SetPoolFmtId( USHRT_MAX ); + pNew->SetPoolHelpId( USHRT_MAX ); + pNew->SetPoolHlpFileId( UCHAR_MAX ); + } + } + else + { + pNew = new SwPageDesc( rName, GetDfltFrmFmt(), this ); + //Default-Seitenformat einstellen. + lcl_DefaultPageFmt( USHRT_MAX, pNew->GetMaster(), pNew->GetLeft() ); + + SvxFrameDirection aFrameDirection = bRegardLanguage ? + GetDefaultFrameDirection(GetAppLanguage()) + : FRMDIR_HORI_LEFT_TOP; + + pNew->GetMaster().SetFmtAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) ); + pNew->GetLeft().SetFmtAttr( SvxFrameDirectionItem(aFrameDirection, RES_FRAMEDIR) ); + } + aPageDescs.Insert( pNew, aPageDescs.Count() ); + + // -> #116530# + if (bBroadcast) + BroadcastStyleOperation(rName, SFX_STYLE_FAMILY_PAGE, + SFX_STYLESHEET_CREATED); + // <- #116530# + + if (GetIDocumentUndoRedo().DoesUndo()) + { + // #116530# + GetIDocumentUndoRedo().AppendUndo(new SwUndoPageDescCreate(pNew, this)); + } + + SetModified(); + return (aPageDescs.Count()-1); +} + +SwPageDesc* SwDoc::FindPageDescByName( const String& rName, sal_uInt16* pPos ) const +{ + SwPageDesc* pRet = 0; + if( pPos ) *pPos = USHRT_MAX; + + for( sal_uInt16 n = 0, nEnd = aPageDescs.Count(); n < nEnd; ++n ) + if( aPageDescs[ n ]->GetName() == rName ) + { + pRet = aPageDescs[ n ]; + if( pPos ) + *pPos = n; + break; + } + return pRet; +} + +/****************************************************************************** + * Methode : void SwDoc::PrtDataChanged() + * Beschreibung: + * Erstellt : OK 27.10.94 10:20 + * Aenderung : MA 26. Mar. 98 + ******************************************************************************/ + +void SwDoc::PrtDataChanged() +{ +//!!!!!!!! Bei Aenderungen hier bitte ggf. InJobSetup im Sw3io mitpflegen + + // --> FME 2005-01-21 #i41075# + ASSERT( get(IDocumentSettingAccess::USE_VIRTUAL_DEVICE) || + 0 != getPrinter( sal_False ), "PrtDataChanged will be called recursive!" ) + // <-- + + SwWait *pWait = 0; + sal_Bool bEndAction = sal_False; + + if( GetDocShell() ) + GetDocShell()->UpdateFontList(); + + sal_Bool bDraw = sal_True; + if ( GetRootFrm() ) + { + ViewShell *pSh = GetRootFrm()->GetCurrShell(); + if( !get(IDocumentSettingAccess::BROWSE_MODE) || + ( pSh && pSh->GetViewOptions()->IsPrtFormat() ) ) + { + if ( GetDocShell() ) + pWait = new SwWait( *GetDocShell(), sal_True ); + + GetRootFrm()->StartAllAction(); + bEndAction = sal_True; + + bDraw = sal_False; + if( pDrawModel ) + { + pDrawModel->SetAddExtLeading( get(IDocumentSettingAccess::ADD_EXT_LEADING) ); + pDrawModel->SetRefDevice( getReferenceDevice( false ) ); + } + + pFntCache->Flush(); + GetRootFrm()->InvalidateAllCntnt(); + + if ( pSh ) + { + do + { + pSh->InitPrt( pPrt ); + pSh = (ViewShell*)pSh->GetNext(); + } + while ( pSh != GetRootFrm()->GetCurrShell() ); + } + + } + } + if ( bDraw && pDrawModel ) + { + const sal_Bool bTmpAddExtLeading = get(IDocumentSettingAccess::ADD_EXT_LEADING); + if ( bTmpAddExtLeading != pDrawModel->IsAddExtLeading() ) + pDrawModel->SetAddExtLeading( bTmpAddExtLeading ); + + OutputDevice* pOutDev = getReferenceDevice( false ); + if ( pOutDev != pDrawModel->GetRefDevice() ) + pDrawModel->SetRefDevice( pOutDev ); + } + + PrtOLENotify( sal_True ); + + if ( bEndAction ) + GetRootFrm()->EndAllAction(); + delete pWait; +} + +//Zur Laufzeit sammeln wir die GlobalNames der Server, die keine +//Benachrichtigung zu Druckerwechseln wuenschen. Dadurch sparen wir +//das Laden vieler Objekte (gluecklicherweise werden obendrein alle +//Fremdobjekte unter einer ID abgebuildet). Init und DeInit vom Array +//ist in init.cxx zu finden. +extern SvPtrarr *pGlobalOLEExcludeList; + +void SwDoc::PrtOLENotify( sal_Bool bAll ) +{ + SwFEShell *pShell = 0; + if ( GetRootFrm() && GetRootFrm()->GetCurrShell() ) + { + ViewShell *pSh = GetRootFrm()->GetCurrShell(); + if ( !pSh->ISA(SwFEShell) ) + do + { pSh = (ViewShell*)pSh->GetNext(); + } while ( !pSh->ISA(SwFEShell) && + pSh != GetRootFrm()->GetCurrShell() ); + + if ( pSh->ISA(SwFEShell) ) + pShell = (SwFEShell*)pSh; + } + if ( !pShell ) + { + //Das hat ohne Shell und damit ohne Client keinen Sinn, weil nur darueber + //die Kommunikation bezueglich der Groessenaenderung implementiert ist. + //Da wir keine Shell haben, merken wir uns diesen unguenstigen + //Zustand am Dokument, dies wird dann beim Erzeugen der ersten Shell + //nachgeholt. + mbOLEPrtNotifyPending = sal_True; + if ( bAll ) + mbAllOLENotify = sal_True; + } + else + { + if ( mbAllOLENotify ) + bAll = sal_True; + + mbOLEPrtNotifyPending = mbAllOLENotify = sal_False; + + + SwOLENodes *pNodes = 0; + SwClientIter aIter( *(SwModify*)GetDfltGrfFmtColl() ); + for( SwCntntNode* pNd = (SwCntntNode*)aIter.First( TYPE( SwCntntNode ) ); + pNd; + pNd = (SwCntntNode*)aIter.Next() ) + { + SwOLENode *pONd; + if ( 0 != (pONd = pNd->GetOLENode()) && + (bAll || pONd->IsOLESizeInvalid()) ) + { + if ( !pNodes ) + pNodes = new SwOLENodes; + pNodes->Insert( pONd, pNodes->Count() ); + } + } + + if ( pNodes ) + { + ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY, + 0, pNodes->Count(), GetDocShell()); + GetRootFrm()->StartAllAction(); + + for( sal_uInt16 i = 0; i < pNodes->Count(); ++i ) + { + ::SetProgressState( i, GetDocShell() ); + + SwOLENode* pOLENd = (*pNodes)[i]; + pOLENd->SetOLESizeInvalid( sal_False ); + + //Ersteinmal die Infos laden und festellen ob das Teil nicht + //schon in der Exclude-Liste steht + SvGlobalName aName; + + svt::EmbeddedObjectRef& xObj = pOLENd->GetOLEObj().GetObject(); + if ( xObj.is() ) + aName = SvGlobalName( xObj->getClassID() ); + else //Noch nicht geladen + { + // TODO/LATER: retrieve ClassID of an unloaded object + // aName = ???? + } + + sal_Bool bFound = sal_False; + for ( sal_uInt16 j = 0; + j < pGlobalOLEExcludeList->Count() && !bFound; + ++j ) + { + bFound = *(SvGlobalName*)(*pGlobalOLEExcludeList)[j] == + aName; + } + if ( bFound ) + continue; + + //Kennen wir nicht, also muss das Objekt geladen werden. + //Wenn es keine Benachrichtigung wuenscht + if ( xObj.is() ) + { + //TODO/LATER: needs MiscStatus for ResizeOnPrinterChange + /* + if ( SVOBJ_MISCSTATUS_RESIZEONPRINTERCHANGE & xRef->GetMiscStatus()) + { + if ( pOLENd->GetFrm() ) + { + xObj->OnDocumentPrinterChanged( pPrt ); + pShell->CalcAndSetScale( xObj );//Client erzeugen lassen. + } + else + pOLENd->SetOLESizeInvalid( sal_True ); + } + else */ + pGlobalOLEExcludeList->Insert( + new SvGlobalName( aName ), + pGlobalOLEExcludeList->Count() ); + } + } + delete pNodes; + GetRootFrm()->EndAllAction(); + ::EndProgress( GetDocShell() ); + } + } +} + +IMPL_LINK( SwDoc, DoUpdateModifiedOLE, Timer *, ) +{ + SwFEShell* pSh = (SwFEShell*)GetEditShell(); + if( pSh ) + { + mbOLEPrtNotifyPending = mbAllOLENotify = sal_False; + + SwOLENodes aOLENodes; + SwClientIter aIter( *(SwModify*)GetDfltGrfFmtColl() ); + for( SwCntntNode* pNd = (SwCntntNode*)aIter.First( TYPE( SwCntntNode ) ); + pNd; + pNd = (SwCntntNode*)aIter.Next() ) + { + SwOLENode *pONd = pNd->GetOLENode(); + if( pONd && pONd->IsOLESizeInvalid() ) + { + aOLENodes.Insert( pONd, aOLENodes.Count() ); + } + } + + if( aOLENodes.Count() ) + { + ::StartProgress( STR_STATSTR_SWGPRTOLENOTIFY, + 0, aOLENodes.Count(), GetDocShell()); + GetRootFrm()->StartAllAction(); + SwMsgPoolItem aMsgHint( RES_UPDATE_ATTR ); + + for( sal_uInt16 i = 0; i < aOLENodes.Count(); ++i ) + { + ::SetProgressState( i, GetDocShell() ); + + SwOLENode* pOLENd = aOLENodes[i]; + pOLENd->SetOLESizeInvalid( sal_False ); + + //Kennen wir nicht, also muss das Objekt geladen werden. + //Wenn es keine Benachrichtigung wuenscht + if( pOLENd->GetOLEObj().GetOleRef().is() ) //Kaputt? + { + //TODO/LATER: needs MiscStatus for ResizeOnPrinterChange + /* + if( SVOBJ_MISCSTATUS_RESIZEONPRINTERCHANGE & + xRef->GetMiscStatus() ) + { + if( pOLENd->GetFrm() ) + { + xRef->OnDocumentPrinterChanged( pPrt ); + pSh->CalcAndSetScale( xRef );//Client erzeugen lassen. + } + else + pOLENd->SetOLESizeInvalid( sal_True ); + }*/ + // repaint it + pOLENd->Modify( &aMsgHint, &aMsgHint ); + } + } + GetRootFrm()->EndAllAction(); + ::EndProgress( GetDocShell() ); + } + } + return 0; +} + +sal_Bool SwDoc::FindPageDesc( const String & rName, sal_uInt16 * pFound) +{ + sal_Bool bResult = sal_False; + sal_uInt16 nI; + for (nI = 0; nI < aPageDescs.Count(); nI++) + { + if (aPageDescs[nI]->GetName() == rName) + { + *pFound = nI; + bResult = sal_True; + break; + } + } + + return bResult; +} + +SwPageDesc * SwDoc::GetPageDesc( const String & rName ) +{ + SwPageDesc * aResult = NULL; + + sal_uInt16 nI; + + if (FindPageDesc(rName, &nI)) + aResult = aPageDescs[nI]; + + return aResult; +} + +void SwDoc::DelPageDesc( const String & rName, sal_Bool bBroadcast ) // #116530# +{ + sal_uInt16 nI; + + if (FindPageDesc(rName, &nI)) + DelPageDesc(nI, bBroadcast); // #116530# +} + +void SwDoc::ChgPageDesc( const String & rName, const SwPageDesc & rDesc) +{ + sal_uInt16 nI; + + if (FindPageDesc(rName, &nI)) + ChgPageDesc(nI, rDesc); +} + +/* + * The HTML import cannot resist changing the page descriptions, I don't + * know why. This function is meant to check the page descriptors for invalid + * values. + */ +void SwDoc::CheckDefaultPageFmt() +{ + for ( sal_uInt16 i = 0; i < GetPageDescCnt(); ++i ) + { + SwPageDesc& rDesc = _GetPageDesc( i ); + + SwFrmFmt& rMaster = rDesc.GetMaster(); + SwFrmFmt& rLeft = rDesc.GetLeft(); + + const SwFmtFrmSize& rMasterSize = rMaster.GetFrmSize(); + const SwFmtFrmSize& rLeftSize = rLeft.GetFrmSize(); + + const bool bSetSize = LONG_MAX == rMasterSize.GetWidth() || + LONG_MAX == rMasterSize.GetHeight() || + LONG_MAX == rLeftSize.GetWidth() || + LONG_MAX == rLeftSize.GetHeight(); + + if ( bSetSize ) + lcl_DefaultPageFmt( rDesc.GetPoolFmtId(), rDesc.GetMaster(), rDesc.GetLeft() ); + } +} + +void SwDoc::SetDefaultPageMode(bool bSquaredPageMode) +{ + if( !bSquaredPageMode == !IsSquaredPageMode() ) + return; + + const SwTextGridItem& rGrid = + (const SwTextGridItem&)GetDefault( RES_TEXTGRID ); + SwTextGridItem aNewGrid = rGrid; + aNewGrid.SetSquaredMode(bSquaredPageMode); + aNewGrid.Init(); + SetDefault(aNewGrid); + + for ( sal_uInt16 i = 0; i < GetPageDescCnt(); ++i ) + { + SwPageDesc& rDesc = _GetPageDesc( i ); + + SwFrmFmt& rMaster = rDesc.GetMaster(); + SwFrmFmt& rLeft = rDesc.GetLeft(); + + SwTextGridItem aGrid((SwTextGridItem&)rMaster.GetFmtAttr(RES_TEXTGRID)); + aGrid.SwitchPaperMode( bSquaredPageMode ); + rMaster.SetFmtAttr(aGrid); + rLeft.SetFmtAttr(aGrid); + } +} + +sal_Bool SwDoc::IsSquaredPageMode() const +{ + const SwTextGridItem& rGrid = + (const SwTextGridItem&)GetDefault( RES_TEXTGRID ); + return rGrid.IsSquaredMode(); +} diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx new file mode 100644 index 000000000000..91d99221e1fd --- /dev/null +++ b/sw/source/core/doc/docdraw.cxx @@ -0,0 +1,1093 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <rtl/logfile.hxx> +#include <vcl/outdev.hxx> +#include <sfx2/printer.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/editeng.hxx> +#include <svx/svdoutl.hxx> +#include <editeng/colritem.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdogrp.hxx> +#include <editeng/langitem.hxx> +#include <editeng/unolingu.hxx> +#include <editeng/measfld.hxx> +#include <svx/svdpool.hxx> +#include <fmtanchr.hxx> +#include <charatr.hxx> +#include <frmfmt.hxx> +#include <charfmt.hxx> +#include <viewimp.hxx> +#include <swhints.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docsh.hxx> +#include <rootfrm.hxx> //Damit der RootDtor gerufen wird. +#include <poolfmt.hxx> +#include <viewsh.hxx> // fuer MakeDrawView +#include <drawdoc.hxx> +#include <UndoDraw.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <dcontact.hxx> +#include <dview.hxx> +#include <mvsave.hxx> +#include <flyfrm.hxx> +#include <dflyobj.hxx> +#include <svx/svdetc.hxx> +#include <editeng/fhgtitem.hxx> + +// OD 26.06.2003 #108784# +#include <svx/svdpagv.hxx> +// OD 2004-04-01 #i26791# +#include <dcontact.hxx> +#include <txtfrm.hxx> +#include <frmfmt.hxx> +#include <editeng/frmdiritem.hxx> +#include <fmtornt.hxx> +// --> OD 2006-03-14 #i62875# +#include <svx/svditer.hxx> +// <-- +// --> OD 2006-11-01 #130889# +#include <vector> +// <-- + +using namespace ::com::sun::star; +using namespace ::com::sun::star::linguistic2; + + +SV_IMPL_VARARR_SORT( _ZSortFlys, _ZSortFly ) + +/************************************************************************* +|* +|* SwDoc::GroupSelection / SwDoc::UnGroupSelection +|* +|* Ersterstellung JP 21.08.95 +|* Letzte Aenderung JP 21.08.95 +|* +|*************************************************************************/ +// OD 2004-04-01 #i26791# - local method to determine positioning and +// alignment attributes for a drawing object, which is newly connected to +// the layout. Used for a newly formed group object <SwDoc::GroupSelection(..)> +// and the members of a destroyed group <SwDoc::UnGroupSelection(..)> +void lcl_AdjustPositioningAttr( SwDrawFrmFmt* _pFrmFmt, + const SdrObject& _rSdrObj ) +{ + const SwContact* pContact = GetUserCall( &_rSdrObj ); + ASSERT( pContact, "<lcl_AdjustPositioningAttr(..)> - missing contact object." ); + + // determine position of new group object relative to its anchor frame position + SwTwips nHoriRelPos = 0; + SwTwips nVertRelPos = 0; + { + const SwFrm* pAnchorFrm = pContact->GetAnchoredObj( &_rSdrObj )->GetAnchorFrm(); + ASSERT( !pAnchorFrm || + !pAnchorFrm->IsTxtFrm() || + !static_cast<const SwTxtFrm*>(pAnchorFrm)->IsFollow(), + "<lcl_AdjustPositioningAttr(..)> - anchor frame is a follow. Please inform OD." ); + bool bVert = false; + bool bR2L = false; + // --> OD 2005-05-10 #i45952# - use anchor position of + // anchor frame, if it exist. + Point aAnchorPos; + if ( pAnchorFrm ) + { + // --> OD 2005-05-10 #i45952# + aAnchorPos = pAnchorFrm->GetFrmAnchorPos( ::HasWrap( &_rSdrObj ) ); + // <-- + bVert = pAnchorFrm->IsVertical(); + bR2L = pAnchorFrm->IsRightToLeft(); + } + else + { + // --> OD 2005-05-10 #i45952# + aAnchorPos = _rSdrObj.GetAnchorPos(); + // <-- + // If no anchor frame exist - e.g. because no layout exists - the + // default layout direction is taken. + const SvxFrameDirectionItem* pDirItem = + static_cast<const SvxFrameDirectionItem*>(&(_pFrmFmt->GetAttrSet().GetPool()->GetDefaultItem( RES_FRAMEDIR ))); + switch ( pDirItem->GetValue() ) + { + case FRMDIR_VERT_TOP_LEFT: + { + // vertical from left-to-right - Badaa: supported now! + bVert = true; + bR2L = true; + //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin + //ASSERT( false, "<lcl_AdjustPositioningAttr(..)> - vertical from left-to-right not supported." ); + //End + } + break; + case FRMDIR_VERT_TOP_RIGHT: + { + // vertical from right-to-left + bVert = true; + bR2L = false; + } + break; + case FRMDIR_HORI_RIGHT_TOP: + { + // horizontal from right-to-left + bVert = false; + bR2L = true; + } + break; + case FRMDIR_HORI_LEFT_TOP: + { + // horizontal from left-to-right + bVert = false; + bR2L = false; + } + break; + } + + } + // use geometry of drawing object + const SwRect aObjRect = _rSdrObj.GetSnapRect(); + + if ( bVert ) + { + if ( bR2L ) { + //FRMDIR_VERT_TOP_LEFT + nHoriRelPos = aObjRect.Left() - aAnchorPos.X(); + nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); + } else { + //FRMDIR_VERT_TOP_RIGHT + nHoriRelPos = aObjRect.Top() - aAnchorPos.Y(); + nVertRelPos = aAnchorPos.X() - aObjRect.Right(); + } + } + else if ( bR2L ) + { + nHoriRelPos = aAnchorPos.X() - aObjRect.Right(); + nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); + } + else + { + nHoriRelPos = aObjRect.Left() - aAnchorPos.X(); + nVertRelPos = aObjRect.Top() - aAnchorPos.Y(); + } + //End of SCMS + } + + _pFrmFmt->SetFmtAttr( SwFmtHoriOrient( nHoriRelPos, text::HoriOrientation::NONE, text::RelOrientation::FRAME ) ); + _pFrmFmt->SetFmtAttr( SwFmtVertOrient( nVertRelPos, text::VertOrientation::NONE, text::RelOrientation::FRAME ) ); + // --> OD 2005-03-11 #i44334#, #i44681# - positioning attributes already set + _pFrmFmt->PosAttrSet(); + // <-- + // --> OD 2004-10-01 #i34750# - keep current object rectangle for drawing + // objects. The object rectangle is used on events from the drawing layer + // to adjust the positioning attributes - see <SwDrawContact::_Changed(..)>. + { + const SwAnchoredObject* pAnchoredObj = pContact->GetAnchoredObj( &_rSdrObj ); + if ( pAnchoredObj->ISA(SwAnchoredDrawObject) ) + { + const SwAnchoredDrawObject* pAnchoredDrawObj = + static_cast<const SwAnchoredDrawObject*>(pAnchoredObj); + const SwRect aObjRect = _rSdrObj.GetSnapRect(); + const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj) + ->SetLastObjRect( aObjRect.SVRect() ); + } + } + // <-- +} + +SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView ) +{ + // OD 30.06.2003 #108784# - replace marked 'virtual' drawing objects by + // the corresponding 'master' drawing objects. + SwDrawView::ReplaceMarkedDrawVirtObjs( rDrawView ); + + const SdrMarkList &rMrkList = rDrawView.GetMarkedObjectList(); + SwDrawFrmFmt *pFmt = 0L; + SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); + sal_Bool bNoGroup = ( 0 == pObj->GetUpGroup() ); + SwDrawContact* pNewContact = 0; + if( bNoGroup ) + { + //Ankerattribut aufheben. + SwDrawContact *pMyContact = (SwDrawContact*)GetUserCall(pObj); + const SwFmtAnchor aAnch( pMyContact->GetFmt()->GetAnchor() ); + + SwUndoDrawGroup *const pUndo = (!GetIDocumentUndoRedo().DoesUndo()) + ? 0 + : new SwUndoDrawGroup( (sal_uInt16)rMrkList.GetMarkCount() ); + + // --> OD 2005-08-16 #i53320# + bool bGroupMembersNotPositioned( false ); + { + SwAnchoredDrawObject* pAnchoredDrawObj = + static_cast<SwAnchoredDrawObject*>(pMyContact->GetAnchoredObj( pObj )); + bGroupMembersNotPositioned = pAnchoredDrawObj->NotYetPositioned(); + } + // <-- + //ContactObjekte und Formate vernichten. + for( sal_uInt16 i = 0; i < rMrkList.GetMarkCount(); ++i ) + { + pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + + // --> OD 2005-08-16 #i53320# +#ifdef DBG_UTIL + SwAnchoredDrawObject* pAnchoredDrawObj = + static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj )); + ASSERT( bGroupMembersNotPositioned == pAnchoredDrawObj->NotYetPositioned(), + "<SwDoc::GroupSelection(..)> - group members have different positioning status!" ); +#endif + // <-- + + pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + //loescht sich selbst! + pContact->Changed(*pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + if( pUndo ) + pUndo->AddObj( i, pFmt, pObj ); + else + DelFrmFmt( pFmt ); + + // --> OD 2005-05-10 #i45952# - re-introduce position + // normalization of group member objects, because its anchor position + // is cleared, when they are grouped. + Point aAnchorPos( pObj->GetAnchorPos() ); + pObj->NbcSetAnchorPos( Point( 0, 0 ) ); + pObj->NbcMove( Size( aAnchorPos.X(), aAnchorPos.Y() ) ); + // <-- + } + + pFmt = MakeDrawFrmFmt( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "DrawObject" )), + GetDfltFrmFmt() ); + pFmt->SetFmtAttr( aAnch ); + // --> OD 2004-10-25 #i36010# - set layout direction of the position + pFmt->SetPositionLayoutDir( + text::PositionLayoutDir::PositionInLayoutDirOfAnchor ); + // <-- + + rDrawView.GroupMarked(); + ASSERT( rMrkList.GetMarkCount() == 1, "GroupMarked more or none groups." ); + + SdrObject* pNewGroupObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); + pNewContact = new SwDrawContact( pFmt, pNewGroupObj ); + // --> OD 2004-11-22 #i35635# + pNewContact->MoveObjToVisibleLayer( pNewGroupObj ); + // <-- + pNewContact->ConnectToLayout(); + // --> OD 2005-08-16 #i53320# - No adjustment of the positioning and + // alignment attributes, if group members aren't positioned yet. + if ( !bGroupMembersNotPositioned ) + { + // OD 2004-04-01 #i26791# - Adjust positioning and alignment attributes. + lcl_AdjustPositioningAttr( pFmt, *pNewGroupObj ); + } + // <-- + + if( pUndo ) + { + pUndo->SetGroupFmt( pFmt ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + else + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + } + + rDrawView.GroupMarked(); + ASSERT( rMrkList.GetMarkCount() == 1, "GroupMarked more or none groups." ); + } + + return pNewContact; +} + + +void SwDoc::UnGroupSelection( SdrView& rDrawView ) +{ + bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); + if( bUndo ) + { + GetIDocumentUndoRedo().ClearRedo(); + } + + // OD 30.06.2003 #108784# - replace marked 'virtual' drawing objects by + // the corresponding 'master' drawing objects. + SwDrawView::ReplaceMarkedDrawVirtObjs( rDrawView ); + + const SdrMarkList &rMrkList = rDrawView.GetMarkedObjectList(); + // --> OD 2006-11-01 #130889# + std::vector< std::pair< SwDrawFrmFmt*, SdrObject* > >* pFmtsAndObjs( 0L ); + const sal_uInt32 nMarkCount( rMrkList.GetMarkCount() ); + // <-- + if ( nMarkCount ) + { + // --> OD 2006-11-01 #130889# + pFmtsAndObjs = new std::vector< std::pair< SwDrawFrmFmt*, SdrObject* > >[nMarkCount]; + // <-- + SdrObject *pMyObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); + if( !pMyObj->GetUpGroup() ) + { + String sDrwFmtNm( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM("DrawObject" ))); + for ( sal_uInt16 i = 0; i < nMarkCount; ++i ) + { + SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); + if ( pObj->IsA( TYPE(SdrObjGroup) ) ) + { + SwDrawContact *pContact = (SwDrawContact*)GetUserCall(pObj); + SwFmtAnchor aAnch( pContact->GetFmt()->GetAnchor() ); + SdrObjList *pLst = ((SdrObjGroup*)pObj)->GetSubList(); + + SwUndoDrawUnGroup* pUndo = 0; + if( bUndo ) + { + pUndo = new SwUndoDrawUnGroup( (SdrObjGroup*)pObj ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + for ( sal_uInt16 i2 = 0; i2 < pLst->GetObjCount(); ++i2 ) + { + SdrObject* pSubObj = pLst->GetObj( i2 ); + SwDrawFrmFmt *pFmt = MakeDrawFrmFmt( sDrwFmtNm, + GetDfltFrmFmt() ); + pFmt->SetFmtAttr( aAnch ); + // --> OD 2004-10-25 #i36010# - set layout direction of the position + pFmt->SetPositionLayoutDir( + text::PositionLayoutDir::PositionInLayoutDirOfAnchor ); + // <-- + // --> OD 2006-11-01 #130889# + // creation of <SwDrawContact> instances for the group + // members and its connection to the Writer layout is + // done after intrinsic ungrouping. +// SwDrawContact* pContact = new SwDrawContact( pFmt, pSubObj ); +// // --> OD 2004-11-22 #i35635# +// pContact->MoveObjToVisibleLayer( pSubObj ); +// // <-- +// pContact->ConnectToLayout(); +// // OD 2004-04-07 #i26791# - Adjust positioning and +// // alignment attributes. +// lcl_AdjustPositioningAttr( pFmt, *pSubObj ); + pFmtsAndObjs[i].push_back( std::pair< SwDrawFrmFmt*, SdrObject* >( pFmt, pSubObj ) ); + // <-- + + if( bUndo ) + pUndo->AddObj( i2, pFmt ); + } + } + } + } + } + rDrawView.UnGroupMarked(); + // --> OD 2006-11-01 #130889# + // creation of <SwDrawContact> instances for the former group members and + // its connection to the Writer layout. + for ( sal_uInt32 i = 0; i < nMarkCount; ++i ) + { + SwUndoDrawUnGroupConnectToLayout* pUndo = 0; + if( bUndo ) + { + pUndo = new SwUndoDrawUnGroupConnectToLayout(); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + while ( pFmtsAndObjs[i].size() > 0 ) + { + SwDrawFrmFmt* pFmt( pFmtsAndObjs[i].back().first ); + SdrObject* pObj( pFmtsAndObjs[i].back().second ); + pFmtsAndObjs[i].pop_back(); + + SwDrawContact* pContact = new SwDrawContact( pFmt, pObj ); + pContact->MoveObjToVisibleLayer( pObj ); + pContact->ConnectToLayout(); + lcl_AdjustPositioningAttr( pFmt, *pObj ); + + if ( bUndo ) + { + pUndo->AddFmtAndObj( pFmt, pObj ); + } + } + } + delete [] pFmtsAndObjs; + // <-- +} + +/************************************************************************* +|* +|* SwDoc::DeleteSelection() +|* +|* Ersterstellung MA 14. Nov. 95 +|* Letzte Aenderung MA 14. Nov. 95 +|* +|*************************************************************************/ + +sal_Bool SwDoc::DeleteSelection( SwDrawView& rDrawView ) +{ + sal_Bool bCallBase = sal_False; + const SdrMarkList &rMrkList = rDrawView.GetMarkedObjectList(); + if( rMrkList.GetMarkCount() ) + { + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); + sal_uInt16 i; + sal_Bool bDelMarked = sal_True; + + if( 1 == rMrkList.GetMarkCount() ) + { + SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); + if( pObj->ISA(SwVirtFlyDrawObj) ) + { + SwFlyFrmFmt* pFrmFmt = (SwFlyFrmFmt*) + ((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetFmt(); + if( pFrmFmt ) + { + DelLayoutFmt( pFrmFmt ); + bDelMarked = sal_False; + } + } + } + + for( i = 0; i < rMrkList.GetMarkCount(); ++i ) + { + SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj(); + if( !pObj->ISA(SwVirtFlyDrawObj) ) + { + SwDrawContact *pC = (SwDrawContact*)GetUserCall(pObj); + SwDrawFrmFmt *pFrmFmt = (SwDrawFrmFmt*)pC->GetFmt(); + if( pFrmFmt && + FLY_AS_CHAR == pFrmFmt->GetAnchor().GetAnchorId() ) + { + rDrawView.MarkObj( pObj, rDrawView.Imp().GetPageView(), sal_True ); + --i; + DelLayoutFmt( pFrmFmt ); + } + } + } + + if( rMrkList.GetMarkCount() && bDelMarked ) + { + SdrObject *pObj = rMrkList.GetMark( 0 )->GetMarkedSdrObj(); + if( !pObj->GetUpGroup() ) + { + SwUndoDrawDelete *const pUndo = + (!GetIDocumentUndoRedo().DoesUndo()) + ? 0 + : new SwUndoDrawDelete( (sal_uInt16)rMrkList.GetMarkCount() ); + + //ContactObjekte vernichten, Formate sicherstellen. + for( i = 0; i < rMrkList.GetMarkCount(); ++i ) + { + const SdrMark& rMark = *rMrkList.GetMark( i ); + pObj = rMark.GetMarkedSdrObj(); + SwDrawContact *pContact = (SwDrawContact*)pObj->GetUserCall(); + if( pContact ) // natuerlich nicht bei gruppierten Objekten + { + SwDrawFrmFmt *pFmt = (SwDrawFrmFmt*)pContact->GetFmt(); + // OD 18.06.2003 #108784# - before delete of selection + // is performed, marked <SwDrawVirtObj>-objects have to + // be replaced by its reference objects. + // Thus, assert, if a <SwDrawVirt>-object is found in the mark list. + if ( pObj->ISA(SwDrawVirtObj) ) + { + ASSERT( false, + "<SwDrawVirtObj> is still marked for delete. application will crash!" ); + } + //loescht sich selbst! + pContact->Changed(*pObj, SDRUSERCALL_DELETE, pObj->GetLastBoundRect() ); + pObj->SetUserCall( 0 ); + + if( pUndo ) + pUndo->AddObj( i, pFmt, rMark ); + else + DelFrmFmt( pFmt ); + } + } + + if( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + } + bCallBase = sal_True; + } + SetModified(); + + GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); + } + + return bCallBase; +} + +/************************************************************************* +|* +|* SwDoc::DeleteSelection() +|* +|* Ersterstellung JP 11.01.96 +|* Letzte Aenderung JP 11.01.96 +|* +|*************************************************************************/ + +_ZSortFly::_ZSortFly( const SwFrmFmt* pFrmFmt, const SwFmtAnchor* pFlyAn, + sal_uInt32 nArrOrdNum ) + : pFmt( pFrmFmt ), pAnchor( pFlyAn ), nOrdNum( nArrOrdNum ) +{ + // #i11176# + // This also needs to work when no layout exists. Thus, for + // FlyFrames an alternative method is used now in that case. + SwClientIter aIter( (SwFmt&)*pFmt ); + + if( RES_FLYFRMFMT == pFmt->Which() ) + { + if( pFmt->getIDocumentLayoutAccess()->GetRootFrm() ) + { + // Schauen, ob es ein SdrObject dafuer gibt + if( aIter.First( TYPE( SwFlyFrm) ) ) + nOrdNum = ((SwFlyFrm*)aIter())->GetVirtDrawObj()->GetOrdNum(); + } + else + { + // Schauen, ob es ein SdrObject dafuer gibt + if( aIter.First( TYPE(SwFlyDrawContact) ) ) + nOrdNum = ((SwFlyDrawContact*)aIter())->GetMaster()->GetOrdNum(); + } + } + else if( RES_DRAWFRMFMT == pFmt->Which() ) + { + // Schauen, ob es ein SdrObject dafuer gibt + if( aIter.First( TYPE(SwDrawContact) ) ) + nOrdNum = ((SwDrawContact*)aIter())->GetMaster()->GetOrdNum(); + } + else { + ASSERT( !this, "was ist das fuer ein Format?" ); + } +} + +/*************************************************************************/ +// Wird auch vom Sw3-Reader gerufen, wenn ein Fehler beim Einlesen +// des Drawing Layers auftrat. In diesem Fall wird der Layer komplett +// neu aufgebaut. + +// #75371# +#include <svx/sxenditm.hxx> + +void SwDoc::InitDrawModel() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLog, "SW", "JP93722", "SwDoc::InitDrawModel" ); + + //!!Achtung im sw3-Reader (sw3imp.cxx) gibt es aehnlichen Code, der + //mitgepfelgt werden muss. + if ( pDrawModel ) + ReleaseDrawModel(); + + //DrawPool und EditEnginePool anlegen, diese gehoeren uns und werden + //dem Drawing nur mitgegeben. Im ReleaseDrawModel werden die Pools wieder + //zerstoert. + // 17.2.99: for Bug 73110 - for loading the drawing items. This must + // be loaded without RefCounts! + SfxItemPool *pSdrPool = new SdrItemPool( &GetAttrPool() ); + // #75371# change DefaultItems for the SdrEdgeObj distance items + // to TWIPS. + if(pSdrPool) + { + const long nDefEdgeDist = ((500 * 72) / 127); // 1/100th mm in twips + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode1VertDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2HorzDistItem(nDefEdgeDist)); + pSdrPool->SetPoolDefaultItem(SdrEdgeNode2VertDistItem(nDefEdgeDist)); + + // #i33700# + // Set shadow distance defaults as PoolDefaultItems. Details see bug. + pSdrPool->SetPoolDefaultItem(SdrShadowXDistItem((300 * 72) / 127)); + pSdrPool->SetPoolDefaultItem(SdrShadowYDistItem((300 * 72) / 127)); + } + SfxItemPool *pEEgPool = EditEngine::CreatePool( sal_False ); + pSdrPool->SetSecondaryPool( pEEgPool ); + if ( !GetAttrPool().GetFrozenIdRanges () ) + GetAttrPool().FreezeIdRanges(); + else + pSdrPool->FreezeIdRanges(); + + // SJ: #95129# set FontHeight pool defaults without changing static SdrEngineDefaults + GetAttrPool().SetPoolDefaultItem(SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT )); + + RTL_LOGFILE_CONTEXT_TRACE( aLog, "before create DrawDocument" ); + //Das SdrModel gehoert dem Dokument, wir haben immer zwei Layer und eine + //Seite. + pDrawModel = new SwDrawDocument( this ); + + pDrawModel->EnableUndo( GetIDocumentUndoRedo().DoesUndo() ); + + String sLayerNm; + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("Hell" )); + nHell = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("Heaven" )); + nHeaven = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("Controls" )); + nControls = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + + // OD 25.06.2003 #108784# - add invisible layers corresponding to the + // visible ones. + { + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleHell" )); + nInvisibleHell = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleHeaven" )); + nInvisibleHeaven = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleControls" )); + nInvisibleControls = pDrawModel->GetLayerAdmin().NewLayer( sLayerNm )->GetID(); + } + + pDrawModel->InsertPage( pDrawModel->AllocPage( sal_False ) ); + RTL_LOGFILE_CONTEXT_TRACE( aLog, "after create DrawDocument" ); + + RTL_LOGFILE_CONTEXT_TRACE( aLog, "before create Spellchecker/Hyphenator" ); + SdrOutliner& rOutliner = pDrawModel->GetDrawOutliner(); + uno::Reference< XSpellChecker1 > xSpell = ::GetSpellChecker(); + rOutliner.SetSpeller( xSpell ); + uno::Reference<XHyphenator> xHyphenator( ::GetHyphenator() ); + rOutliner.SetHyphenator( xHyphenator ); + RTL_LOGFILE_CONTEXT_TRACE( aLog, "after create Spellchecker/Hyphenator" ); + + SetCalcFieldValueHdl(&rOutliner); + SetCalcFieldValueHdl(&pDrawModel->GetHitTestOutliner()); + + //JP 16.07.98: Bug 50193 - Linkmanager am Model setzen, damit + // dort ggfs. verlinkte Grafiken eingefuegt werden koennen + //JP 28.01.99: der WinWord Import benoetigt ihn auch + pDrawModel->SetLinkManager( &GetLinkManager() ); + pDrawModel->SetAddExtLeading( get(IDocumentSettingAccess::ADD_EXT_LEADING) ); + + OutputDevice* pRefDev = getReferenceDevice( false ); + if ( pRefDev ) + pDrawModel->SetRefDevice( pRefDev ); + + pDrawModel->SetNotifyUndoActionHdl( LINK( this, SwDoc, AddDrawUndo )); + if ( pLayout ) + { + pLayout->SetDrawPage( pDrawModel->GetPage( 0 ) ); + pLayout->GetDrawPage()->SetSize( pLayout->Frm().SSize() ); + } +} + +/** method to notify drawing page view about the invisible layers + + OD 26.06.2003 #108784# + + @author OD +*/ +void SwDoc::NotifyInvisibleLayers( SdrPageView& _rSdrPageView ) +{ + String sLayerNm; + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleHell" )); + _rSdrPageView.SetLayerVisible( sLayerNm, sal_False ); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleHeaven" )); + _rSdrPageView.SetLayerVisible( sLayerNm, sal_False ); + + sLayerNm.AssignAscii(RTL_CONSTASCII_STRINGPARAM("InvisibleControls" )); + _rSdrPageView.SetLayerVisible( sLayerNm, sal_False ); +} + +/** method to determine, if a layer ID belongs to the visible ones. + + OD 25.06.2003 #108784# + Note: If given layer ID is unknown, method asserts and returns <false>. + + @author OD +*/ +bool SwDoc::IsVisibleLayerId( const SdrLayerID& _nLayerId ) const +{ + bool bRetVal; + + if ( _nLayerId == GetHeavenId() || + _nLayerId == GetHellId() || + _nLayerId == GetControlsId() ) + { + bRetVal = true; + } + else if ( _nLayerId == GetInvisibleHeavenId() || + _nLayerId == GetInvisibleHellId() || + _nLayerId == GetInvisibleControlsId() ) + { + bRetVal = false; + } + else + { + ASSERT( false, "<SwDoc::IsVisibleLayerId(..)> - unknown layer ID." ); + bRetVal = false; + } + + return bRetVal; +} + +/** method to determine, if the corresponding visible layer ID for a invisible one. + + OD 25.06.2003 #108784# + Note: If given layer ID is a visible one, method returns given layer ID. + Note: If given layer ID is unknown, method returns given layer ID. + + @author OD +*/ +SdrLayerID SwDoc::GetVisibleLayerIdByInvisibleOne( const SdrLayerID& _nInvisibleLayerId ) +{ + SdrLayerID nVisibleLayerId; + + if ( _nInvisibleLayerId == GetInvisibleHeavenId() ) + { + nVisibleLayerId = GetHeavenId(); + } + else if ( _nInvisibleLayerId == GetInvisibleHellId() ) + { + nVisibleLayerId = GetHellId(); + } + else if ( _nInvisibleLayerId == GetInvisibleControlsId() ) + { + nVisibleLayerId = GetControlsId(); + } + else if ( _nInvisibleLayerId == GetHeavenId() || + _nInvisibleLayerId == GetHellId() || + _nInvisibleLayerId == GetControlsId() ) + { + ASSERT( false, "<SwDoc::GetVisibleLayerIdByInvisibleOne(..)> - given layer ID already an invisible one." ); + nVisibleLayerId = _nInvisibleLayerId; + } + else + { + ASSERT( false, "<SwDoc::GetVisibleLayerIdByInvisibleOne(..)> - given layer ID is unknown." ); + nVisibleLayerId = _nInvisibleLayerId; + } + + return nVisibleLayerId; +} + +/** method to determine, if the corresponding invisible layer ID for a visible one. + + OD 25.06.2003 #108784# + Note: If given layer ID is a invisible one, method returns given layer ID. + Note: If given layer ID is unknown, method returns given layer ID. + + @author OD +*/ +SdrLayerID SwDoc::GetInvisibleLayerIdByVisibleOne( const SdrLayerID& _nVisibleLayerId ) +{ + SdrLayerID nInvisibleLayerId; + + if ( _nVisibleLayerId == GetHeavenId() ) + { + nInvisibleLayerId = GetInvisibleHeavenId(); + } + else if ( _nVisibleLayerId == GetHellId() ) + { + nInvisibleLayerId = GetInvisibleHellId(); + } + else if ( _nVisibleLayerId == GetControlsId() ) + { + nInvisibleLayerId = GetInvisibleControlsId(); + } + else if ( _nVisibleLayerId == GetInvisibleHeavenId() || + _nVisibleLayerId == GetInvisibleHellId() || + _nVisibleLayerId == GetInvisibleControlsId() ) + { + ASSERT( false, "<SwDoc::GetInvisibleLayerIdByVisibleOne(..)> - given layer ID already an invisible one." ); + nInvisibleLayerId = _nVisibleLayerId; + } + else + { + ASSERT( false, "<SwDoc::GetInvisibleLayerIdByVisibleOne(..)> - given layer ID is unknown." ); + nInvisibleLayerId = _nVisibleLayerId; + } + + return nInvisibleLayerId; +} + +/*************************************************************************/ + + +void SwDoc::ReleaseDrawModel() +{ + if ( pDrawModel ) + { + //!!Den code im sw3io fuer Einfuegen Dokument mitpflegen!! + + delete pDrawModel; pDrawModel = 0; + SfxItemPool *pSdrPool = GetAttrPool().GetSecondaryPool(); + + ASSERT( pSdrPool, "missing Pool" ); + SfxItemPool *pEEgPool = pSdrPool->GetSecondaryPool(); + ASSERT( !pEEgPool->GetSecondaryPool(), "i don't accept additional pools"); + pSdrPool->Delete(); //Erst die Items vernichten lassen, + //dann erst die Verkettung loesen + GetAttrPool().SetSecondaryPool( 0 ); //Der ist ein muss! + pSdrPool->SetSecondaryPool( 0 ); //Der ist sicherer + SfxItemPool::Free(pSdrPool); + SfxItemPool::Free(pEEgPool); + } +} + +/*************************************************************************/ + + +SdrModel* SwDoc::_MakeDrawModel() +{ + ASSERT( !pDrawModel, "_MakeDrawModel: Why?" ); + InitDrawModel(); + if ( pLayout && pLayout->GetCurrShell() ) + { + ViewShell* pTmp = pLayout->GetCurrShell(); + do + { + pTmp->MakeDrawView(); + pTmp = (ViewShell*) pTmp->GetNext(); + } while ( pTmp != pLayout->GetCurrShell() ); + + //Broadcast, damit die FormShell mit der DrawView verbunden werden kann + if( GetDocShell() ) + { + SfxSimpleHint aHnt( SW_BROADCAST_DRAWVIEWS_CREATED ); + GetDocShell()->Broadcast( aHnt ); + } + } + return pDrawModel; +} + +/*************************************************************************/ + +void SwDoc::DrawNotifyUndoHdl() +{ + pDrawModel->SetNotifyUndoActionHdl( Link() ); +} + +/************************************************************************* +* +* Am Outliner Link auf Methode fuer Felddarstellung in Editobjekten setzen +* +*************************************************************************/ + +void SwDoc::SetCalcFieldValueHdl(Outliner* pOutliner) +{ + pOutliner->SetCalcFieldValueHdl(LINK(this, SwDoc, CalcFieldValueHdl)); +} + +/************************************************************************* +|* +|* Felder bzw URLs im Outliner erkennen und Darstellung festlegen +|* +\************************************************************************/ + +IMPL_LINK(SwDoc, CalcFieldValueHdl, EditFieldInfo*, pInfo) +{ + if (pInfo) + { + const SvxFieldItem& rField = pInfo->GetField(); + const SvxFieldData* pField = rField.GetField(); + + if (pField && pField->ISA(SvxDateField)) + { + /****************************************************************** + * Date-Field + ******************************************************************/ + pInfo->SetRepresentation( + ((const SvxDateField*) pField)->GetFormatted( + *GetNumberFormatter( sal_True ), LANGUAGE_SYSTEM) ); + } + else if (pField && pField->ISA(SvxURLField)) + { + /****************************************************************** + * URL-Field + ******************************************************************/ + + switch ( ((const SvxURLField*) pField)->GetFormat() ) + { + case SVXURLFORMAT_APPDEFAULT: //!!! einstellbar an App??? + case SVXURLFORMAT_REPR: + { + pInfo->SetRepresentation( + ((const SvxURLField*)pField)->GetRepresentation()); + } + break; + + case SVXURLFORMAT_URL: + { + pInfo->SetRepresentation( + ((const SvxURLField*)pField)->GetURL()); + } + break; + } + + sal_uInt16 nChrFmt; + + if (IsVisitedURL(((const SvxURLField*)pField)->GetURL())) + nChrFmt = RES_POOLCHR_INET_VISIT; + else + nChrFmt = RES_POOLCHR_INET_NORMAL; + + SwFmt *pFmt = GetCharFmtFromPool(nChrFmt); + + Color aColor(COL_LIGHTBLUE); + if (pFmt) + aColor = pFmt->GetColor().GetValue(); + + pInfo->SetTxtColor(aColor); + } + else if (pField && pField->ISA(SdrMeasureField)) + { + /****************************************************************** + * Measure-Field + ******************************************************************/ + pInfo->ClearFldColor(); + } + else if ( pField && pField->ISA(SvxExtTimeField)) + { + /****************************************************************** + * Time-Field + ******************************************************************/ + pInfo->SetRepresentation( + ((const SvxExtTimeField*) pField)->GetFormatted( + *GetNumberFormatter( sal_True ), LANGUAGE_SYSTEM) ); + } + else + { + DBG_ERROR("unbekannter Feldbefehl"); + pInfo->SetRepresentation( String( '?' ) ); + } + } + + return(0); +} + +/* TFFDI: The functions formerly declared 'inline' + */ +const SdrModel* SwDoc::GetDrawModel() const { return pDrawModel; } +SdrModel* SwDoc::GetDrawModel() { return pDrawModel; } +SdrLayerID SwDoc::GetHeavenId() const { return nHeaven; } +SdrLayerID SwDoc::GetHellId() const { return nHell; } +SdrLayerID SwDoc::GetControlsId() const { return nControls; } +SdrLayerID SwDoc::GetInvisibleHeavenId() const { return nInvisibleHeaven; } +SdrLayerID SwDoc::GetInvisibleHellId() const { return nInvisibleHell; } +SdrLayerID SwDoc::GetInvisibleControlsId() const { return nInvisibleControls; } +SdrModel* SwDoc::GetOrCreateDrawModel() { return GetDrawModel() ? GetDrawModel() : _MakeDrawModel(); } + +// --> OD 2006-03-14 #i62875# +namespace docfunc +{ + bool ExistsDrawObjs( SwDoc& p_rDoc ) + { + bool bExistsDrawObjs( false ); + + if ( p_rDoc.GetDrawModel() && + p_rDoc.GetDrawModel()->GetPage( 0 ) ) + { + const SdrPage& rSdrPage( *(p_rDoc.GetDrawModel()->GetPage( 0 )) ); + + SdrObjListIter aIter( rSdrPage, IM_FLAT ); + while( aIter.IsMore() ) + { + SdrObject* pObj( aIter.Next() ); + if ( !dynamic_cast<SwVirtFlyDrawObj*>(pObj) && + !dynamic_cast<SwFlyDrawObj*>(pObj) ) + { + bExistsDrawObjs = true; + break; + } + } + } + + return bExistsDrawObjs; + } + + bool AllDrawObjsOnPage( SwDoc& p_rDoc ) + { + bool bAllDrawObjsOnPage( true ); + + if ( p_rDoc.GetDrawModel() && + p_rDoc.GetDrawModel()->GetPage( 0 ) ) + { + const SdrPage& rSdrPage( *(p_rDoc.GetDrawModel()->GetPage( 0 )) ); + + SdrObjListIter aIter( rSdrPage, IM_FLAT ); + while( aIter.IsMore() ) + { + SdrObject* pObj( aIter.Next() ); + if ( !dynamic_cast<SwVirtFlyDrawObj*>(pObj) && + !dynamic_cast<SwFlyDrawObj*>(pObj) ) + { + SwDrawContact* pDrawContact = + dynamic_cast<SwDrawContact*>(::GetUserCall( pObj )); + if ( pDrawContact ) + { + SwAnchoredDrawObject* pAnchoredDrawObj = + dynamic_cast<SwAnchoredDrawObject*>(pDrawContact->GetAnchoredObj( pObj )); + + // error handling + { + if ( !pAnchoredDrawObj ) + { + ASSERT( false, + "<docfunc::AllDrawObjsOnPage() - missing anchored draw object" ); + bAllDrawObjsOnPage = false; + break; + } + } + + if ( pAnchoredDrawObj->NotYetPositioned() ) + { + // The drawing object isn't yet layouted. + // Thus, it isn't known, if all drawing objects are on page. + bAllDrawObjsOnPage = false; + break; + } + else if ( pAnchoredDrawObj->IsOutsidePage() ) + { + bAllDrawObjsOnPage = false; + break; + } + } + else + { + // contact object of drawing object doesn't exists. + // Thus, the drawing object isn't yet positioned. + // Thus, it isn't known, if all drawing objects are on page. + bAllDrawObjsOnPage = false; + break; + } + } + } + } + + return bAllDrawObjsOnPage; + } +} +// <-- + diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx new file mode 100644 index 000000000000..6e5c259a9d04 --- /dev/null +++ b/sw/source/core/doc/docedt.cxx @@ -0,0 +1,2845 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <string.h> // fuer strchr() +#include <hintids.hxx> + +#include <vcl/sound.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/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 <unotools/transliterationwrapper.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 <UndoManager.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 <hints.hxx> +#include <UndoSplitMove.hxx> +#include <UndoRedline.hxx> +#include <UndoOverwrite.hxx> +#include <UndoInsert.hxx> +#include <UndoDelete.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> + +#include <vector> + +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 ) +{ + SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts(); + for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) + { + SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]); + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + 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 SwNodeIndex* pCntntIdx; + + for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) + { + sal_Bool bInsPos = sal_False; + pFmt = (SwFrmFmt*)rFmts[n]; + pAnchor = &pFmt->GetAnchor(); + const SwPosition* pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + // 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(); + for ( sal_uInt16 i = rTbl.Count(); i; ) + { + SwFrmFmt *pFmt = rTbl[--i]; + const SwFmtAnchor &rAnch = pFmt->GetAnchor(); + SwPosition const*const pAPos = rAnch.GetCntntAnchor(); + if (pAPos && + ((rAnch.GetAnchorId() == FLY_AT_PARA) || + (rAnch.GetAnchorId() == FLY_AT_CHAR)) && + ( 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 + sal_uInt16 nCount = pHints->Count(); + for( sal_uInt16 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 (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called + } + + sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints() + ? pNode->GetpSwpHints()->Count() : 0; + SwDataChanged aTmp( rRg, 0 ); + SwIndex& rIdx = rPt.nContent; + xub_StrLen nStart = 0; + + sal_Unicode c; + String aStr; + + sal_Bool bOldExpFlg = pNode->IsIgnoreDontExpand(); + pNode->SetIgnoreDontExpand( sal_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 (GetIDocumentUndoRedo().DoesUndo()) + { + bool bMerged(false); + if (GetIDocumentUndoRedo().DoesGroupUndo()) + { + SwUndo *const pUndo = GetUndoManager().GetLastUndo(); + SwUndoOverwrite *const pUndoOW( + dynamic_cast<SwUndoOverwrite *>(pUndo) ); + if (pUndoOW) + { + // if CanGrouping() returns true it's already merged + bMerged = pUndoOW->CanGrouping( this, rPt, c ); + } + } + if (!bMerged) + { + SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) ); + GetIDocumentUndoRedo().AppendUndo(pUndoOW); + } + } + 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 (!GetIDocumentUndoRedo().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. + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + _DelBookmarks( + pStt->nNode, + pEnd->nNode, + NULL, + &pStt->nContent, + &pEnd->nContent); + } + + + int bUpdateFtn = sal_False; + SwFtnIdxs aTmpFntIdx; + + // falls Undo eingeschaltet, erzeuge das UndoMove-Objekt + SwUndoMove * pUndoMove = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().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 (GetIDocumentUndoRedo().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 ); + GetIDocumentUndoRedo().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 ) && GetIDocumentUndoRedo().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 + sal_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 ) + { + pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos ); + GetIDocumentUndoRedo().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(sal_uInt16 * pRanges) +{ + SvUShorts * pResult = new SvUShorts(); + + int i = 0; + while (pRanges[i] != 0) + { + ASSERT(pRanges[i+1] != 0, "malformed ranges"); + + for (sal_uInt16 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 !!!) + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + /* 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() ); + + // 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" ); + + { + SwUndoRedlineDelete* pUndo = 0; + RedlineMode_t eOld = GetRedlineMode(); + checkRedlining(eOld); + if (GetIDocumentUndoRedo().DoesUndo()) + { + + //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 )); + + GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL); + pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + if( *rPam.GetPoint() != *rPam.GetMark() ) + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true); + SetModified(); + + if( pUndo ) + { + GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL); + // ??? why the hell is the AppendUndo not below the + // CanGrouping, so this hideous cleanup wouldn't be necessary? + // bah, this is redlining, probably changing this would break it... + if (GetIDocumentUndoRedo().DoesGroupUndo()) + { + SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() ); + SwUndoRedlineDelete *const pUndoRedlineDel( + dynamic_cast<SwUndoRedlineDelete*>(pLastUndo) ); + if (pUndoRedlineDel) + { + bool const bMerged = pUndoRedlineDel->CanGrouping(*pUndo); + if (bMerged) + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + SwUndo const*const pDeleted = + GetUndoManager().RemoveLastUndo(); + OSL_ENSURE(pDeleted == pUndo, + "DeleteAndJoinWithRedlineImpl: " + "undo removed is not undo inserted?"); + delete pDeleted; + } + } + } +//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; + } + // <-- + { + bool const bSuccess( DeleteRangeImpl( rPam ) ); + if (!bSuccess) + return false; + } + + if( bJoinTxt ) + { + lcl_JoinText( rPam, bJoinPrev ); + } + + return true; +} + +bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool) +{ + // move all cursors out of the deleted range. + // but first copy the given PaM, because it could be a cursor that + // would be moved! + SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() ); + ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() ); + + bool const bSuccess( DeleteRangeImplImpl( aDelPam ) ); + if (bSuccess) + { // now copy position from temp copy to given PaM + *rPam.GetPoint() = *aDelPam.GetPoint(); + } + + return bSuccess; +} + +bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam) +{ + 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 (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + bool bMerged(false); + if (GetIDocumentUndoRedo().DoesGroupUndo()) + { + SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() ); + SwUndoDelete *const pUndoDelete( + dynamic_cast<SwUndoDelete *>(pLastUndo) ); + if (pUndoDelete) + { + bMerged = pUndoDelete->CanGrouping( this, rPam ); + // if CanGrouping() returns true it's already merged + } + } + if (!bMerged) + { + GetIDocumentUndoRedo().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(); + sal_uInt16 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 ); + + sal_uLong nCurrNd = pSttPos->nNode.GetIndex(); + sal_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(sal_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 (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().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 (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndoRD = + new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE ); + GetIDocumentUndoRedo().AppendUndo(pUndoRD); + } + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true); + + *rPam.GetMark() = *aDelPam.GetMark(); + if (GetIDocumentUndoRedo().DoesUndo()) + { + *aDelPam.GetPoint() = *rPam.GetPoint(); + GetIDocumentUndoRedo().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; + bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo(); + if (bDoesUndo) + { + pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace); + GetIDocumentUndoRedo().AppendUndo(pUndoRpl); + } + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + 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->SetEnd(rPam); + } + } + } + + 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 == GetNodes().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. */ + sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1; + SwTableNode *const pTblNd = GetNodes()[ 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; + } + } + } + + bool const bDoesUndo = GetIDocumentUndoRedo().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 ); + + GetIDocumentUndoRedo().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 ); + GetIDocumentUndoRedo().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 + for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + SwFrmFmt* pFly = (*GetSpzFrmFmts())[n]; + const SwFmtAnchor* pAnchor = &pFly->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd ) + { + DelLayoutFmt( pFly ); + --n; + } + } + } + + SwCntntNode *pTmpNode = rPam.GetBound( sal_True ).nNode.GetNode().GetCntntNode(); + rPam.GetBound( sal_True ).nContent.Assign( pTmpNode, 0 ); + pTmpNode = rPam.GetBound( sal_False ).nNode.GetNode().GetCntntNode(); + rPam.GetBound( sal_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 *const pUndo = (GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoTransliterate( rPaM, rTrans ) + : 0; + + const SwPosition* pStt = rPaM.Start(), + * pEnd = rPaM.End(); + sal_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 selection? + { + // set current word as 'area of effect' + + Boundary aBndry; + if( pBreakIt->GetBreakIter().is() ) + aBndry = pBreakIt->GetBreakIter()->getWordBoundary( + pTNd->GetTxt(), nSttCnt, + pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ), + WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, + sal_True ); + + if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos ) + { + nSttCnt = (xub_StrLen)aBndry.startPos; + nEndCnt = (xub_StrLen)aBndry.endPos; + } + } + + if( nSttNd != nEndNd ) // is more than one text node involved? + { + // iterate over all effected text nodes, the first and the last one + // may be incomplete because the selection starts and/or ends there + + 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() ) + { + GetIDocumentUndoRedo().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)); + sal_uInt16 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 sal_uLong nSttNd = pStt->nNode.GetIndex(); + const sal_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 ); + } + } +} diff --git a/sw/source/core/doc/docfld.cxx b/sw/source/core/doc/docfld.cxx new file mode 100644 index 000000000000..28d41e9e5364 --- /dev/null +++ b/sw/source/core/doc/docfld.cxx @@ -0,0 +1,2829 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#include <string.h> +#include <float.h> +#include <tools/datetime.hxx> +#ifndef _SVSTDARR_HXX +#define _SVSTDARR_ULONGS +#include <svl/svarray.hxx> +#endif +#include <vcl/svapp.hxx> +#include <vcl/svapp.hxx> +#include <unotools/charclass.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <cntfrm.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <calc.hxx> +#include <txtfld.hxx> +#include <fmtfld.hxx> +#include <tox.hxx> +#include <txttxmrk.hxx> +#include <docfld.hxx> // fuer Expression-Felder +#include <docufld.hxx> +#include <ddefld.hxx> +#include <usrfld.hxx> +#include <expfld.hxx> +#include <dbfld.hxx> +#include <flddat.hxx> +#include <chpfld.hxx> +#include <reffld.hxx> +#include <flddropdown.hxx> +#include <dbmgr.hxx> +#include <section.hxx> +#include <cellatr.hxx> +#include <docary.hxx> +#include <authfld.hxx> +#include <txtinet.hxx> +#include <fmtcntnt.hxx> +#include <poolfmt.hrc> // fuer InitFldTypes + +#include <SwUndoField.hxx> + +using namespace ::com::sun::star::uno; + +extern sal_Bool IsFrameBehind( const SwTxtNode& rMyNd, sal_uInt16 nMySttPos, + const SwTxtNode& rBehindNd, sal_uInt16 nSttPos ); + +SV_IMPL_OP_PTRARR_SORT( _SetGetExpFlds, _SetGetExpFldPtr ) + + +/*-------------------------------------------------------------------- + Beschreibung: Feldtypen einfuegen + --------------------------------------------------------------------*/ +/* + * Implementierung der Feldfunktionen am Doc + * Return immer einen gueltigen Pointer auf den Typ. Wenn er also neu + * zugefuegt oder schon vorhanden ist. + */ + +SwFieldType* SwDoc::InsertFldType(const SwFieldType &rFldTyp) +{ + sal_uInt16 nSize = pFldTypes->Count(), + nFldWhich = rFldTyp.Which(); + + sal_uInt16 i = INIT_FLDTYPES; + + switch( nFldWhich ) + { + case RES_SETEXPFLD: + //JP 29.01.96: SequenceFelder beginnen aber bei INIT_FLDTYPES - 3!! + // Sonst gibt es doppelte Nummernkreise!! + //MIB 14.03.95: Ab sofort verlaesst sich auch der SW3-Reader + //beim Aufbau der String-Pools und beim Einlesen von SetExp-Feldern + //hierauf + if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType&)rFldTyp).GetType() ) + i -= INIT_SEQ_FLDTYPES; + // kein break; + case RES_DBFLD: + case RES_USERFLD: + case RES_DDEFLD: + { + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + String sFldNm( rFldTyp.GetName() ); + for( ; i < nSize; ++i ) + if( nFldWhich == (*pFldTypes)[i]->Which() && + rSCmp.isEqual( sFldNm, (*pFldTypes)[i]->GetName() )) + return (*pFldTypes)[i]; + } + break; + + case RES_AUTHORITY: + for( ; i < nSize; ++i ) + if( nFldWhich == (*pFldTypes)[i]->Which() ) + return (*pFldTypes)[i]; + break; + + default: + for( i = 0; i < nSize; ++i ) + if( nFldWhich == (*pFldTypes)[i]->Which() ) + return (*pFldTypes)[i]; + } + + SwFieldType* pNew = rFldTyp.Copy(); + switch( nFldWhich ) + { + case RES_DDEFLD: + ((SwDDEFieldType*)pNew)->SetDoc( this ); + break; + + case RES_DBFLD: + case RES_TABLEFLD: + case RES_DATETIMEFLD: + case RES_GETEXPFLD: + ((SwValueFieldType*)pNew)->SetDoc( this ); + break; + + case RES_USERFLD: + case RES_SETEXPFLD: + ((SwValueFieldType*)pNew)->SetDoc( this ); + // JP 29.07.96: opt. FeldListe fuer den Calculator vorbereiten: + pUpdtFlds->InsertFldType( *pNew ); + break; + case RES_AUTHORITY : + ((SwAuthorityFieldType*)pNew)->SetDoc( this ); + break; + } + + pFldTypes->Insert( pNew, nSize ); + SetModified(); + + return (*pFldTypes)[ nSize ]; +} + +void SwDoc::InsDeletedFldType( SwFieldType& rFldTyp ) +{ + // der FeldTyp wurde als geloescht gekennzeichnet und aus dem + // Array entfernt. Nun muss man nach diesem wieder suchen. + // - Ist der nicht vorhanden, dann kann er eingefuegt werden. + // - Wird genau der gleiche Typ gefunden, dann muss der geloeschte + // einen anderen Namen erhalten. + + sal_uInt16 nSize = pFldTypes->Count(), nFldWhich = rFldTyp.Which(); + sal_uInt16 i = INIT_FLDTYPES; + + ASSERT( RES_SETEXPFLD == nFldWhich || + RES_USERFLD == nFldWhich || + RES_DDEFLD == nFldWhich, "Falscher FeldTyp" ); + + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + const String& rFldNm = rFldTyp.GetName(); + SwFieldType* pFnd; + + for( ; i < nSize; ++i ) + if( nFldWhich == (pFnd = (*pFldTypes)[i])->Which() && + rSCmp.isEqual( rFldNm, pFnd->GetName() ) ) + { + // neuen Namen suchen + sal_uInt16 nNum = 1; + do { + String sSrch( rFldNm ); + sSrch.Append( String::CreateFromInt32( nNum )); + for( i = INIT_FLDTYPES; i < nSize; ++i ) + if( nFldWhich == (pFnd = (*pFldTypes)[i])->Which() && + rSCmp.isEqual( sSrch, pFnd->GetName() ) ) + break; + + if( i >= nSize ) // nicht gefunden + { + ((String&)rFldNm) = sSrch; + break; // raus aus der While-Schleife + } + ++nNum; + } while( sal_True ); + break; + } + + // nicht gefunden, also eintragen und Flag loeschen + pFldTypes->Insert( &rFldTyp, nSize ); + switch( nFldWhich ) + { + case RES_SETEXPFLD: + ((SwSetExpFieldType&)rFldTyp).SetDeleted( sal_False ); + break; + case RES_USERFLD: + ((SwUserFieldType&)rFldTyp).SetDeleted( sal_False ); + break; + case RES_DDEFLD: + ((SwDDEFieldType&)rFldTyp).SetDeleted( sal_False ); + break; + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Feldtypen loeschen + --------------------------------------------------------------------*/ + +void SwDoc::RemoveFldType(sal_uInt16 nFld) +{ + ASSERT( INIT_FLDTYPES <= nFld, "keine InitFields loeschen" ); + /* + * Abheangige Felder vorhanden -> ErrRaise + */ + sal_uInt16 nSize = pFldTypes->Count(); + if(nFld < nSize) + { + SwFieldType* pTmp = (*pFldTypes)[nFld]; + + // JP 29.07.96: opt. FeldListe fuer den Calculator vorbereiten: + sal_uInt16 nWhich = pTmp->Which(); + switch( nWhich ) + { + case RES_SETEXPFLD: + case RES_USERFLD: + pUpdtFlds->RemoveFldType( *pTmp ); + // kein break; + case RES_DDEFLD: + if( pTmp->GetDepends() && !IsUsed( *pTmp ) ) + { + if( RES_SETEXPFLD == nWhich ) + ((SwSetExpFieldType*)pTmp)->SetDeleted( sal_True ); + else if( RES_USERFLD == nWhich ) + ((SwUserFieldType*)pTmp)->SetDeleted( sal_True ); + else + ((SwDDEFieldType*)pTmp)->SetDeleted( sal_True ); + nWhich = 0; + } + break; + } + + if( nWhich ) + { + ASSERT( !pTmp->GetDepends(), "Abhaengige vorh.!" ); + // Feldtype loschen + delete pTmp; + } + pFldTypes->Remove( nFld ); + SetModified(); + } +} + +const SwFldTypes* SwDoc::GetFldTypes() const +{ + return pFldTypes; +} + +/*-------------------------------------------------------------------- + Beschreibung: Den ersten Typen mit ResId und Namen finden + --------------------------------------------------------------------*/ + +SwFieldType* SwDoc::GetFldType( sal_uInt16 nResId, const String& rName, + bool bDbFieldMatching // used in some UNO calls for RES_DBFLD + // to use different string matching code + // #i51815# + ) const +{ + sal_uInt16 nSize = pFldTypes->Count(), i = 0; + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + + switch( nResId ) + { + case RES_SETEXPFLD: + //JP 29.01.96: SequenceFelder beginnen aber bei INIT_FLDTYPES - 3!! + // Sonst gibt es doppelte Nummernkreise!! + //MIB 14.03.95: Ab sofort verlaesst sich auch der SW3-Reader + //beim Aufbau der String-Pools und beim Einlesen von SetExp-Feldern + //hierauf + i = INIT_FLDTYPES - INIT_SEQ_FLDTYPES; + break; + + case RES_DBFLD: + case RES_USERFLD: + case RES_DDEFLD: + case RES_AUTHORITY: + i = INIT_FLDTYPES; + break; + } + + SwFieldType* pRet = 0; + for( ; i < nSize; ++i ) + { + SwFieldType* pFldType = (*pFldTypes)[i]; + + String aFldName( pFldType->GetName() ); + if (bDbFieldMatching && nResId == RES_DBFLD) // #i51815# + aFldName.SearchAndReplaceAll(DB_DELIM, '.'); + + if( nResId == pFldType->Which() && + rSCmp.isEqual( rName, aFldName )) + { + pRet = pFldType; + break; + } + } + return pRet; +} + + +/************************************************************************* +|* SwDoc::UpdateFlds() +|* Beschreibung Felder updaten +*************************************************************************/ +/* + * Alle sollen neu evaluiert werden. + */ + +void SwDoc::UpdateFlds( SfxPoolItem *pNewHt, bool bCloseDB ) +{ + // Modify() fuer jeden Feldtypen rufen, + // abhaengige SwTxtFld werden benachrichtigt ... + + for( sal_uInt16 i=0; i < pFldTypes->Count(); ++i) + { + switch( (*pFldTypes)[i]->Which() ) + { + // Tabellen-Felder als vorletztes Updaten + // Referenzen als letztes Updaten + case RES_GETREFFLD: + case RES_TABLEFLD: + case RES_DBFLD: + case RES_JUMPEDITFLD: + case RES_REFPAGESETFLD: // werden nie expandiert! + break; + + case RES_DDEFLD: + { + if( !pNewHt ) + { + SwMsgPoolItem aUpdateDDE( RES_UPDATEDDETBL ); + (*pFldTypes)[i]->Modify( 0, &aUpdateDDE ); + } + else + (*pFldTypes)[i]->Modify( 0, pNewHt ); + break; + } + case RES_GETEXPFLD: + case RES_SETEXPFLD: + case RES_HIDDENTXTFLD: + case RES_HIDDENPARAFLD: + // Expression-Felder werden gesondert behandelt + if( !pNewHt ) + break; + default: + (*pFldTypes)[i]->Modify( 0, pNewHt ); + } + } + + if( !IsExpFldsLocked() ) + UpdateExpFlds( 0, sal_False ); // Expression-Felder Updaten + + // Tabellen + UpdateTblFlds(pNewHt); + + // Referenzen + UpdateRefFlds(pNewHt); + + if( bCloseDB ) + GetNewDBMgr()->CloseAll(); + + // Nur bei KomplettUpdate evaluieren + SetModified(); +} + +/****************************************************************************** + * void SwDoc::UpdateUsrFlds() + ******************************************************************************/ + +void SwDoc::UpdateUsrFlds() +{ + SwCalc* pCalc = 0; + const SwFieldType* pFldType; + for( sal_uInt16 i = INIT_FLDTYPES; i < pFldTypes->Count(); ++i ) + if( RES_USERFLD == ( pFldType = (*pFldTypes)[i] )->Which() ) + { + if( !pCalc ) + pCalc = new SwCalc( *this ); + ((SwUserFieldType*)pFldType)->GetValue( *pCalc ); + } + + if( pCalc ) + { + delete pCalc; + SetModified(); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Referenzfelder und TableFelder erneuern + --------------------------------------------------------------------*/ + +void SwDoc::UpdateRefFlds( SfxPoolItem* pHt ) +{ + SwFieldType* pFldType; + for( sal_uInt16 i = 0; i < pFldTypes->Count(); ++i ) + if( RES_GETREFFLD == ( pFldType = (*pFldTypes)[i] )->Which() ) + pFldType->Modify( 0, pHt ); +} + +void SwDoc::UpdateTblFlds( SfxPoolItem* pHt ) +{ + ASSERT( !pHt || RES_TABLEFML_UPDATE == pHt->Which(), + "Was ist das fuer ein MessageItem?" ); + + SwFieldType* pFldType(0); + + for (sal_uInt16 i = 0; i < pFldTypes->Count(); ++i) + { + if( RES_TABLEFLD == ( pFldType = (*pFldTypes)[i] )->Which() ) + { + SwTableFmlUpdate* pUpdtFld = 0; + if( pHt && RES_TABLEFML_UPDATE == pHt->Which() ) + pUpdtFld = (SwTableFmlUpdate*)pHt; + + SwClientIter aIter( *pFldType ); + for( SwFmtFld* pFmtFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + pFmtFld; pFmtFld = (SwFmtFld*)aIter.Next() ) + if( pFmtFld->GetTxtFld() ) + { + SwTblField* pFld = (SwTblField*)pFmtFld->GetFld(); + + if( pUpdtFld ) + { + // bestimme Tabelle, in der das Feld steht + const SwTableNode* pTblNd; + const SwTxtNode& rTxtNd = pFmtFld->GetTxtFld()->GetTxtNode(); + if( !rTxtNd.GetNodes().IsDocNodes() || + 0 == ( pTblNd = rTxtNd.FindTableNode() ) ) + continue; + + switch( pUpdtFld->eFlags ) + { + case TBL_CALC: + // setze das Value-Flag zurueck + // JP 17.06.96: interne Darstellung auf alle Formeln + // (Referenzen auf andere Tabellen!!!) + if( nsSwExtendedSubType::SUB_CMD & pFld->GetSubType() ) + pFld->PtrToBoxNm( pUpdtFld->pTbl ); + else + pFld->ChgValid( sal_False ); + break; + case TBL_BOXNAME: + // ist es die gesuchte Tabelle ?? + if( &pTblNd->GetTable() == pUpdtFld->pTbl ) + // zur externen Darstellung + pFld->PtrToBoxNm( pUpdtFld->pTbl ); + break; + case TBL_BOXPTR: + // zur internen Darstellung + // JP 17.06.96: interne Darstellung auf alle Formeln + // (Referenzen auf andere Tabellen!!!) + pFld->BoxNmToPtr( pUpdtFld->pTbl ); + break; + case TBL_RELBOXNAME: + // ist es die gesuchte Tabelle ?? + if( &pTblNd->GetTable() == pUpdtFld->pTbl ) + // zur relativen Darstellung + pFld->ToRelBoxNm( pUpdtFld->pTbl ); + break; + default: + break; + } + } + else + // setze bei allen das Value-Flag zurueck + pFld->ChgValid( sal_False ); + } + + break; + } + pFldType = 0; + } + + // und dann noch alle Tabellen Box Formeln abklappern + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_BOXATR_FORMULA ); + for (sal_uInt32 i = 0; i < nMaxItems; ++i) + { + if( 0 != (pItem = GetAttrPool().GetItem2( RES_BOXATR_FORMULA, i ) ) && + ((SwTblBoxFormula*)pItem)->GetDefinedIn() ) + { + ((SwTblBoxFormula*)pItem)->ChangeState( pHt ); + } + } + + + // alle Felder/Boxen sind jetzt invalide, also kann das Rechnen anfangen + if( pHt && ( RES_TABLEFML_UPDATE != pHt->Which() || + TBL_CALC != ((SwTableFmlUpdate*)pHt)->eFlags )) + return ; + + SwCalc* pCalc = 0; + + if( pFldType ) + { + SwClient* pLast; + SwClientIter aIter( *pFldType ); + // dann rechne mal schoen + // JP 27.03.97: Beim Berechnen am Ende anfangen - weil neue + // Felder immer am Anfang der Modifykette eingefuegt + // werden. Beim Import haben wir damit eine bessere/ + // schnellere Berechnung bei "Kettenformeln" + if( 0 != ( pLast = aIter.GoEnd() )) + do { + SwFmtFld* pFmtFld = (SwFmtFld*)pLast; + SwTblField* pFld; + if( !pFmtFld->GetTxtFld() || (nsSwExtendedSubType::SUB_CMD & + (pFld = (SwTblField*)pFmtFld->GetFld())->GetSubType() )) + continue; + + // muss neu berechnet werden (und ist keine textuelle Anzeige) + if( !pFld->IsValid() ) + { + // bestimme Tabelle, in der das Feld steht + const SwTxtNode& rTxtNd = pFmtFld->GetTxtFld()->GetTxtNode(); + if( !rTxtNd.GetNodes().IsDocNodes() ) + continue; + const SwTableNode* pTblNd = rTxtNd.FindTableNode(); + if( !pTblNd ) + continue; + + // falls dieses Feld nicht in der zu updatenden + // Tabelle steht, ueberspringen !! + if( pHt && &pTblNd->GetTable() != + ((SwTableFmlUpdate*)pHt)->pTbl ) + continue; + + if( !pCalc ) + pCalc = new SwCalc( *this ); + + // bestimme die Werte aller SetExpresion Felder, die + // bis zur Tabelle gueltig sind + SwFrm* pFrm = 0; + if( pTblNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) + { + // steht im Sonderbereich, wird teuer !! + Point aPt; // den im Layout 1. Frame returnen - Tab.Kopfzeile !! + pFrm = rTxtNd.GetFrm( &aPt ); + if( pFrm ) + { + SwPosition aPos( *pTblNd ); + if( GetBodyTxtNode( *this, aPos, *pFrm ) ) + FldsToCalc( *pCalc, _SetGetExpFld( + aPos.nNode, pFmtFld->GetTxtFld(), + &aPos.nContent )); + else + pFrm = 0; + } + } + if( !pFrm ) + { + // einen Index fuers bestimmen vom TextNode anlegen + SwNodeIndex aIdx( rTxtNd ); + FldsToCalc( *pCalc, + _SetGetExpFld( aIdx, pFmtFld->GetTxtFld() )); + } + + SwTblCalcPara aPara( *pCalc, pTblNd->GetTable() ); + pFld->CalcField( aPara ); + if( aPara.IsStackOverFlow() ) + { + if( aPara.CalcWithStackOverflow() ) + pFld->CalcField( aPara ); +#ifdef DBG_UTIL + else + { + // mind. ein ASSERT + ASSERT( !this, "die Kettenformel konnte nicht errechnet werden" ); + } +#endif + } + pCalc->SetCalcError( CALC_NOERR ); + } + pFmtFld->Modify( 0, pHt ); + } while( 0 != ( pLast = aIter-- )); + } + + // dann berechene noch die Formeln an den Boxen + for (sal_uInt32 i = 0; i < nMaxItems; ++i ) + { + if( 0 != (pItem = GetAttrPool().GetItem2( RES_BOXATR_FORMULA, i ) ) && + ((SwTblBoxFormula*)pItem)->GetDefinedIn() && + !((SwTblBoxFormula*)pItem)->IsValid() ) + { + SwTblBoxFormula* pFml = (SwTblBoxFormula*)pItem; + SwTableBox* pBox = pFml->GetTableBox(); + if( pBox && pBox->GetSttNd() && + pBox->GetSttNd()->GetNodes().IsDocNodes() ) + { + const SwTableNode* pTblNd = pBox->GetSttNd()->FindTableNode(); + if( !pHt || &pTblNd->GetTable() == + ((SwTableFmlUpdate*)pHt)->pTbl ) + { + double nValue; + if( !pCalc ) + pCalc = new SwCalc( *this ); + + // bestimme die Werte aller SetExpresion Felder, die + // bis zur Tabelle gueltig sind + SwFrm* pFrm = 0; + if( pTblNd->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) + { + // steht im Sonderbereich, wird teuer !! + Point aPt; // den im Layout 1. Frame returnen - Tab.Kopfzeile !! + SwNodeIndex aCNdIdx( *pTblNd, +2 ); + SwCntntNode* pCNd = aCNdIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = GetNodes().GoNext( &aCNdIdx ); + + if( pCNd && 0 != (pFrm = pCNd->GetFrm( &aPt )) ) + { + SwPosition aPos( *pCNd ); + if( GetBodyTxtNode( *this, aPos, *pFrm ) ) + FldsToCalc( *pCalc, _SetGetExpFld( aPos.nNode )); + else + pFrm = 0; + } + } + if( !pFrm ) + { + // einen Index fuers bestimmen vom TextNode anlegen + SwNodeIndex aIdx( *pTblNd ); + FldsToCalc( *pCalc, _SetGetExpFld( aIdx )); + } + + SwTblCalcPara aPara( *pCalc, pTblNd->GetTable() ); + pFml->Calc( aPara, nValue ); + + if( aPara.IsStackOverFlow() ) + { + if( aPara.CalcWithStackOverflow() ) + pFml->Calc( aPara, nValue ); +#ifdef DBG_UTIL + else + { + // mind. ein ASSERT + ASSERT( !this, "die Kettenformel konnte nicht errechnet werden" ); + } +#endif + } + + SwFrmFmt* pFmt = pBox->ClaimFrmFmt(); + SfxItemSet aTmp( GetAttrPool(), + RES_BOXATR_BEGIN,RES_BOXATR_END-1 ); + + if( pCalc->IsCalcError() ) + nValue = DBL_MAX; + aTmp.Put( SwTblBoxValue( nValue )); + if( SFX_ITEM_SET != pFmt->GetItemState( RES_BOXATR_FORMAT )) + aTmp.Put( SwTblBoxNumFormat( 0 )); + pFmt->SetFmtAttr( aTmp ); + + pCalc->SetCalcError( CALC_NOERR ); + } + } + } + } + + if( pCalc ) + delete pCalc; +} + +void SwDoc::UpdatePageFlds( SfxPoolItem* pMsgHnt ) +{ + SwFieldType* pFldType; + for( sal_uInt16 i = 0; i < INIT_FLDTYPES; ++i ) + switch( ( pFldType = (*pFldTypes)[ i ] )->Which() ) + { + case RES_PAGENUMBERFLD: + case RES_CHAPTERFLD: + case RES_GETEXPFLD: + case RES_REFPAGEGETFLD: + pFldType->Modify( 0, pMsgHnt ); + break; + case RES_DOCSTATFLD: + pFldType->Modify( 0, 0 ); + break; + } + SetNewFldLst(true); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +// ---- Loesche alle nicht referenzierten FeldTypen eines Dokumentes -- +void SwDoc::GCFieldTypes() +{ + for( sal_uInt16 n = pFldTypes->Count(); n > INIT_FLDTYPES; ) + if( !(*pFldTypes)[ --n ]->GetDepends() ) + RemoveFldType( n ); +} + +void SwDoc::LockExpFlds() +{ + ++nLockExpFld; +} + +void SwDoc::UnlockExpFlds() +{ + if( nLockExpFld ) + --nLockExpFld; +} + +bool SwDoc::IsExpFldsLocked() const +{ + return 0 != nLockExpFld; +} + +SwDocUpdtFld& SwDoc::GetUpdtFlds() const +{ + return *pUpdtFlds; +} + +bool SwDoc::IsNewFldLst() const +{ + return mbNewFldLst; +} + +void SwDoc::SetNewFldLst(bool bFlag) +{ + mbNewFldLst = bFlag; +} + + +//---------------------------------------------------------------------- + +// der StartIndex kann optional mit angegeben werden (z.B. wenn dieser +// zuvor schon mal erfragt wurde - ist sonst eine virtuelle Methode !!) + +_SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx, const SwTxtFld* pFld, + const SwIndex* pIdx ) +{ + eSetGetExpFldType = TEXTFIELD; + CNTNT.pTxtFld = pFld; + nNode = rNdIdx.GetIndex(); + if( pIdx ) + nCntnt = pIdx->GetIndex(); + else if( pFld ) + nCntnt = *pFld->GetStart(); + else + nCntnt = 0; +} + +_SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx, + const SwTxtINetFmt& rINet, const SwIndex* pIdx ) +{ + eSetGetExpFldType = TEXTINET; + CNTNT.pTxtINet = &rINet; + nNode = rNdIdx.GetIndex(); + if( pIdx ) + nCntnt = pIdx->GetIndex(); + else + nCntnt = *rINet.GetStart(); +} + + //Erweiterung fuer Sections: + // diese haben immer als Content-Position 0xffff !! + // Auf dieser steht nie ein Feld, maximal bis STRING_MAXLEN moeglich +_SetGetExpFld::_SetGetExpFld( const SwSectionNode& rSectNd, + const SwPosition* pPos ) +{ + eSetGetExpFldType = SECTIONNODE; + CNTNT.pSection = &rSectNd.GetSection(); + + if( pPos ) + { + nNode = pPos->nNode.GetIndex(); + nCntnt = pPos->nContent.GetIndex(); + } + else + { + nNode = rSectNd.GetIndex(); + nCntnt = 0; + } +} + +_SetGetExpFld::_SetGetExpFld( const SwTableBox& rTBox, const SwPosition* pPos ) +{ + eSetGetExpFldType = TABLEBOX; + CNTNT.pTBox = &rTBox; + + if( pPos ) + { + nNode = pPos->nNode.GetIndex(); + nCntnt = pPos->nContent.GetIndex(); + } + else + { + nNode = 0; + nCntnt = 0; + if( rTBox.GetSttNd() ) + { + SwNodeIndex aIdx( *rTBox.GetSttNd() ); + const SwCntntNode* pNd = aIdx.GetNode().GetNodes().GoNext( &aIdx ); + if( pNd ) + nNode = pNd->GetIndex(); + } + } +} + +_SetGetExpFld::_SetGetExpFld( const SwNodeIndex& rNdIdx, + const SwTxtTOXMark& rTOX, + const SwIndex* pIdx ) +{ + eSetGetExpFldType = TEXTTOXMARK; + CNTNT.pTxtTOX = &rTOX; + nNode = rNdIdx.GetIndex(); + if( pIdx ) + nCntnt = pIdx->GetIndex(); + else + nCntnt = *rTOX.GetStart(); +} + +_SetGetExpFld::_SetGetExpFld( const SwPosition& rPos ) +{ + eSetGetExpFldType = CRSRPOS; + CNTNT.pPos = &rPos; + nNode = rPos.nNode.GetIndex(); + nCntnt = rPos.nContent.GetIndex(); +} + +_SetGetExpFld::_SetGetExpFld( const SwFlyFrmFmt& rFlyFmt, + const SwPosition* pPos ) +{ + eSetGetExpFldType = FLYFRAME; + CNTNT.pFlyFmt = &rFlyFmt; + if( pPos ) + { + nNode = pPos->nNode.GetIndex(); + nCntnt = pPos->nContent.GetIndex(); + } + else + { + const SwFmtCntnt& rCntnt = rFlyFmt.GetCntnt(); + nNode = rCntnt.GetCntntIdx()->GetIndex() + 1; + nCntnt = 0; + } +} + +void _SetGetExpFld::GetPos( SwPosition& rPos ) const +{ + rPos.nNode = nNode; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), nCntnt ); +} + +void _SetGetExpFld::GetPosOfContent( SwPosition& rPos ) const +{ + const SwNode* pNd = GetNodeFromCntnt(); + if( pNd ) + pNd = pNd->GetCntntNode(); + + if( pNd ) + { + rPos.nNode = *pNd; + rPos.nContent.Assign( (SwCntntNode*)pNd,GetCntPosFromCntnt() ); + } + else + { + rPos.nNode = nNode; + rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(), nCntnt ); + } +} + +void _SetGetExpFld::SetBodyPos( const SwCntntFrm& rFrm ) +{ + if( !rFrm.IsInDocBody() ) + { + SwNodeIndex aIdx( *rFrm.GetNode() ); + SwDoc& rDoc = *aIdx.GetNodes().GetDoc(); + SwPosition aPos( aIdx ); +#ifdef DBG_UTIL + ASSERT( ::GetBodyTxtNode( rDoc, aPos, rFrm ), "wo steht das Feld" ); +#else + ::GetBodyTxtNode( rDoc, aPos, rFrm ); +#endif + nNode = aPos.nNode.GetIndex(); + nCntnt = aPos.nContent.GetIndex(); + } +} + +sal_Bool _SetGetExpFld::operator<( const _SetGetExpFld& rFld ) const +{ + if( nNode < rFld.nNode || ( nNode == rFld.nNode && nCntnt < rFld.nCntnt )) + return sal_True; + else if( nNode != rFld.nNode || nCntnt != rFld.nCntnt ) + return sal_False; + + const SwNode *pFirst = GetNodeFromCntnt(), + *pNext = rFld.GetNodeFromCntnt(); + + // Position gleich: nur weiter wenn beide FeldPointer besetzt sind !! + if( !pFirst || !pNext ) + return sal_False; + + // gleiche Section ?? + if( pFirst->StartOfSectionNode() != pNext->StartOfSectionNode() ) + { + // sollte einer in der Tabelle stehen ? + const SwNode *pFirstStt, *pNextStt; + const SwTableNode* pTblNd = pFirst->FindTableNode(); + if( pTblNd ) + pFirstStt = pTblNd->StartOfSectionNode(); + else + pFirstStt = pFirst->StartOfSectionNode(); + + if( 0 != ( pTblNd = pNext->FindTableNode() ) ) + pNextStt = pTblNd->StartOfSectionNode(); + else + pNextStt = pNext->StartOfSectionNode(); + + if( pFirstStt != pNextStt ) + { + if( pFirst->IsTxtNode() && pNext->IsTxtNode() && + ( pFirst->FindFlyStartNode() || pNext->FindFlyStartNode() )) + { + return ::IsFrameBehind( *(SwTxtNode*)pNext, nCntnt, + *(SwTxtNode*)pFirst, nCntnt ); + } + return pFirstStt->GetIndex() < pNextStt->GetIndex(); + } + } + + // ist gleiche Section, dann Feld im gleichen Node ? + if( pFirst != pNext ) + return pFirst->GetIndex() < pNext->GetIndex(); + + // gleicher Node in der Section, dann Position im Node + return GetCntPosFromCntnt() < rFld.GetCntPosFromCntnt(); +} + +const SwNode* _SetGetExpFld::GetNodeFromCntnt() const +{ + const SwNode* pRet = 0; + if( CNTNT.pTxtFld ) + switch( eSetGetExpFldType ) + { + case TEXTFIELD: + pRet = &CNTNT.pTxtFld->GetTxtNode(); + break; + + case TEXTINET: + pRet = &CNTNT.pTxtINet->GetTxtNode(); + break; + + case SECTIONNODE: + pRet = CNTNT.pSection->GetFmt()->GetSectionNode(); + break; + + case CRSRPOS: + pRet = &CNTNT.pPos->nNode.GetNode(); + break; + + case TEXTTOXMARK: + pRet = &CNTNT.pTxtTOX->GetTxtNode(); + break; + + case TABLEBOX: + if( CNTNT.pTBox->GetSttNd() ) + { + SwNodeIndex aIdx( *CNTNT.pTBox->GetSttNd() ); + pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx ); + } + break; + + case FLYFRAME: + { + SwNodeIndex aIdx( *CNTNT.pFlyFmt->GetCntnt().GetCntntIdx() ); + pRet = aIdx.GetNode().GetNodes().GoNext( &aIdx ); + } + break; + } + return pRet; +} + +xub_StrLen _SetGetExpFld::GetCntPosFromCntnt() const +{ + sal_uInt16 nRet = 0; + if( CNTNT.pTxtFld ) + switch( eSetGetExpFldType ) + { + case TEXTFIELD: + case TEXTINET: + case TEXTTOXMARK: + nRet = *CNTNT.pTxtFld->GetStart(); + break; + case CRSRPOS: + nRet = CNTNT.pPos->nContent.GetIndex(); + break; + default: + break; + } + return nRet; +} + +_HashStr::_HashStr( const String& rName, const String& rText, + _HashStr* pNxt ) + : SwHash( rName ), aSetStr( rText ) +{ + pNext = pNxt; +} + +// suche nach dem Namen, ist er vorhanden, returne seinen String, sonst +// einen LeerString +void LookString( SwHash** ppTbl, sal_uInt16 nSize, const String& rName, + String& rRet, sal_uInt16* pPos ) +{ + rRet = rName; + rRet.EraseLeadingChars().EraseTrailingChars(); + SwHash* pFnd = Find( rRet, ppTbl, nSize, pPos ); + if( pFnd ) + rRet = ((_HashStr*)pFnd)->aSetStr; + else + rRet.Erase(); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +String lcl_GetDBVarName( SwDoc& rDoc, SwDBNameInfField& rDBFld ) +{ + SwDBData aDBData( rDBFld.GetDBData( &rDoc )); + String sDBNumNm; + SwDBData aDocData = rDoc.GetDBData(); + + if( aDBData != aDocData ) + { + sDBNumNm = aDBData.sDataSource; + sDBNumNm += DB_DELIM; + sDBNumNm += String(aDBData.sCommand); + sDBNumNm += DB_DELIM; + } + sDBNumNm += SwFieldType::GetTypeStr(TYP_DBSETNUMBERFLD); + + return sDBNumNm; +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void lcl_CalcFld( SwDoc& rDoc, SwCalc& rCalc, const _SetGetExpFld& rSGEFld, + SwNewDBMgr* pMgr ) +{ + const SwTxtFld* pTxtFld = rSGEFld.GetFld(); + if( !pTxtFld ) + return ; + + const SwField* pFld = pTxtFld->GetFld().GetFld(); + const sal_uInt16 nFldWhich = pFld->GetTyp()->Which(); + + if( RES_SETEXPFLD == nFldWhich ) + { + SwSbxValue aValue; + if( nsSwGetSetExpType::GSE_EXPR & pFld->GetSubType() ) + aValue.PutDouble( ((SwSetExpField*)pFld)->GetValue() ); + else + // Erweiterung fuers Rechnen mit Strings + aValue.PutString( ((SwSetExpField*)pFld)->GetExpStr() ); + + // setze im Calculator den neuen Wert + rCalc.VarChange( pFld->GetTyp()->GetName(), aValue ); + } + else if( pMgr ) + { + switch( nFldWhich ) + { + case RES_DBNUMSETFLD: + { + SwDBNumSetField* pDBFld = (SwDBNumSetField*)pFld; + + SwDBData aDBData(pDBFld->GetDBData(&rDoc)); + + if( pDBFld->IsCondValid() && + pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand )) + rCalc.VarChange( lcl_GetDBVarName( rDoc, *pDBFld), + pDBFld->GetFormat() ); + } + break; + case RES_DBNEXTSETFLD: + { + SwDBNextSetField* pDBFld = (SwDBNextSetField*)pFld; + SwDBData aDBData(pDBFld->GetDBData(&rDoc)); + if( !pDBFld->IsCondValid() || + !pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand )) + break; + + String sDBNumNm(lcl_GetDBVarName( rDoc, *pDBFld)); + SwCalcExp* pExp = rCalc.VarLook( sDBNumNm ); + if( pExp ) + rCalc.VarChange( sDBNumNm, pExp->nValue.GetLong() + 1 ); + } + break; + + } + } +} + +void SwDoc::FldsToCalc( SwCalc& rCalc, const _SetGetExpFld& rToThisFld ) +{ + // erzeuge die Sortierteliste aller SetFelder + pUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_CALC ); + mbNewFldLst = sal_False; + + SwNewDBMgr* pMgr = GetNewDBMgr(); + pMgr->CloseAll(sal_False); + + if( pUpdtFlds->GetSortLst()->Count() ) + { + sal_uInt16 nLast; + _SetGetExpFld* pFld = (_SetGetExpFld*)&rToThisFld; + if( pUpdtFlds->GetSortLst()->Seek_Entry( pFld, &nLast ) ) + ++nLast; + + const _SetGetExpFldPtr* ppSortLst = pUpdtFlds->GetSortLst()->GetData(); + for( sal_uInt16 n = 0; n < nLast; ++n, ++ppSortLst ) + lcl_CalcFld( *this, rCalc, **ppSortLst, pMgr ); + } + + pMgr->CloseAll(sal_False); +} + +void SwDoc::FldsToCalc( SwCalc& rCalc, sal_uLong nLastNd, sal_uInt16 nLastCnt ) +{ + // erzeuge die Sortierteliste aller SetFelder + pUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_CALC ); + mbNewFldLst = sal_False; + + SwNewDBMgr* pMgr = GetNewDBMgr(); + pMgr->CloseAll(sal_False); + + const _SetGetExpFldPtr* ppSortLst = pUpdtFlds->GetSortLst()->GetData(); + + for( sal_uInt16 n = pUpdtFlds->GetSortLst()->Count(); + n && + ( (*ppSortLst)->GetNode() < nLastNd || + ( (*ppSortLst)->GetNode() == nLastNd && (*ppSortLst)->GetCntnt() <= nLastCnt ) + ); + --n, ++ppSortLst ) + lcl_CalcFld( *this, rCalc, **ppSortLst, pMgr ); + + pMgr->CloseAll(sal_False); +} + +void SwDoc::FldsToExpand( SwHash**& ppHashTbl, sal_uInt16& rTblSize, + const _SetGetExpFld& rToThisFld ) +{ + // erzeuge die Sortierteliste aller SetFelder + pUpdtFlds->MakeFldList( *this, mbNewFldLst, GETFLD_EXPAND ); + mbNewFldLst = sal_False; + + // HashTabelle fuer alle String Ersetzungen, wird "one the fly" gefuellt + // (versuche eine "ungerade"-Zahl zu erzeugen) + rTblSize = (( pUpdtFlds->GetSortLst()->Count() / 7 ) + 1 ) * 7; + ppHashTbl = new SwHash*[ rTblSize ]; + memset( ppHashTbl, 0, sizeof( _HashStr* ) * rTblSize ); + + sal_uInt16 nLast; + { + _SetGetExpFld* pTmp = (_SetGetExpFld*)&rToThisFld; + if( pUpdtFlds->GetSortLst()->Seek_Entry( pTmp, &nLast ) ) + ++nLast; + } + + sal_uInt16 nPos; + SwHash* pFnd; + String aNew; + const _SetGetExpFldPtr* ppSortLst = pUpdtFlds->GetSortLst()->GetData(); + for( ; nLast; --nLast, ++ppSortLst ) + { + const SwTxtFld* pTxtFld = (*ppSortLst)->GetFld(); + if( !pTxtFld ) + continue; + + const SwField* pFld = pTxtFld->GetFld().GetFld(); + switch( pFld->GetTyp()->Which() ) + { + case RES_SETEXPFLD: + if( nsSwGetSetExpType::GSE_STRING & pFld->GetSubType() ) + { + // setze in der HashTabelle den neuen Wert + // ist die "Formel" ein Feld ?? + SwSetExpField* pSFld = (SwSetExpField*)pFld; + LookString( ppHashTbl, rTblSize, pSFld->GetFormula(), aNew ); + + if( !aNew.Len() ) // nichts gefunden, dann ist + aNew = pSFld->GetFormula(); // die Formel der neue Wert + + // OD 11.02.2003 #i3141# - update expression of field as in + // method <SwDoc::UpdateExpFlds(..)> for string/text fields + pSFld->ChgExpStr( aNew ); + + // suche den Namen vom Feld + aNew = ((SwSetExpFieldType*)pSFld->GetTyp())->GetSetRefName(); + // Eintrag vorhanden ? + pFnd = Find( aNew, ppHashTbl, rTblSize, &nPos ); + if( pFnd ) + // Eintrag in der HashTabelle aendern + ((_HashStr*)pFnd)->aSetStr = pSFld->GetExpStr(); + else + // neuen Eintrag einfuegen + *(ppHashTbl + nPos ) = new _HashStr( aNew, + pSFld->GetExpStr(), (_HashStr*)*(ppHashTbl + nPos) ); + } + break; + case RES_DBFLD: + { + const String& rName = pFld->GetTyp()->GetName(); + + // Eintrag in den HashTable eintragen + // Eintrag vorhanden ? + pFnd = Find( rName, ppHashTbl, rTblSize, &nPos ); + String const value(pFld->ExpandField(IsClipBoard())); + if( pFnd ) + { + // Eintrag in der HashTabelle aendern + static_cast<_HashStr*>(pFnd)->aSetStr = value; + } + else + { + // neuen Eintrag einfuegen + *(ppHashTbl + nPos ) = new _HashStr( rName, + value, static_cast<_HashStr *>(*(ppHashTbl + nPos))); + } + } + break; + } + } +} + + +void SwDoc::UpdateExpFlds( SwTxtFld* pUpdtFld, bool bUpdRefFlds ) +{ + if( IsExpFldsLocked() || IsInReading() ) + return; + + sal_Bool bOldInUpdateFlds = pUpdtFlds->IsInUpdateFlds(); + pUpdtFlds->SetInUpdateFlds( sal_True ); + + pUpdtFlds->MakeFldList( *this, sal_True, GETFLD_ALL ); + mbNewFldLst = sal_False; + + if( !pUpdtFlds->GetSortLst()->Count() ) + { + if( bUpdRefFlds ) + UpdateRefFlds(NULL); + + pUpdtFlds->SetInUpdateFlds( bOldInUpdateFlds ); + pUpdtFlds->SetFieldsDirty( sal_False ); + return ; + } + + sal_uInt16 nWhich, n; + + // HashTabelle fuer alle String Ersetzungen, wird "one the fly" gefuellt + // (versuche eine "ungerade"-Zahl zu erzeugen) + sal_uInt16 nStrFmtCnt = (( pFldTypes->Count() / 7 ) + 1 ) * 7; + SwHash** pHashStrTbl = new SwHash*[ nStrFmtCnt ]; + memset( pHashStrTbl, 0, sizeof( _HashStr* ) * nStrFmtCnt ); + + { + const SwFieldType* pFldType; + // gesondert behandeln: + for( n = pFldTypes->Count(); n; ) + switch( ( pFldType = (*pFldTypes)[ --n ] )->Which() ) + { + case RES_USERFLD: + { + // Eintrag vorhanden ? + sal_uInt16 nPos; + const String& rNm = pFldType->GetName(); + String sExpand(((SwUserFieldType*)pFldType)->Expand(nsSwGetSetExpType::GSE_STRING, 0, 0)); + SwHash* pFnd = Find( rNm, pHashStrTbl, nStrFmtCnt, &nPos ); + if( pFnd ) + // Eintrag in der HashTabelle aendern ?? + ((_HashStr*)pFnd)->aSetStr = sExpand; + else + // neuen Eintrag einfuegen + *(pHashStrTbl + nPos ) = new _HashStr( rNm, sExpand, + (_HashStr*)*(pHashStrTbl + nPos) ); + } + break; + case RES_SETEXPFLD: + ((SwSetExpFieldType*)pFldType)->SetOutlineChgNd( 0 ); + break; + } + } + + // Ok, das Array ist soweit mit allen Feldern gefuellt, dann rechne mal + SwCalc aCalc( *this ); + + String sDBNumNm( SwFieldType::GetTypeStr( TYP_DBSETNUMBERFLD ) ); + + // aktuelle Datensatznummer schon vorher einstellen + SwNewDBMgr* pMgr = GetNewDBMgr(); + pMgr->CloseAll(sal_False); +/* + if(pMgr && pMgr->OpenDB(DBMGR_STD, GetDBDesc(), sal_False)) + { + if(!pMgr->IsInMerge() ) + pMgr->ToFirstSelectedRecord(DBMGR_STD); + + aCalc.VarChange( sDBNumNm, pMgr->GetCurSelectedRecordId(DBMGR_STD)); + } +*/ + + String aNew; + const _SetGetExpFldPtr* ppSortLst = pUpdtFlds->GetSortLst()->GetData(); + for( n = pUpdtFlds->GetSortLst()->Count(); n; --n, ++ppSortLst ) + { + SwSection* pSect = (SwSection*)(*ppSortLst)->GetSection(); + if( pSect ) + { + //!SECTION + +// if( pGFld->IsInBodyTxt() ) + SwSbxValue aValue = aCalc.Calculate( + pSect->GetCondition() ); + if(!aValue.IsVoidValue()) + pSect->SetCondHidden( aValue.GetBool() ); + continue; + } + + SwTxtFld* pTxtFld = (SwTxtFld*)(*ppSortLst)->GetFld(); + if( !pTxtFld ) + { + ASSERT( !this, "was ist es denn nun" ); + continue; + } + + SwFmtFld* pFmtFld = (SwFmtFld*)&pTxtFld->GetFld(); + SwField* pFld = pFmtFld->GetFld(); + + switch( nWhich = pFld->GetTyp()->Which() ) + { + case RES_HIDDENTXTFLD: + { + SwHiddenTxtField* pHFld = (SwHiddenTxtField*)pFld; + SwSbxValue aValue = aCalc.Calculate( pHFld->GetPar1() ); + sal_Bool bValue = !aValue.GetBool(); + if(!aValue.IsVoidValue()) + { + pHFld->SetValue( bValue ); + // Feld Evaluieren + pHFld->Evaluate(this); + } + } + break; + case RES_HIDDENPARAFLD: + { + SwHiddenParaField* pHPFld = (SwHiddenParaField*)pFld; + SwSbxValue aValue = aCalc.Calculate( pHPFld->GetPar1() ); + sal_Bool bValue = aValue.GetBool(); + if(!aValue.IsVoidValue()) + pHPFld->SetHidden( bValue ); + } + break; + case RES_DBSETNUMBERFLD: + { + ((SwDBSetNumberField*)pFld)->Evaluate(this); + aCalc.VarChange( sDBNumNm, ((SwDBSetNumberField*)pFld)->GetSetNumber()); + } + break; + case RES_DBNEXTSETFLD: + case RES_DBNUMSETFLD: + UpdateDBNumFlds( *(SwDBNameInfField*)pFld, aCalc ); + break; + case RES_DBFLD: + { + // Feld Evaluieren + ((SwDBField*)pFld)->Evaluate(); + + SwDBData aTmpDBData(((SwDBField*)pFld)->GetDBData()); + + if( pMgr->IsDataSourceOpen(aTmpDBData.sDataSource, aTmpDBData.sCommand, sal_False)) + aCalc.VarChange( sDBNumNm, pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType)); + + const String& rName = pFld->GetTyp()->GetName(); + + // Wert fuer den Calculator setzen +//JP 10.02.96: GetValue macht hier doch keinen Sinn +// ((SwDBField*)pFld)->GetValue(); + +//!OK aCalc.VarChange(aName, ((SwDBField*)pFld)->GetValue(aCalc)); + + // Eintrag in den HashTable eintragen + // Eintrag vorhanden ? + sal_uInt16 nPos; + SwHash* pFnd = Find( rName, pHashStrTbl, nStrFmtCnt, &nPos ); + String const value(pFld->ExpandField(IsClipBoard())); + if( pFnd ) + { + // Eintrag in der HashTabelle aendern + static_cast<_HashStr*>(pFnd)->aSetStr = value; + } + else + { + // neuen Eintrag einfuegen + *(pHashStrTbl + nPos ) = new _HashStr( rName, + value, static_cast<_HashStr *>(*(pHashStrTbl + nPos))); + } + } + break; + case RES_GETEXPFLD: + case RES_SETEXPFLD: + { + if( nsSwGetSetExpType::GSE_STRING & pFld->GetSubType() ) // String Ersetzung + { + if( RES_GETEXPFLD == nWhich ) + { + SwGetExpField* pGFld = (SwGetExpField*)pFld; + + if( (!pUpdtFld || pUpdtFld == pTxtFld ) + && pGFld->IsInBodyTxt() ) + { + LookString( pHashStrTbl, nStrFmtCnt, + pGFld->GetFormula(), aNew ); + pGFld->ChgExpStr( aNew ); + } + } + else + { + SwSetExpField* pSFld = (SwSetExpField*)pFld; + // ist die "Formel" ein Feld ?? + LookString( pHashStrTbl, nStrFmtCnt, + pSFld->GetFormula(), aNew ); + + if( !aNew.Len() ) // nichts gefunden, dann ist die + aNew = pSFld->GetFormula(); // Formel der neue Wert + + // nur ein spezielles FeldUpdaten ? + if( !pUpdtFld || pUpdtFld == pTxtFld ) + pSFld->ChgExpStr( aNew ); + + // suche den Namen vom Feld + aNew = ((SwSetExpFieldType*)pSFld->GetTyp())->GetSetRefName(); + // Eintrag vorhanden ? + sal_uInt16 nPos; + SwHash* pFnd = Find( aNew, pHashStrTbl, nStrFmtCnt, &nPos ); + if( pFnd ) + // Eintrag in der HashTabelle aendern + ((_HashStr*)pFnd)->aSetStr = pSFld->GetExpStr(); + else + // neuen Eintrag einfuegen + *(pHashStrTbl + nPos ) = pFnd = new _HashStr( aNew, + pSFld->GetExpStr(), + (_HashStr*)*(pHashStrTbl + nPos) ); + + // Erweiterung fuers Rechnen mit Strings + SwSbxValue aValue; + aValue.PutString( ((_HashStr*)pFnd)->aSetStr ); + aCalc.VarChange( aNew, aValue ); + } + } + else // Formel neu berechnen + { + if( RES_GETEXPFLD == nWhich ) + { + SwGetExpField* pGFld = (SwGetExpField*)pFld; + + if( (!pUpdtFld || pUpdtFld == pTxtFld ) + && pGFld->IsInBodyTxt() ) + { + SwSbxValue aValue = aCalc.Calculate( + pGFld->GetFormula()); + if(!aValue.IsVoidValue()) + pGFld->SetValue(aValue.GetDouble() ); + } + } + else + { + SwSetExpField* pSFld = (SwSetExpField*)pFld; + SwSetExpFieldType* pSFldTyp = (SwSetExpFieldType*)pFld->GetTyp(); + aNew = pSFldTyp->GetName(); + + SwNode* pSeqNd = 0; + + if( pSFld->IsSequenceFld() ) + { + const sal_uInt8 nLvl = pSFldTyp->GetOutlineLvl(); + if( MAXLEVEL > nLvl ) + { + // dann teste, ob die Nummer neu aufsetzen muss + pSeqNd = GetNodes()[ (*ppSortLst)->GetNode() ]; + + const SwTxtNode* pOutlNd = pSeqNd-> + FindOutlineNodeOfLevel( nLvl ); + if( pSFldTyp->GetOutlineChgNd() != pOutlNd ) + { + pSFldTyp->SetOutlineChgNd( pOutlNd ); + aCalc.VarChange( aNew, 0 ); + } + } + } + + aNew += '='; + aNew += pSFld->GetFormula(); + + SwSbxValue aValue = aCalc.Calculate( aNew ); + double nErg = aValue.GetDouble(); + // nur ein spezielles Feld updaten ? + if( !aValue.IsVoidValue() && (!pUpdtFld || pUpdtFld == pTxtFld) ) + { + pSFld->SetValue( nErg ); + + if( pSeqNd ) + pSFldTyp->SetChapter( *pSFld, *pSeqNd ); + } + } + } + } + } // switch + + pFmtFld->Modify( 0, 0 ); // Formatierung anstossen + + if( pUpdtFld == pTxtFld ) // sollte nur dieses geupdatet werden + { + if( RES_GETEXPFLD == nWhich || // nur GetFeld oder + RES_HIDDENTXTFLD == nWhich || // HiddenTxt? + RES_HIDDENPARAFLD == nWhich) // HiddenParaFld? + break; // beenden + pUpdtFld = 0; // ab jetzt alle Updaten + } + } + + pMgr->CloseAll(sal_False); + // HashTabelle wieder loeschen + ::DeleteHashTable( pHashStrTbl, nStrFmtCnt ); + + // Referenzfelder updaten + if( bUpdRefFlds ) + UpdateRefFlds(NULL); + + pUpdtFlds->SetInUpdateFlds( bOldInUpdateFlds ); + pUpdtFlds->SetFieldsDirty( sal_False ); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::UpdateDBNumFlds( SwDBNameInfField& rDBFld, SwCalc& rCalc ) +{ + SwNewDBMgr* pMgr = GetNewDBMgr(); + + sal_uInt16 nFldType = rDBFld.Which(); + + sal_Bool bPar1 = rCalc.Calculate( rDBFld.GetPar1() ).GetBool(); + + if( RES_DBNEXTSETFLD == nFldType ) + ((SwDBNextSetField&)rDBFld).SetCondValid( bPar1 ); + else + ((SwDBNumSetField&)rDBFld).SetCondValid( bPar1 ); + + if( rDBFld.GetRealDBData().sDataSource.getLength() ) + { + // Eine bestimmte Datenbank bearbeiten + if( RES_DBNEXTSETFLD == nFldType ) + ((SwDBNextSetField&)rDBFld).Evaluate(this); + else + ((SwDBNumSetField&)rDBFld).Evaluate(this); + + SwDBData aTmpDBData( rDBFld.GetDBData(this) ); + + if( pMgr->OpenDataSource( aTmpDBData.sDataSource, aTmpDBData.sCommand, -1, false )) + rCalc.VarChange( lcl_GetDBVarName( *this, rDBFld), + pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType) ); + } + else + { + DBG_ERROR("TODO: what should happen with unnamed DBFields?"); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::_InitFieldTypes() // wird vom CTOR gerufen!! +{ + // Feldtypen + sal_uInt16 nFldType = 0; + pFldTypes->Insert( new SwDateTimeFieldType(this), nFldType++ ); + pFldTypes->Insert( new SwChapterFieldType, nFldType++ ); + pFldTypes->Insert( new SwPageNumberFieldType, nFldType++ ); + pFldTypes->Insert( new SwAuthorFieldType, nFldType++ ); + pFldTypes->Insert( new SwFileNameFieldType(this), nFldType++ ); + pFldTypes->Insert( new SwDBNameFieldType(this), nFldType++); + pFldTypes->Insert( new SwGetExpFieldType(this), nFldType++ ); + pFldTypes->Insert( new SwGetRefFieldType( this ), nFldType++ ); + pFldTypes->Insert( new SwHiddenTxtFieldType, nFldType++ ); + pFldTypes->Insert( new SwPostItFieldType(this), nFldType++ ); + pFldTypes->Insert( new SwDocStatFieldType(this), nFldType++); + pFldTypes->Insert( new SwDocInfoFieldType(this), nFldType++); + pFldTypes->Insert( new SwInputFieldType( this ), nFldType++ ); + pFldTypes->Insert( new SwTblFieldType( this ), nFldType++); + pFldTypes->Insert( new SwMacroFieldType(this), nFldType++ ); + pFldTypes->Insert( new SwHiddenParaFieldType, nFldType++ ); + pFldTypes->Insert( new SwDBNextSetFieldType, nFldType++ ); + pFldTypes->Insert( new SwDBNumSetFieldType, nFldType++ ); + pFldTypes->Insert( new SwDBSetNumberFieldType, nFldType++ ); + pFldTypes->Insert( new SwTemplNameFieldType(this), nFldType++); + pFldTypes->Insert( new SwTemplNameFieldType(this),nFldType++); + pFldTypes->Insert( new SwExtUserFieldType, nFldType++ ); + pFldTypes->Insert( new SwRefPageSetFieldType, nFldType++ ); + pFldTypes->Insert( new SwRefPageGetFieldType( this ), nFldType++ ); + pFldTypes->Insert( new SwJumpEditFieldType( this ), nFldType++ ); + pFldTypes->Insert( new SwScriptFieldType( this ), nFldType++ ); + pFldTypes->Insert( new SwCombinedCharFieldType, nFldType++ ); + pFldTypes->Insert( new SwDropDownFieldType, nFldType++ ); + + // Types muessen am Ende stehen !! + // Im InsertFldType wird davon ausgegangen !!!! + // MIB 14.04.95: Im Sw3StringPool::Setup (sw3imp.cxx) und + // lcl_sw3io_InSetExpField (sw3field.cxx) jetzt auch + pFldTypes->Insert( new SwSetExpFieldType(this, + SW_RESSTR(STR_POOLCOLL_LABEL_ABB), nsSwGetSetExpType::GSE_SEQ), nFldType++); + pFldTypes->Insert( new SwSetExpFieldType(this, + SW_RESSTR(STR_POOLCOLL_LABEL_TABLE), nsSwGetSetExpType::GSE_SEQ),nFldType++); + pFldTypes->Insert( new SwSetExpFieldType(this, + SW_RESSTR(STR_POOLCOLL_LABEL_FRAME), nsSwGetSetExpType::GSE_SEQ),nFldType++); + pFldTypes->Insert( new SwSetExpFieldType(this, + SW_RESSTR(STR_POOLCOLL_LABEL_DRAWING), nsSwGetSetExpType::GSE_SEQ),nFldType++); + + ASSERT( nFldType == INIT_FLDTYPES, "Bad initsize: SwFldTypes" ); +} + +void SwDoc::InsDelFldInFldLst( bool bIns, const SwTxtFld& rFld ) +{ + if( !mbNewFldLst || !IsInDtor() ) + pUpdtFlds->InsDelFldInFldLst( bIns, rFld ); +} + +SwDBData SwDoc::GetDBData() +{ + return GetDBDesc(); +} + +const SwDBData& SwDoc::GetDBDesc() +{ + if(!aDBData.sDataSource.getLength()) + { + const sal_uInt16 nSize = pFldTypes->Count(); + for(sal_uInt16 i = 0; i < nSize && !aDBData.sDataSource.getLength(); ++i) + { + SwFieldType& rFldType = *((*pFldTypes)[i]); + sal_uInt16 nWhich = rFldType.Which(); + if(IsUsed(rFldType)) + { + switch(nWhich) + { + case RES_DBFLD: + case RES_DBNEXTSETFLD: + case RES_DBNUMSETFLD: + case RES_DBSETNUMBERFLD: + { + SwClientIter aIter( rFldType ); + SwFmtFld* pFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + while(pFld) + { + if(pFld->IsFldInDoc()) + { + if(RES_DBFLD == nWhich) + aDBData = + (static_cast < SwDBFieldType * > (pFld->GetFld()->GetTyp())) + ->GetDBData(); + else + aDBData = (static_cast < SwDBNameInfField* > (pFld->GetFld()))->GetRealDBData(); + break; + } + pFld = (SwFmtFld*)aIter.Next(); + } + } + break; + } + } + } + } + if(!aDBData.sDataSource.getLength()) + aDBData = GetNewDBMgr()->GetAddressDBName(); + return aDBData; +} + +void SwDoc::SetInitDBFields( sal_Bool b ) +{ + GetNewDBMgr()->SetInitDBFields( b ); +} + +/*-------------------------------------------------------------------- + Beschreibung: Alle von Feldern verwendete Datenbanken herausfinden + --------------------------------------------------------------------*/ +String lcl_DBDataToString(const SwDBData& rData) +{ + String sRet = rData.sDataSource; + sRet += DB_DELIM; + sRet += (String)rData.sCommand; + sRet += DB_DELIM; + sRet += String::CreateFromInt32(rData.nCommandType); + return sRet; +} +void SwDoc::GetAllUsedDB( SvStringsDtor& rDBNameList, + const SvStringsDtor* pAllDBNames ) +{ + SvStringsDtor aUsedDBNames; + SvStringsDtor aAllDBNames; + + if( !pAllDBNames ) + { + GetAllDBNames( aAllDBNames ); + pAllDBNames = &aAllDBNames; + } + + SwSectionFmts& rArr = GetSections(); + for (sal_uInt16 n = rArr.Count(); n; ) + { + SwSection* pSect = rArr[ --n ]->GetSection(); + + if( pSect ) + { + String aCond( pSect->GetCondition() ); + AddUsedDBToList( rDBNameList, FindUsedDBs( *pAllDBNames, + aCond, aUsedDBNames ) ); + aUsedDBNames.DeleteAndDestroy( 0, aUsedDBNames.Count() ); + } + } + + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); + for (sal_uInt32 n = 0; n < nMaxItems; ++n) + { + if( 0 == (pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) )) + continue; + + const SwFmtFld* pFmtFld = (SwFmtFld*)pItem; + const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); + if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() ) + continue; + + const SwField* pFld = pFmtFld->GetFld(); + switch( pFld->GetTyp()->Which() ) + { + case RES_DBFLD: + AddUsedDBToList( rDBNameList, + lcl_DBDataToString(((SwDBField*)pFld)->GetDBData() )); + break; + + case RES_DBSETNUMBERFLD: + case RES_DBNAMEFLD: + AddUsedDBToList( rDBNameList, + lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData() )); + break; + + case RES_DBNUMSETFLD: + case RES_DBNEXTSETFLD: + AddUsedDBToList( rDBNameList, + lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData() )); + // kein break // JP: ist das so richtig ?? + + case RES_HIDDENTXTFLD: + case RES_HIDDENPARAFLD: + AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, + pFld->GetPar1(), aUsedDBNames )); + aUsedDBNames.DeleteAndDestroy( 0, aUsedDBNames.Count() ); + break; + + case RES_SETEXPFLD: + case RES_GETEXPFLD: + case RES_TABLEFLD: + AddUsedDBToList(rDBNameList, FindUsedDBs( *pAllDBNames, + pFld->GetFormula(), aUsedDBNames )); + aUsedDBNames.DeleteAndDestroy( 0, aUsedDBNames.Count() ); + break; + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::GetAllDBNames( SvStringsDtor& rAllDBNames ) +{ + SwNewDBMgr* pMgr = GetNewDBMgr(); + + const SwDSParamArr& rArr = pMgr->GetDSParamArray(); + for(sal_uInt16 i = 0; i < rArr.Count(); i++) + { + SwDSParam* pParam = rArr[i]; + String* pStr = new String( pParam->sDataSource ); + (*pStr) += DB_DELIM; + (*pStr) += (String)pParam->sCommand; + rAllDBNames.Insert( pStr, rAllDBNames.Count() ); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +SvStringsDtor& SwDoc::FindUsedDBs( const SvStringsDtor& rAllDBNames, + const String& rFormel, + SvStringsDtor& rUsedDBNames ) +{ + const CharClass& rCC = GetAppCharClass(); + String sFormel( rFormel); +#ifndef UNX + rCC.toUpper( sFormel ); +#endif + + xub_StrLen nPos; + for (sal_uInt16 i = 0; i < rAllDBNames.Count(); ++i ) + { + const String* pStr = rAllDBNames.GetObject(i); + + if( STRING_NOTFOUND != (nPos = sFormel.Search( *pStr )) && + sFormel.GetChar( nPos + pStr->Len() ) == '.' && + (!nPos || !rCC.isLetterNumeric( sFormel, nPos - 1 ))) + { + // Tabellenname suchen + xub_StrLen nEndPos; + nPos += pStr->Len() + 1; + if( STRING_NOTFOUND != (nEndPos = sFormel.Search('.', nPos)) ) + { + String* pDBNm = new String( *pStr ); + pDBNm->Append( DB_DELIM ); + pDBNm->Append( sFormel.Copy( nPos, nEndPos - nPos )); + rUsedDBNames.Insert( pDBNm, rUsedDBNames.Count() ); + } + } + } + return rUsedDBNames; +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::AddUsedDBToList( SvStringsDtor& rDBNameList, + const SvStringsDtor& rUsedDBNames ) +{ + for (sal_uInt16 i = 0; i < rUsedDBNames.Count(); i++) + AddUsedDBToList( rDBNameList, *rUsedDBNames.GetObject(i) ); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::AddUsedDBToList( SvStringsDtor& rDBNameList, const String& rDBName) +{ + if( !rDBName.Len() ) + return; + +#ifdef UNX + for( sal_uInt16 i = 0; i < rDBNameList.Count(); ++i ) + if( rDBName == rDBNameList.GetObject(i)->GetToken(0) ) + return; +#else + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + for( sal_uInt16 i = 0; i < rDBNameList.Count(); ++i ) + if( rSCmp.isEqual( rDBName, rDBNameList.GetObject(i)->GetToken(0) ) ) + return; +#endif + + SwDBData aData; + aData.sDataSource = rDBName.GetToken(0, DB_DELIM); + aData.sCommand = rDBName.GetToken(1, DB_DELIM); + aData.nCommandType = -1; + GetNewDBMgr()->CreateDSData(aData); + String* pNew = new String( rDBName ); + rDBNameList.Insert( pNew, rDBNameList.Count() ); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::ChangeDBFields( const SvStringsDtor& rOldNames, + const String& rNewName ) +{ + SwDBData aNewDBData; + aNewDBData.sDataSource = rNewName.GetToken(0, DB_DELIM); + aNewDBData.sCommand = rNewName.GetToken(1, DB_DELIM); + aNewDBData.nCommandType = (short)rNewName.GetToken(2, DB_DELIM).ToInt32(); + + String sFormel; + + SwSectionFmts& rArr = GetSections(); + for (sal_uInt16 n = rArr.Count(); n; ) + { + SwSection* pSect = rArr[ --n ]->GetSection(); + + if( pSect ) + { + sFormel = pSect->GetCondition(); + ReplaceUsedDBs( rOldNames, rNewName, sFormel); + pSect->SetCondition(sFormel); + } + } + + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); + + for (sal_uInt32 n = 0; n < nMaxItems; ++n ) + { + if( 0 == (pItem = GetAttrPool().GetItem2( RES_TXTATR_FIELD, n ) )) + continue; + + SwFmtFld* pFmtFld = (SwFmtFld*)pItem; + SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); + if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() ) + continue; + + SwField* pFld = pFmtFld->GetFld(); + sal_Bool bExpand = sal_False; + + switch( pFld->GetTyp()->Which() ) + { + case RES_DBFLD: + if( IsNameInArray( rOldNames, lcl_DBDataToString(((SwDBField*)pFld)->GetDBData()))) + { + SwDBFieldType* pOldTyp = (SwDBFieldType*)pFld->GetTyp(); + + SwDBFieldType* pTyp = (SwDBFieldType*)InsertFldType( + SwDBFieldType(this, pOldTyp->GetColumnName(), aNewDBData)); + + pTyp->Add(pFmtFld); // Feld auf neuen Typ umhaengen + pFld->ChgTyp(pTyp); + + ((SwDBField*)pFld)->ClearInitialized(); + ((SwDBField*)pFld)->InitContent(); + + bExpand = sal_True; + } + break; + + case RES_DBSETNUMBERFLD: + case RES_DBNAMEFLD: + if( IsNameInArray( rOldNames, + lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData()))) + { + ((SwDBNameInfField*)pFld)->SetDBData(aNewDBData); + bExpand = sal_True; + } + break; + + case RES_DBNUMSETFLD: + case RES_DBNEXTSETFLD: + if( IsNameInArray( rOldNames, + lcl_DBDataToString(((SwDBNameInfField*)pFld)->GetRealDBData()))) + { + ((SwDBNameInfField*)pFld)->SetDBData(aNewDBData); + bExpand = sal_True; + } + // kein break; + case RES_HIDDENTXTFLD: + case RES_HIDDENPARAFLD: + sFormel = pFld->GetPar1(); + ReplaceUsedDBs( rOldNames, rNewName, sFormel); + pFld->SetPar1( sFormel ); + bExpand = sal_True; + break; + + case RES_SETEXPFLD: + case RES_GETEXPFLD: + case RES_TABLEFLD: + sFormel = pFld->GetFormula(); + ReplaceUsedDBs( rOldNames, rNewName, sFormel); + pFld->SetPar2( sFormel ); + bExpand = sal_True; + break; + } + + if (bExpand) + pTxtFld->ExpandAlways(); + } + SetModified(); +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDoc::ReplaceUsedDBs( const SvStringsDtor& rUsedDBNames, + const String& rNewName, String& rFormel ) +{ + const CharClass& rCC = GetAppCharClass(); + String sFormel(rFormel); + String sNewName( rNewName ); + sNewName.SearchAndReplace( DB_DELIM, '.'); + //the command type is not part of the condition + sNewName = sNewName.GetToken(0, DB_DELIM); + String sUpperNewNm( sNewName ); + + + for( sal_uInt16 i = 0; i < rUsedDBNames.Count(); ++i ) + { + String sDBName( *rUsedDBNames.GetObject( i ) ); + + sDBName.SearchAndReplace( DB_DELIM, '.'); + //cut off command type + sDBName = sDBName.GetToken(0, DB_DELIM); + if( !sDBName.Equals( sUpperNewNm )) + { + xub_StrLen nPos = 0; + + while ((nPos = sFormel.Search(sDBName, nPos)) != STRING_NOTFOUND) + { + if( sFormel.GetChar( nPos + sDBName.Len() ) == '.' && + (!nPos || !rCC.isLetterNumeric( sFormel, nPos - 1 ))) + { + rFormel.Erase( nPos, sDBName.Len() ); + rFormel.Insert( sNewName, nPos ); + //prevent re-searching - this is useless and provokes + //endless loops when names containing each other and numbers are exchanged + //e.g.: old ?12345.12345 new: i12345.12345 + nPos = nPos + sNewName.Len(); + sFormel = rFormel; + } + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +sal_Bool SwDoc::IsNameInArray( const SvStringsDtor& rArr, const String& rName ) +{ +#ifdef UNX + for( sal_uInt16 i = 0; i < rArr.Count(); ++i ) + if( rName == *rArr[ i ] ) + return sal_True; +#else + const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore(); + for( sal_uInt16 i = 0; i < rArr.Count(); ++i ) + if( rSCmp.isEqual( rName, *rArr[ i] )) + return sal_True; +#endif + return sal_False; +} + +void SwDoc::SetFixFields( bool bOnlyTimeDate, const DateTime* pNewDateTime ) +{ + sal_Bool bIsModified = IsModified(); + + sal_uLong nDate, nTime; + if( pNewDateTime ) + { + nDate = pNewDateTime->GetDate(); + nTime = pNewDateTime->GetTime(); + } + else + { + nDate = Date().GetDate(); + nTime = Time().GetTime(); + } + + sal_uInt16 aTypes[5] = { + /*0*/ RES_DOCINFOFLD, + /*1*/ RES_AUTHORFLD, + /*2*/ RES_EXTUSERFLD, + /*3*/ RES_FILENAMEFLD, + /*4*/ RES_DATETIMEFLD }; // MUSS am Ende stehen!! + + sal_uInt16 nStt = bOnlyTimeDate ? 4 : 0; + + for( ; nStt < 5; ++nStt ) + { + SwFieldType* pFldType = GetSysFldType( aTypes[ nStt ] ); + SwClientIter aDocInfIter( *pFldType ); + + for( SwFmtFld* pFld = (SwFmtFld*)aDocInfIter.First( TYPE( SwFmtFld )); + pFld; pFld = (SwFmtFld*)aDocInfIter.Next() ) + { + if( pFld && pFld->GetTxtFld() ) + { + sal_Bool bChgd = sal_False; + switch( aTypes[ nStt ] ) + { + case RES_DOCINFOFLD: + if( ((SwDocInfoField*)pFld->GetFld())->IsFixed() ) + { + bChgd = sal_True; + SwDocInfoField* pDocInfFld = (SwDocInfoField*)pFld->GetFld(); + pDocInfFld->SetExpansion( ((SwDocInfoFieldType*) + pDocInfFld->GetTyp())->Expand( + pDocInfFld->GetSubType(), + pDocInfFld->GetFormat(), + pDocInfFld->GetLanguage(), + pDocInfFld->GetName() ) ); + } + break; + + case RES_AUTHORFLD: + if( ((SwAuthorField*)pFld->GetFld())->IsFixed() ) + { + bChgd = sal_True; + SwAuthorField* pAuthorFld = (SwAuthorField*)pFld->GetFld(); + pAuthorFld->SetExpansion( ((SwAuthorFieldType*) + pAuthorFld->GetTyp())->Expand( + pAuthorFld->GetFormat() ) ); + } + break; + + case RES_EXTUSERFLD: + if( ((SwExtUserField*)pFld->GetFld())->IsFixed() ) + { + bChgd = sal_True; + SwExtUserField* pExtUserFld = (SwExtUserField*)pFld->GetFld(); + pExtUserFld->SetExpansion( ((SwExtUserFieldType*) + pExtUserFld->GetTyp())->Expand( + pExtUserFld->GetSubType(), + pExtUserFld->GetFormat())); + } + break; + + case RES_DATETIMEFLD: + if( ((SwDateTimeField*)pFld->GetFld())->IsFixed() ) + { + bChgd = sal_True; + ((SwDateTimeField*)pFld->GetFld())->SetDateTime( + DateTime(Date(nDate), Time(nTime)) ); + } + break; + + case RES_FILENAMEFLD: + if( ((SwFileNameField*)pFld->GetFld())->IsFixed() ) + { + bChgd = sal_True; + SwFileNameField* pFileNameFld = + (SwFileNameField*)pFld->GetFld(); + pFileNameFld->SetExpansion( ((SwFileNameFieldType*) + pFileNameFld->GetTyp())->Expand( + pFileNameFld->GetFormat() ) ); + } + break; + } + + // Formatierung anstossen + if( bChgd ) + pFld->Modify( 0, 0 ); + } + } + } + + if( !bIsModified ) + ResetModified(); +} + +bool SwDoc::SetFieldsDirty( bool b, const SwNode* pChk, sal_uLong nLen ) +{ + // teste ggfs. mal, ob die angegbenen Nodes ueberhaupt Felder beinhalten. + // wenn nicht, braucht das Flag nicht veraendert werden. + sal_Bool bFldsFnd = sal_False; + if( b && pChk && !GetUpdtFlds().IsFieldsDirty() && !IsInDtor() + // ?? was ist mit Undo, da will man es doch auch haben !! + /*&& &pChk->GetNodes() == &GetNodes()*/ ) + { + b = sal_False; + if( !nLen ) + ++nLen; + sal_uLong nStt = pChk->GetIndex(); + const SwNodes& rNds = pChk->GetNodes(); + while( nLen-- ) + { + const SwTxtNode* pTNd = rNds[ nStt++ ]->GetTxtNode(); + if( pTNd ) + { + if( //pTNd->GetFmtColl() && //#outline level,zhaojianwei + // MAXLEVEL > pTNd->GetTxtColl()->GetOutlineLevel() ) + pTNd->GetAttrOutlineLevel() != 0 )//<-end,zhaojianwei + // Kapitelfelder aktualisieren + b = sal_True; + else if( pTNd->GetpSwpHints() && pTNd->GetSwpHints().Count() ) + for( sal_uInt16 n = 0, nEnd = pTNd->GetSwpHints().Count(); + n < nEnd; ++n ) + { + const SwTxtAttr* pAttr = pTNd->GetSwpHints()[ n ]; + if( RES_TXTATR_FIELD == pAttr->Which() ) + { + b = sal_True; + break; + } + } + + if( b ) + break; + } + } + bFldsFnd = b; + } + GetUpdtFlds().SetFieldsDirty( b ); + return bFldsFnd; +} +/* -----------------------------21.12.99 12:55-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwDoc::ChangeAuthorityData( const SwAuthEntry* pNewData ) +{ + const sal_uInt16 nSize = pFldTypes->Count(); + + for( sal_uInt16 i = INIT_FLDTYPES; i < nSize; ++i ) + { + SwFieldType* pFldType = (*pFldTypes)[i]; + if( RES_AUTHORITY == pFldType->Which() ) + { + SwAuthorityFieldType* pAuthType = (SwAuthorityFieldType*)pFldType; + pAuthType->ChangeEntryContent(pNewData); + break; + } + } + +} +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDocUpdtFld::InsDelFldInFldLst( sal_Bool bIns, const SwTxtFld& rFld ) +{ + sal_uInt16 nWhich = rFld.GetFld().GetFld()->GetTyp()->Which(); + switch( nWhich ) + { + case RES_DBFLD: + case RES_SETEXPFLD: + case RES_HIDDENPARAFLD: + case RES_HIDDENTXTFLD: + case RES_DBNUMSETFLD: + case RES_DBNEXTSETFLD: + case RES_DBSETNUMBERFLD: + case RES_GETEXPFLD: + break; // diese muessen ein-/ausgetragen werden! + + default: + return; + } + + SetFieldsDirty( sal_True ); + if( !pFldSortLst ) + { + if( !bIns ) // keine Liste vorhanden und loeschen + return; // dann nichts tun + pFldSortLst = new _SetGetExpFlds( 64, 16 ); + } + + if( bIns ) // neu einfuegen: + GetBodyNode( rFld, nWhich ); + else + { + // ueber den pTxtFld Pointer suchen. Ist zwar eine Sortierte + // Liste, aber nach Node-Positionen sortiert. Bis dieser + // bestimmt ist, ist das Suchen nach dem Pointer schon fertig + for( sal_uInt16 n = 0; n < pFldSortLst->Count(); ++n ) + if( &rFld == (*pFldSortLst)[ n ]->GetPointer() ) + pFldSortLst->DeleteAndDestroy( n--, 1 ); + // ein Feld kann mehrfach vorhanden sein! + } +} + +void SwDocUpdtFld::MakeFldList( SwDoc& rDoc, int bAll, int eGetMode ) +{ + if( !pFldSortLst || bAll || !( eGetMode & nFldLstGetMode ) || + rDoc.GetNodes().Count() != nNodes ) + _MakeFldList( rDoc, eGetMode ); +} + +void SwDocUpdtFld::_MakeFldList( SwDoc& rDoc, int eGetMode ) +{ + // neue Version: gehe ueber alle Felder vom Attribut-Pool + if( pFldSortLst ) + delete pFldSortLst; + pFldSortLst = new _SetGetExpFlds( 64, 16 ); + + /// OD 09.08.2002 [#101207#,#101216#,#101778#] - consider and unhide sections + /// with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>) + /// notes by OD: + /// eGetMode == GETFLD_CALC in call from methods SwDoc::FldsToCalc + /// eGetMode == GETFLD_EXPAND in call from method SwDoc::FldsToExpand + /// eGetMode == GETFLD_ALL in call from method SwDoc::UpdateExpFlds + /// I figured out that hidden section only have to be shown, + /// if fields have updated (call by SwDoc::UpdateExpFlds) and thus + /// the hide conditions of section have to be updated. + /// For correct updating the hide condition of a section, its position + /// have to be known in order to insert the hide condition as a new + /// expression field into the sorted field list (<pFldSortLst>). + if ( eGetMode == GETFLD_ALL ) + // zuerst die Bereiche einsammeln. Alle die ueber Bedingung + // gehiddet sind, wieder mit Frames versorgen, damit die darin + // enthaltenen Felder richtig einsortiert werden!!! + { + // damit die Frames richtig angelegt werden, muessen sie in der + // Reihenfolgen von oben nach unten expandiert werden + SvULongs aTmpArr; + SwSectionFmts& rArr = rDoc.GetSections(); + SwSectionNode* pSectNd; + sal_uInt16 nArrStt = 0; + sal_uLong nSttCntnt = rDoc.GetNodes().GetEndOfExtras().GetIndex(); + + for (sal_uInt16 n = rArr.Count(); n; ) + { + SwSection* pSect = rArr[ --n ]->GetSection(); + if( pSect && pSect->IsHidden() && pSect->GetCondition().Len() && + 0 != ( pSectNd = pSect->GetFmt()->GetSectionNode() )) + { + sal_uLong nIdx = pSectNd->GetIndex(); + sal_uInt16 i; + + for( i = 0; i < aTmpArr.Count() && aTmpArr[ i ] < nIdx; ++i ) + ; + aTmpArr.Insert( nIdx, i ); + if( nIdx < nSttCntnt ) + ++nArrStt; + } + } + + // erst alle anzeigen, damit die Frames vorhanden sind. Mit deren + // Position wird das BodyAnchor ermittelt. + // Dafuer erst den ContentBereich, dann die Sonderbereiche!!! + for (sal_uInt16 n = nArrStt; n < aTmpArr.Count(); ++n) + { + pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode(); + ASSERT( pSectNd, "Wo ist mein SectionNode" ); + pSectNd->GetSection().SetCondHidden( sal_False ); + } + for (sal_uInt16 n = 0; n < nArrStt; ++n) + { + pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode(); + ASSERT( pSectNd, "Wo ist mein SectionNode" ); + pSectNd->GetSection().SetCondHidden( sal_False ); + } + + // so, erst jetzt alle sortiert in die Liste eintragen + for (sal_uInt16 n = 0; n < aTmpArr.Count(); ++n) + { + GetBodyNode( *rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode() ); + } + } + + String sTrue( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "sal_True" ))), + sFalse( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "sal_False" ))); + + sal_Bool bIsDBMgr = 0 != rDoc.GetNewDBMgr(); + sal_uInt16 nWhich, n; + const String* pFormel = 0; + const SfxPoolItem* pItem; + sal_uInt32 nMaxItems = rDoc.GetAttrPool().GetItemCount2( RES_TXTATR_FIELD ); + for( n = 0; n < nMaxItems; ++n ) + { + if( 0 == (pItem = rDoc.GetAttrPool().GetItem2( RES_TXTATR_FIELD, n )) ) + continue; + + const SwFmtFld* pFmtFld = (SwFmtFld*)pItem; + const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); + if( !pTxtFld || !pTxtFld->GetTxtNode().GetNodes().IsDocNodes() ) + continue; + + const SwField* pFld = pFmtFld->GetFld(); + switch( nWhich = pFld->GetTyp()->Which() ) + { + case RES_DBSETNUMBERFLD: + case RES_GETEXPFLD: + if( GETFLD_ALL == eGetMode ) + pFormel = &sTrue; + break; + + case RES_DBFLD: + if( GETFLD_EXPAND & eGetMode ) + pFormel = &sTrue; + break; + + case RES_SETEXPFLD: + /// OD 04.10.2002 #102894# + /// fields of subtype <string> have also been add + /// for calculation (eGetMode == GETFLD_CALC). + /// Thus, add fields of subtype <string> in all modes + /// (eGetMode == GETFLD_EXPAND||GETFLD_CALC||GETFLD_ALL) + /// and fields of other subtypes only in the modes + /// (eGetMode == GETFLD_CALC||GETFLD_ALL) + /* "old" if construct - not deleted for history and code review + if( ( nsSwGetSetExpType::GSE_STRING & pFld->GetSubType() + ? GETFLD_EXPAND : GETFLD_CALC ) + & eGetMode ) + */ + if ( !(eGetMode == GETFLD_EXPAND) || + (nsSwGetSetExpType::GSE_STRING & pFld->GetSubType()) ) + { + pFormel = &sTrue; + } + break; + + case RES_HIDDENPARAFLD: + if( GETFLD_ALL == eGetMode ) + { + pFormel = &pFld->GetPar1(); + if( !pFormel->Len() || pFormel->Equals( sFalse )) + ((SwHiddenParaField*)pFld)->SetHidden( sal_False ); + else if( pFormel->Equals( sTrue )) + ((SwHiddenParaField*)pFld)->SetHidden( sal_True ); + else + break; + + pFormel = 0; + // Formatierung anstossen + ((SwFmtFld*)pFmtFld)->Modify( 0, 0 ); + } + break; + + case RES_HIDDENTXTFLD: + if( GETFLD_ALL == eGetMode ) + { + pFormel = &pFld->GetPar1(); + if( !pFormel->Len() || pFormel->Equals( sFalse )) + ((SwHiddenTxtField*)pFld)->SetValue( sal_True ); + else if( pFormel->Equals( sTrue )) + ((SwHiddenTxtField*)pFld)->SetValue( sal_False ); + else + break; + + pFormel = 0; + + // Feld Evaluieren + ((SwHiddenTxtField*)pFld)->Evaluate(&rDoc); + // Formatierung anstossen + ((SwFmtFld*)pFmtFld)->Modify( 0, 0 ); + } + break; + + case RES_DBNUMSETFLD: + { + SwDBData aDBData(((SwDBNumSetField*)pFld)->GetDBData(&rDoc)); + + if ( + (bIsDBMgr && rDoc.GetNewDBMgr()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) && + (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && ((SwDBNumSetField*)pFld)->IsCondValid())) + ) + { + pFormel = &pFld->GetPar1(); + } + } + break; + case RES_DBNEXTSETFLD: + { + SwDBData aDBData(((SwDBNextSetField*)pFld)->GetDBData(&rDoc)); + + if ( + (bIsDBMgr && rDoc.GetNewDBMgr()->OpenDataSource(aDBData.sDataSource, aDBData.sCommand)) && + (GETFLD_ALL == eGetMode || (GETFLD_CALC & eGetMode && ((SwDBNextSetField*)pFld)->IsCondValid())) + ) + { + pFormel = &pFld->GetPar1(); + } + } + break; + } + + if( pFormel && pFormel->Len() ) + { + GetBodyNode( *pTxtFld, nWhich ); + pFormel = 0; + } + } + nFldLstGetMode = static_cast<sal_uInt8>( eGetMode ); + nNodes = rDoc.GetNodes().Count(); + +#ifdef JP_DEBUG + { + SvFileStream sOut( "f:\\x.x", STREAM_STD_WRITE ); + sOut.Seek( STREAM_SEEK_TO_END ); + sOut << "------------------" << endl; + const _SetGetExpFldPtr* pSortLst = pFldSortLst->GetData(); + for( sal_uInt16 n = pFldSortLst->Count(); n; --n, ++pSortLst ) + { + String sStr( (*pSortLst)->GetNode() ); + sStr += "\t, "; + sStr += (*pSortLst)->GetCntnt(); + sStr += "\tNode: "; + sStr += (*pSortLst)->GetFld()->GetTxtNode().StartOfSectionIndex(); + sStr += "\tPos: "; + sStr += *(*pSortLst)->GetFld()->GetStart(); + sStr += "\tType: "; + sStr += (*pSortLst)->GetFld()->GetFld().GetFld()->GetTyp()->Which(); + + sOut << sStr.GetStr() << endl; + } + } +#endif + // JP_DEBUG +} + +/*-------------------------------------------------------------------- + Beschreibung: + --------------------------------------------------------------------*/ + +void SwDocUpdtFld::GetBodyNode( const SwTxtFld& rTFld, sal_uInt16 nFldWhich ) +{ + const SwTxtNode& rTxtNd = rTFld.GetTxtNode(); + const SwDoc& rDoc = *rTxtNd.GetDoc(); + + // immer den ersten !! (in Tab-Headline, Kopf-/Fuss ) + Point aPt; + const SwCntntFrm* pFrm = rTxtNd.GetFrm( &aPt, 0, sal_False ); + + _SetGetExpFld* pNew = NULL; + sal_Bool bIsInBody = sal_False; + + if( !pFrm || pFrm->IsInDocBody() ) + { + // einen Index fuers bestimmen vom TextNode anlegen + SwNodeIndex aIdx( rTxtNd ); + bIsInBody = rDoc.GetNodes().GetEndOfExtras().GetIndex() < aIdx.GetIndex(); + + // #104291# dvo: We don't want to update fields in redlines, or those + // in frames whose anchor is in redline. However, we do want to update + // fields in hidden sections. So: In order to be updated, a field 1) + // must have a frame, or 2) it must be in the document body. + if( (pFrm != NULL) || bIsInBody ) + pNew = new _SetGetExpFld( aIdx, &rTFld ); + } + else + { + // einen Index fuers bestimmen vom TextNode anlegen + SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() ); +#ifdef DBG_UTIL + ASSERT( GetBodyTxtNode( rDoc, aPos, *pFrm ), "wo steht das Feld" ); +#else + GetBodyTxtNode( rDoc, aPos, *pFrm ); +#endif + pNew = new _SetGetExpFld( aPos.nNode, &rTFld, &aPos.nContent ); + } + + // bei GetExp.-/DB.-Felder immer das BodyTxtFlag setzen + if( RES_GETEXPFLD == nFldWhich ) + { + SwGetExpField* pGetFld = (SwGetExpField*)rTFld.GetFld().GetFld(); + pGetFld->ChgBodyTxtFlag( bIsInBody ); + } + else if( RES_DBFLD == nFldWhich ) + { + SwDBField* pDBFld = (SwDBField*)rTFld.GetFld().GetFld(); + pDBFld->ChgBodyTxtFlag( bIsInBody ); + } + + if( pNew != NULL ) + if( !pFldSortLst->Insert( pNew )) + delete pNew; +} + +void SwDocUpdtFld::GetBodyNode( const SwSectionNode& rSectNd ) +{ + const SwDoc& rDoc = *rSectNd.GetDoc(); + _SetGetExpFld* pNew = 0; + + if( rSectNd.GetIndex() < rDoc.GetNodes().GetEndOfExtras().GetIndex() ) + { + do { // middle check loop + + // dann muessen wir uns mal den Anker besorgen! + // einen Index fuers bestimmen vom TextNode anlegen + SwPosition aPos( rSectNd ); + SwCntntNode* pCNd = rDoc.GetNodes().GoNext( &aPos.nNode ); // zum naechsten ContentNode + + if( !pCNd || !pCNd->IsTxtNode() ) + break; + + // immer den ersten !! (in Tab-Headline, Kopf-/Fuss ) + Point aPt; + const SwCntntFrm* pFrm = pCNd->GetFrm( &aPt, 0, sal_False ); + if( !pFrm ) + break; + +#ifdef DBG_UTIL + ASSERT( GetBodyTxtNode( rDoc, aPos, *pFrm ), "wo steht das Feld" ); +#else + GetBodyTxtNode( rDoc, aPos, *pFrm ); +#endif + pNew = new _SetGetExpFld( rSectNd, &aPos ); + + } while( sal_False ); + } + + if( !pNew ) + pNew = new _SetGetExpFld( rSectNd ); + + if( !pFldSortLst->Insert( pNew )) + delete pNew; +} + +void SwDocUpdtFld::InsertFldType( const SwFieldType& rType ) +{ + String sFldName; + switch( rType.Which() ) + { + case RES_USERFLD : + sFldName = ((SwUserFieldType&)rType).GetName(); + break; + case RES_SETEXPFLD: + sFldName = ((SwSetExpFieldType&)rType).GetName(); + break; + default: + ASSERT( !this, "kein gueltiger FeldTyp" ); + } + + if( sFldName.Len() ) + { + SetFieldsDirty( sal_True ); + // suchen und aus der HashTabelle entfernen + GetAppCharClass().toLower( sFldName ); + sal_uInt16 n; + + SwHash* pFnd = Find( sFldName, GetFldTypeTable(), TBLSZ, &n ); + + if( !pFnd ) + { + SwCalcFldType* pNew = new SwCalcFldType( sFldName, &rType ); + pNew->pNext = aFldTypeTable[ n ]; + aFldTypeTable[ n ] = pNew; + } + } +} + +void SwDocUpdtFld::RemoveFldType( const SwFieldType& rType ) +{ + String sFldName; + switch( rType.Which() ) + { + case RES_USERFLD : + sFldName = ((SwUserFieldType&)rType).GetName(); + break; + case RES_SETEXPFLD: + sFldName = ((SwSetExpFieldType&)rType).GetName(); + break; + } + + if( sFldName.Len() ) + { + SetFieldsDirty( sal_True ); + // suchen und aus der HashTabelle entfernen + GetAppCharClass().toLower( sFldName ); + sal_uInt16 n; + + SwHash* pFnd = Find( sFldName, GetFldTypeTable(), TBLSZ, &n ); + if( pFnd ) + { + if( aFldTypeTable[ n ] == pFnd ) + aFldTypeTable[ n ] = (SwCalcFldType*)pFnd->pNext; + else + { + SwHash* pPrev = aFldTypeTable[ n ]; + while( pPrev->pNext != pFnd ) + pPrev = pPrev->pNext; + pPrev->pNext = pFnd->pNext; + } + pFnd->pNext = 0; + delete pFnd; + } + } +} + +SwDocUpdtFld::SwDocUpdtFld() + : pFldSortLst(0), nFldUpdtPos(LONG_MAX), nFldLstGetMode(0) +{ + bInUpdateFlds = bFldsDirty = sal_False; + memset( aFldTypeTable, 0, sizeof( aFldTypeTable ) ); +} + +SwDocUpdtFld::~SwDocUpdtFld() +{ + delete pFldSortLst; + + for( sal_uInt16 n = 0; n < TBLSZ; ++n ) + delete aFldTypeTable[n]; +} + +// #111840# +bool SwDoc::UpdateFld(SwTxtFld * pDstTxtFld, SwField & rSrcFld, + SwMsgPoolItem * pMsgHnt, + bool bUpdateFlds) +{ + ASSERT(pDstTxtFld, "no field to update!"); + + sal_Bool bTblSelBreak = sal_False; + + SwFmtFld * pDstFmtFld = (SwFmtFld*)&pDstTxtFld->GetFld(); + SwField * pDstFld = pDstFmtFld->GetFld(); + sal_uInt16 nFldWhich = rSrcFld.GetTyp()->Which(); + SwNodeIndex aTblNdIdx(pDstTxtFld->GetTxtNode()); + + if (pDstFld->GetTyp()->Which() == + rSrcFld.GetTyp()->Which()) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwPosition aPosition( pDstTxtFld->GetTxtNode() ); + aPosition.nContent = *pDstTxtFld->GetStart(); + + SwUndo *const pUndo( new SwUndoFieldFromDoc( + aPosition, *pDstFld, rSrcFld, pMsgHnt, bUpdateFlds) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + // Das gefundene Feld wird angepasst ... + //pDstFld->ChangeFormat( rSrcFld.GetFormat() ); + //pDstFld->SetLanguage( rSrcFld.GetLanguage() ); + + SwField * pNewFld = rSrcFld.CopyField(); + pDstFmtFld->SetFld(pNewFld); + + switch( nFldWhich ) + { + case RES_SETEXPFLD: + case RES_GETEXPFLD: + case RES_HIDDENTXTFLD: + case RES_HIDDENPARAFLD: + UpdateExpFlds( pDstTxtFld, true ); + break; + + case RES_TABLEFLD: + { + const SwTableNode* pTblNd = + IsIdxInTbl(aTblNdIdx); + if( pTblNd ) + { + SwTableFmlUpdate aTblUpdate( &pTblNd-> + GetTable() ); + if (bUpdateFlds) + UpdateTblFlds( &aTblUpdate ); + else + pNewFld->GetTyp()->Modify(0, &aTblUpdate); + + if (! bUpdateFlds) + bTblSelBreak = sal_True; + } + } + break; + + case RES_MACROFLD: + if( bUpdateFlds && pDstTxtFld->GetpTxtNode() ) + (pDstTxtFld->GetpTxtNode())-> + Modify( 0, pDstFmtFld ); + break; + + case RES_DBNAMEFLD: + case RES_DBNEXTSETFLD: + case RES_DBNUMSETFLD: + case RES_DBSETNUMBERFLD: + ChgDBData(((SwDBNameInfField*) pNewFld)->GetRealDBData()); + pNewFld->GetTyp()->UpdateFlds(); + + break; + + case RES_DBFLD: + { + // JP 10.02.96: ChgValue aufrufen, damit + //die Format- aenderung den ContentString + //richtig setzt + SwDBField* pDBFld = (SwDBField*)pNewFld; + if (pDBFld->IsInitialized()) + pDBFld->ChgValue( pDBFld->GetValue(), sal_True ); + + pDBFld->ClearInitialized(); + pDBFld->InitContent(); + } + // kein break; + + default: + pDstFmtFld->Modify( 0, pMsgHnt ); + } + + // Die Felder die wir berechnen koennen werden hier expli. + // zum Update angestossen. + if( nFldWhich == RES_USERFLD ) + UpdateUsrFlds(); + } + + return bTblSelBreak; +} + +bool SwDoc::PutValueToField(const SwPosition & rPos, + const Any& rVal, sal_uInt16 nWhich) +{ + Any aOldVal; + SwField * pField = GetField(rPos); + + + if (GetIDocumentUndoRedo().DoesUndo() && + pField->QueryValue(aOldVal, nWhich)) + { + SwUndo *const pUndo(new SwUndoFieldFromAPI(rPos, aOldVal, rVal, nWhich)); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + return pField->PutValue(rVal, nWhich); +} diff --git a/sw/source/core/doc/docfly.cxx b/sw/source/core/doc/docfly.cxx new file mode 100644 index 000000000000..fb0ccdd97a80 --- /dev/null +++ b/sw/source/core/doc/docfly.cxx @@ -0,0 +1,1063 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <svl/itemiter.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdpage.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdocapt.hxx> +#include <svx/svdmark.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <dcontact.hxx> + +#include <ndgrf.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <ndindex.hxx> +#include <docary.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <txtflcnt.hxx> +#include <fmtflcnt.hxx> +#include <txtfrm.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <flyfrms.hxx> +#include <frmtool.hxx> +#include <frmfmt.hxx> +#include <ndtxt.hxx> +#include <pam.hxx> +#include <tblsel.hxx> +#include <swundo.hxx> +#include <swtable.hxx> +#include <crstate.hxx> +#include <UndoCore.hxx> +#include <UndoAttribute.hxx> +#include <fmtcnct.hxx> +#include <dflyobj.hxx> + +// --> OD 2009-07-20 #i73249# +#include <undoflystrattr.hxx> +// <-- + +extern sal_uInt16 GetHtmlMode( const SwDocShell* ); + + +using namespace ::com::sun::star; + +/*-----------------17.02.98 08:35------------------- + +--------------------------------------------------*/ +sal_uInt16 SwDoc::GetFlyCount( FlyCntType eType ) const +{ + const SwSpzFrmFmts& rFmts = *GetSpzFrmFmts(); + sal_uInt16 nSize = rFmts.Count(); + sal_uInt16 nCount = 0; + const SwNodeIndex* pIdx; + for ( sal_uInt16 i = 0; i < nSize; i++) + { + const SwFrmFmt* pFlyFmt = rFmts[ i ]; + if( RES_FLYFRMFMT == pFlyFmt->Which() + && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() ) + && pIdx->GetNodes().IsDocNodes() + ) + { + const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ]; + + switch( eType ) + { + case FLYCNTTYPE_FRM: + if(!pNd->IsNoTxtNode()) + nCount++; + break; + + case FLYCNTTYPE_GRF: + if( pNd->IsGrfNode() ) + nCount++; + break; + + case FLYCNTTYPE_OLE: + if(pNd->IsOLENode()) + nCount++; + break; + + default: + nCount++; + } + } + } + return nCount; +} + +/*-----------------17.02.98 08:35------------------- + +--------------------------------------------------*/ +// If you change this, also update SwXFrameEnumeration in unocoll. +SwFrmFmt* SwDoc::GetFlyNum( sal_uInt16 nIdx, FlyCntType eType ) +{ + SwSpzFrmFmts& rFmts = *GetSpzFrmFmts(); + SwFrmFmt* pRetFmt = 0; + sal_uInt16 nSize = rFmts.Count(); + const SwNodeIndex* pIdx; + sal_uInt16 nCount = 0; + for( sal_uInt16 i = 0; !pRetFmt && i < nSize; ++i ) + { + SwFrmFmt* pFlyFmt = rFmts[ i ]; + if( RES_FLYFRMFMT == pFlyFmt->Which() + && 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() ) + && pIdx->GetNodes().IsDocNodes() + ) + { + const SwNode* pNd = GetNodes()[ pIdx->GetIndex() + 1 ]; + switch( eType ) + { + case FLYCNTTYPE_FRM: + if( !pNd->IsNoTxtNode() && nIdx == nCount++) + pRetFmt = pFlyFmt; + break; + case FLYCNTTYPE_GRF: + if(pNd->IsGrfNode() && nIdx == nCount++ ) + pRetFmt = pFlyFmt; + break; + case FLYCNTTYPE_OLE: + if(pNd->IsOLENode() && nIdx == nCount++) + pRetFmt = pFlyFmt; + break; + default: + if(nIdx == nCount++) + pRetFmt = pFlyFmt; + } + } + } + return pRetFmt; +} + +/* */ + +/*********************************************************************** +#* Class : SwDoc +#* Methode : SetFlyFrmAnchor +#* Beschreibung: Das Ankerattribut des FlyFrms aendert sich. +#* Datum : MA 01. Feb. 94 +#* Update : JP 09.03.98 +#***********************************************************************/ + +Point lcl_FindAnchorLayPos( SwDoc& rDoc, const SwFmtAnchor& rAnch, + const SwFrmFmt* pFlyFmt ) +{ + Point aRet; + if( rDoc.GetRootFrm() ) + switch( rAnch.GetAnchorId() ) + { + case FLY_AS_CHAR: + if( pFlyFmt && rAnch.GetCntntAnchor() ) + { + const SwFrm* pOld = ((SwFlyFrmFmt*)pFlyFmt)->GetFrm( &aRet, sal_False ); + if( pOld ) + aRet = pOld->Frm().Pos(); + } + break; + + case FLY_AT_PARA: + case FLY_AT_CHAR: // LAYER_IMPL + if( rAnch.GetCntntAnchor() ) + { + const SwPosition *pPos = rAnch.GetCntntAnchor(); + const SwCntntNode* pNd = pPos->nNode.GetNode().GetCntntNode(); + const SwFrm* pOld = pNd ? pNd->GetFrm( &aRet, 0, sal_False ) : 0; + if( pOld ) + aRet = pOld->Frm().Pos(); + } + break; + + case FLY_AT_FLY: // LAYER_IMPL + if( rAnch.GetCntntAnchor() ) + { + const SwFlyFrmFmt* pFmt = (SwFlyFrmFmt*)rAnch.GetCntntAnchor()-> + nNode.GetNode().GetFlyFmt(); + const SwFrm* pOld = pFmt ? pFmt->GetFrm( &aRet, sal_False ) : 0; + if( pOld ) + aRet = pOld->Frm().Pos(); + } + break; + + case FLY_AT_PAGE: + { + sal_uInt16 nPgNum = rAnch.GetPageNum(); + const SwPageFrm *pPage = (SwPageFrm*)rDoc.GetRootFrm()->Lower(); + for( sal_uInt16 i = 1; (i <= nPgNum) && pPage; ++i, + pPage = (const SwPageFrm*)pPage->GetNext() ) + if( i == nPgNum ) + { + aRet = pPage->Frm().Pos(); + break; + } + } + break; + default: + break; + } + return aRet; +} + +#define MAKEFRMS 0 +#define IGNOREANCHOR 1 +#define DONTMAKEFRMS 2 + +sal_Int8 SwDoc::SetFlyFrmAnchor( SwFrmFmt& rFmt, SfxItemSet& rSet, sal_Bool bNewFrms ) +{ + //Ankerwechsel sind fast immer in alle 'Richtungen' erlaubt. + //Ausnahme: Absatz- bzw. Zeichengebundene Rahmen duerfen wenn sie in + //Kopf-/Fusszeilen stehen nicht Seitengebunden werden. + const SwFmtAnchor &rOldAnch = rFmt.GetAnchor(); + const RndStdIds nOld = rOldAnch.GetAnchorId(); + + SwFmtAnchor aNewAnch( (SwFmtAnchor&)rSet.Get( RES_ANCHOR ) ); + RndStdIds nNew = aNewAnch.GetAnchorId(); + + // ist der neue ein gueltiger Anker? + if( !aNewAnch.GetCntntAnchor() && (FLY_AT_FLY == nNew || + (FLY_AT_PARA == nNew) || (FLY_AS_CHAR == nNew) || + (FLY_AT_CHAR == nNew) )) + { + return IGNOREANCHOR; + } + + if( nOld == nNew ) + return DONTMAKEFRMS; + + + Point aOldAnchorPos( ::lcl_FindAnchorLayPos( *this, rOldAnch, &rFmt )); + Point aNewAnchorPos( ::lcl_FindAnchorLayPos( *this, aNewAnch, 0 )); + + //Die alten Frms vernichten. Dabei werden die Views implizit gehidet und + //doppeltes hiden waere so eine art Show! + rFmt.DelFrms(); + + if ( FLY_AS_CHAR == nOld ) + { + //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet + //werden. Leider reisst dies neben den Frms auch noch das Format mit + //in sein Grab. Um dass zu unterbinden loesen wir vorher die + //Verbindung zwischen Attribut und Format. + const SwPosition *pPos = rOldAnch.GetCntntAnchor(); + SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT ); + ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == &rFmt, + "Wrong TxtFlyCnt-Hint." ); + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt(); + + //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet + //werden. + pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIdx, nIdx ); + } + + //Endlich kann das Attribut gesetzt werden. Es muss das erste Attribut + //sein; Undo depends on it! + rFmt.SetFmtAttr( aNewAnch ); + + //Positionskorrekturen + const SfxPoolItem* pItem; + switch( nNew ) + { + case FLY_AS_CHAR: + //Wenn keine Positionsattribute hereinkommen, dann muss dafuer + //gesorgt werden, das keine unerlaubte automatische Ausrichtung + //bleibt. + { + const SwPosition *pPos = aNewAnch.GetCntntAnchor(); + SwTxtNode *pNd = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pNd, "Crsr steht nicht auf TxtNode." ); + + SwFmtFlyCnt aFmt( static_cast<SwFlyFrmFmt*>(&rFmt) ); + pNd->InsertItem( aFmt, pPos->nContent.GetIndex(), 0 ); + } + + if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem )) + { + SwFmtVertOrient aOldV( rFmt.GetVertOrient() ); + sal_Bool bSet = sal_True; + switch( aOldV.GetVertOrient() ) + { + case text::VertOrientation::LINE_TOP: aOldV.SetVertOrient( text::VertOrientation::TOP ); break; + case text::VertOrientation::LINE_CENTER: aOldV.SetVertOrient( text::VertOrientation::CENTER); break; + case text::VertOrientation::LINE_BOTTOM: aOldV.SetVertOrient( text::VertOrientation::BOTTOM); break; + case text::VertOrientation::NONE: aOldV.SetVertOrient( text::VertOrientation::CENTER); break; + default: + bSet = sal_False; + } + if( bSet ) + rSet.Put( aOldV ); + } + break; + + case FLY_AT_PARA: + case FLY_AT_CHAR: // LAYER_IMPL + case FLY_AT_FLY: // LAYER_IMPL + case FLY_AT_PAGE: + { + //Wenn keine Positionsattribute hereinschneien korrigieren wir + //die Position so, dass die Dokumentkoordinaten des Flys erhalten + //bleiben. + //Chg: Wenn sich in den Positionsattributen lediglich die + //Ausrichtung veraendert (text::RelOrientation::FRAME vs. text::RelOrientation::PRTAREA), dann wird die + //Position ebenfalls korrigiert. + if( SFX_ITEM_SET != rSet.GetItemState( RES_HORI_ORIENT, sal_False, &pItem )) + pItem = 0; + + SwFmtHoriOrient aOldH( rFmt.GetHoriOrient() ); + + if( text::HoriOrientation::NONE == aOldH.GetHoriOrient() && ( !pItem || + aOldH.GetPos() == ((SwFmtHoriOrient*)pItem)->GetPos() )) + { + SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldH.GetPos(); + nPos += aOldAnchorPos.X() - aNewAnchorPos.X(); + + if( pItem ) + { + SwFmtHoriOrient* pH = (SwFmtHoriOrient*)pItem; + aOldH.SetHoriOrient( pH->GetHoriOrient() ); + aOldH.SetRelationOrient( pH->GetRelationOrient() ); + } + aOldH.SetPos( nPos ); + rSet.Put( aOldH ); + } + + if( SFX_ITEM_SET != rSet.GetItemState( RES_VERT_ORIENT, sal_False, &pItem )) + pItem = 0; + SwFmtVertOrient aOldV( rFmt.GetVertOrient() ); + + // OD 2004-05-14 #i28922# - correction: compare <aOldV.GetVertOrient() + // with <text::VertOrientation::NONE> + if( text::VertOrientation::NONE == aOldV.GetVertOrient() && (!pItem || + aOldV.GetPos() == ((SwFmtVertOrient*)pItem)->GetPos() ) ) + { + SwTwips nPos = (FLY_AS_CHAR == nOld) ? 0 : aOldV.GetPos(); + nPos += aOldAnchorPos.Y() - aNewAnchorPos.Y(); + if( pItem ) + { + SwFmtVertOrient* pV = (SwFmtVertOrient*)pItem; + aOldV.SetVertOrient( pV->GetVertOrient() ); + aOldV.SetRelationOrient( pV->GetRelationOrient() ); + } + aOldV.SetPos( nPos ); + rSet.Put( aOldV ); + } + } + break; + default: + break; + } + + if( bNewFrms ) + rFmt.MakeFrms(); + + return MAKEFRMS; +} + +static bool +lcl_SetFlyFrmAttr(SwDoc & rDoc, + sal_Int8 (SwDoc::*pSetFlyFrmAnchor)(SwFrmFmt &, SfxItemSet &, sal_Bool), + SwFrmFmt & rFlyFmt, SfxItemSet & rSet) +{ + // #i32968# Inserting columns in the frame causes MakeFrmFmt to put two + // objects of type SwUndoFrmFmt on the undo stack. We don't want them. + ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + + //Ist das Ankerattribut dabei? Falls ja ueberlassen wir die Verarbeitung + //desselben einer Spezialmethode. Sie Returnt sal_True wenn der Fly neu + //erzeugt werden muss (z.B. weil ein Wechsel des FlyTyps vorliegt). + sal_Int8 const nMakeFrms = + (SFX_ITEM_SET == rSet.GetItemState( RES_ANCHOR, sal_False )) + ? (rDoc.*pSetFlyFrmAnchor)( rFlyFmt, rSet, sal_False ) + : DONTMAKEFRMS; + + const SfxPoolItem* pItem; + SfxItemIter aIter( rSet ); + SfxItemSet aTmpSet( rDoc.GetAttrPool(), aFrmFmtSetRange ); + sal_uInt16 nWhich = aIter.GetCurItem()->Which(); + do { + switch( nWhich ) + { + case RES_FILL_ORDER: + case RES_BREAK: + case RES_PAGEDESC: + case RES_CNTNT: + case RES_FOOTER: + OSL_ENSURE(false, ":-) unknown Attribute for Fly."); + // kein break; + case RES_CHAIN: + rSet.ClearItem( nWhich ); + break; + case RES_ANCHOR: + if( DONTMAKEFRMS != nMakeFrms ) + break; + + default: + if( !IsInvalidItem( aIter.GetCurItem() ) && ( SFX_ITEM_SET != + rFlyFmt.GetAttrSet().GetItemState( nWhich, sal_True, &pItem ) || + *pItem != *aIter.GetCurItem() )) + aTmpSet.Put( *aIter.GetCurItem() ); + break; + } + + if( aIter.IsAtEnd() ) + break; + + } while( 0 != ( nWhich = aIter.NextItem()->Which() ) ); + + if( aTmpSet.Count() ) + rFlyFmt.SetFmtAttr( aTmpSet ); + + if( MAKEFRMS == nMakeFrms ) + rFlyFmt.MakeFrms(); + + return aTmpSet.Count() || MAKEFRMS == nMakeFrms; +} + +sal_Bool SwDoc::SetFlyFrmAttr( SwFrmFmt& rFlyFmt, SfxItemSet& rSet ) +{ + if( !rSet.Count() ) + return sal_False; + + ::std::auto_ptr<SwUndoFmtAttrHelper> pSaveUndo; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it + pSaveUndo.reset( new SwUndoFmtAttrHelper( rFlyFmt ) ); + } + + bool const bRet = + lcl_SetFlyFrmAttr(*this, &SwDoc::SetFlyFrmAnchor, rFlyFmt, rSet); + + if ( pSaveUndo.get() ) + { + if ( pSaveUndo->GetUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( pSaveUndo->ReleaseUndo() ); + } + } + + SetModified(); + + return bRet; +} + +// --> OD 2009-07-20 #i73249# +void SwDoc::SetFlyFrmTitle( SwFlyFrmFmt& rFlyFrmFmt, + const String& sNewTitle ) +{ + if ( rFlyFrmFmt.GetObjTitle() == sNewTitle ) + { + return; + } + + ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, + UNDO_FLYFRMFMT_TITLE, + rFlyFrmFmt.GetObjTitle(), + sNewTitle ) ); + } + + rFlyFrmFmt.SetObjTitle( sNewTitle, true ); + + SetModified(); +} + +void SwDoc::SetFlyFrmDescription( SwFlyFrmFmt& rFlyFrmFmt, + const String& sNewDescription ) +{ + if ( rFlyFrmFmt.GetObjDescription() == sNewDescription ) + { + return; + } + + ::sw::DrawUndoGuard const drawUndoGuard(GetIDocumentUndoRedo()); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoFlyStrAttr( rFlyFrmFmt, + UNDO_FLYFRMFMT_DESCRIPTION, + rFlyFrmFmt.GetObjDescription(), + sNewDescription ) ); + } + + rFlyFrmFmt.SetObjDescription( sNewDescription, true ); + + SetModified(); +} +// <-- + +/*************************************************************************** + * Methode : sal_Bool SwDoc::SetFrmFmtToFly( SwFlyFrm&, SwFrmFmt& ) + * Beschreibung: + * Erstellt : OK 14.04.94 15:40 + * Aenderung : JP 23.04.98 + ***************************************************************************/ + +sal_Bool SwDoc::SetFrmFmtToFly( SwFrmFmt& rFmt, SwFrmFmt& rNewFmt, + SfxItemSet* pSet, sal_Bool bKeepOrient ) +{ + sal_Bool bChgAnchor = sal_False, bFrmSz = sal_False; + + const SwFmtFrmSize aFrmSz( rFmt.GetFrmSize() ); + const SwFmtVertOrient aVert( rFmt.GetVertOrient() ); + const SwFmtHoriOrient aHori( rFmt.GetHoriOrient() ); + + SwUndoSetFlyFmt* pUndo = 0; + bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); + if (bUndo) + { + pUndo = new SwUndoSetFlyFmt( rFmt, rNewFmt ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + // #i32968# Inserting columns in the section causes MakeFrmFmt to put + // 2 objects of type SwUndoFrmFmt on the undo stack. We don't want them. + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + //Erstmal die Spalten setzen, sonst gibts nix als Aerger mit dem + //Set/Reset/Abgleich usw. + const SfxPoolItem* pItem; + if( SFX_ITEM_SET != rNewFmt.GetAttrSet().GetItemState( RES_COL )) + rFmt.ResetFmtAttr( RES_COL ); + + if( rFmt.DerivedFrom() != &rNewFmt ) + { + rFmt.SetDerivedFrom( &rNewFmt ); + + // 1. wenn nicht automatisch -> ignorieren, sonst -> wech + // 2. wech damit, MB! + if( SFX_ITEM_SET == rNewFmt.GetAttrSet().GetItemState( RES_FRM_SIZE, sal_False )) + { + rFmt.ResetFmtAttr( RES_FRM_SIZE ); + bFrmSz = sal_True; + } + + const SfxItemSet* pAsk = pSet; + if( !pAsk ) pAsk = &rNewFmt.GetAttrSet(); + if( SFX_ITEM_SET == pAsk->GetItemState( RES_ANCHOR, sal_False, &pItem ) + && ((SwFmtAnchor*)pItem)->GetAnchorId() != + rFmt.GetAnchor().GetAnchorId() ) + { + if( pSet ) + bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, *pSet, sal_False ); + else + { + //JP 23.04.98: muss den FlyFmt-Range haben, denn im SetFlyFrmAnchor + // werden Attribute in diesen gesetzt! + SfxItemSet aFlySet( *rNewFmt.GetAttrSet().GetPool(), + rNewFmt.GetAttrSet().GetRanges() ); + aFlySet.Put( *pItem ); + bChgAnchor = MAKEFRMS == SetFlyFrmAnchor( rFmt, aFlySet, sal_False); + } + } + } + + //Hori und Vert nur dann resetten, wenn in der Vorlage eine + //automatische Ausrichtung eingestellt ist, anderfalls den alten Wert + //wieder hineinstopfen. + //JP 09.06.98: beim Update der RahmenVorlage sollte der Fly NICHT + // seine Orientierng verlieren (diese wird nicht geupdatet!) + //OS: #96584# text::HoriOrientation::NONE and text::VertOrientation::NONE are allowed now + if (!bKeepOrient) + { + rFmt.ResetFmtAttr(RES_VERT_ORIENT); + rFmt.ResetFmtAttr(RES_HORI_ORIENT); + } + + rFmt.ResetFmtAttr( RES_PRINT, RES_SURROUND ); + rFmt.ResetFmtAttr( RES_LR_SPACE, RES_UL_SPACE ); + rFmt.ResetFmtAttr( RES_BACKGROUND, RES_COL ); + rFmt.ResetFmtAttr( RES_URL, RES_EDIT_IN_READONLY ); + + if( !bFrmSz ) + rFmt.SetFmtAttr( aFrmSz ); + + if( bChgAnchor ) + rFmt.MakeFrms(); + + if( pUndo ) + rFmt.Remove( pUndo ); + + SetModified(); + + return bChgAnchor; +} + +void SwDoc::GetGrfNms( const SwFlyFrmFmt& rFmt, String* pGrfName, + String* pFltName ) const +{ + SwNodeIndex aIdx( *rFmt.GetCntnt().GetCntntIdx(), 1 ); + const SwGrfNode* pGrfNd = aIdx.GetNode().GetGrfNode(); + if( pGrfNd && pGrfNd->IsLinkedFile() ) + pGrfNd->GetFileFilterNms( pGrfName, pFltName ); +} + +/************************************************************************* +|* +|* SwDoc::ChgAnchor() +|* +|* Ersterstellung MA 10. Jan. 95 +|* Letzte Aenderung JP 08.07.98 +|* +*************************************************************************/ + +sal_Bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList, + RndStdIds _eAnchorType, + const sal_Bool _bSameOnly, + const sal_Bool _bPosCorr ) +{ + ASSERT( GetRootFrm(), "Ohne Layout geht gar nichts" ); + + if ( !_rMrkList.GetMarkCount() || + _rMrkList.GetMark( 0 )->GetMarkedSdrObj()->GetUpGroup() ) + { + return false; + } + + GetIDocumentUndoRedo().StartUndo( UNDO_INSATTR, NULL ); + + sal_Bool bUnmark = sal_False; + for ( sal_uInt16 i = 0; i < _rMrkList.GetMarkCount(); ++i ) + { + SdrObject* pObj = _rMrkList.GetMark( i )->GetMarkedSdrObj(); + if ( !pObj->ISA(SwVirtFlyDrawObj) ) + { + SwDrawContact* pContact = static_cast<SwDrawContact*>(GetUserCall(pObj)); + + // OD 27.06.2003 #108784# - consider, that drawing object has + // no user call. E.g.: a 'virtual' drawing object is disconnected by + // the anchor type change of the 'master' drawing object. + // Continue with next selected object and assert, if this isn't excepted. + if ( !pContact ) + { +#ifdef DBG_UTIL + bool bNoUserCallExcepted = + pObj->ISA(SwDrawVirtObj) && + !static_cast<SwDrawVirtObj*>(pObj)->IsConnected(); + ASSERT( bNoUserCallExcepted, "SwDoc::ChgAnchor(..) - no contact at selected drawing object" ); +#endif + continue; + } + + // OD 2004-03-29 #i26791# + const SwFrm* pOldAnchorFrm = pContact->GetAnchorFrm( pObj ); + const SwFrm* pNewAnchorFrm = pOldAnchorFrm; + + // --> OD 2006-03-01 #i54336# + // Instead of only keeping the index position for an as-character + // anchored object the complete <SwPosition> is kept, because the + // anchor index position could be moved, if the object again is + // anchored as character. +// xub_StrLen nIndx = STRING_NOTFOUND; + const SwPosition* pOldAsCharAnchorPos( 0L ); + const RndStdIds eOldAnchorType = pContact->GetAnchorId(); + if ( !_bSameOnly && eOldAnchorType == FLY_AS_CHAR ) + { + pOldAsCharAnchorPos = new SwPosition( pContact->GetCntntAnchor() ); + } + // <-- + + if ( _bSameOnly ) + _eAnchorType = eOldAnchorType; + + SwFmtAnchor aNewAnch( _eAnchorType ); + Rectangle aObjRect( pContact->GetAnchoredObj( pObj )->GetObjRect().SVRect() ); + const Point aPt( aObjRect.TopLeft() ); + + switch ( _eAnchorType ) + { + case FLY_AT_PARA: + case FLY_AT_CHAR: + { + const Point aNewPoint = pOldAnchorFrm && + ( pOldAnchorFrm->IsVertical() || + pOldAnchorFrm->IsRightToLeft() ) + ? aObjRect.TopRight() + : aPt; + + // OD 18.06.2003 #108784# - allow drawing objects in header/footer + pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aNewPoint, false ); + if ( pNewAnchorFrm->IsTxtFrm() && ((SwTxtFrm*)pNewAnchorFrm)->IsFollow() ) + { + pNewAnchorFrm = ((SwTxtFrm*)pNewAnchorFrm)->FindMaster(); + } + if ( pNewAnchorFrm->IsProtected() ) + { + pNewAnchorFrm = 0; + } + else + { + SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); + aNewAnch.SetType( _eAnchorType ); + aNewAnch.SetAnchor( &aPos ); + } + } + break; + + case FLY_AT_FLY: // LAYER_IMPL + { + //Ausgehend von der linken oberen Ecke des Fly den + //dichtesten SwFlyFrm suchen. + SwFrm *pTxtFrm; + { + SwCrsrMoveState aState( MV_SETONLYTEXT ); + SwPosition aPos( GetNodes() ); + Point aPoint( aPt ); + aPoint.X() -= 1; + GetRootFrm()->GetCrsrOfst( &aPos, aPoint, &aState ); + // OD 20.06.2003 #108784# - consider that drawing objects + // can be in header/footer. Thus, <GetFrm()> by left-top-corner + pTxtFrm = aPos.nNode.GetNode(). + GetCntntNode()->GetFrm( &aPt, 0, sal_False ); + } + const SwFrm *pTmp = ::FindAnchor( pTxtFrm, aPt ); + pNewAnchorFrm = pTmp->FindFlyFrm(); + if( pNewAnchorFrm && !pNewAnchorFrm->IsProtected() ) + { + const SwFrmFmt *pTmpFmt = ((SwFlyFrm*)pNewAnchorFrm)->GetFmt(); + const SwFmtCntnt& rCntnt = pTmpFmt->GetCntnt(); + SwPosition aPos( *rCntnt.GetCntntIdx() ); + aNewAnch.SetAnchor( &aPos ); + break; + } + + aNewAnch.SetType( FLY_AT_PAGE ); + // no break + } + case FLY_AT_PAGE: + { + pNewAnchorFrm = GetRootFrm()->Lower(); + while ( pNewAnchorFrm && !pNewAnchorFrm->Frm().IsInside( aPt ) ) + pNewAnchorFrm = pNewAnchorFrm->GetNext(); + if ( !pNewAnchorFrm ) + continue; + + aNewAnch.SetPageNum( ((SwPageFrm*)pNewAnchorFrm)->GetPhyPageNum()); + } + break; + case FLY_AS_CHAR: + if( _bSameOnly ) // Positions/Groessenaenderung + { + if( !pOldAnchorFrm ) + { + pContact->ConnectToLayout(); + pOldAnchorFrm = pContact->GetAnchorFrm(); + } + ((SwTxtFrm*)pOldAnchorFrm)->Prepare(); + } + else // Ankerwechsel + { + // OD 18.06.2003 #108784# - allow drawing objects in header/footer + pNewAnchorFrm = ::FindAnchor( pOldAnchorFrm, aPt, false ); + if( pNewAnchorFrm->IsProtected() ) + { + pNewAnchorFrm = 0; + break; + } + + bUnmark = ( 0 != i ); + Point aPoint( aPt ); + aPoint.X() -= 1; // nicht im DrawObj landen!! + aNewAnch.SetType( FLY_AS_CHAR ); + SwPosition aPos( *((SwCntntFrm*)pNewAnchorFrm)->GetNode() ); + if ( pNewAnchorFrm->Frm().IsInside( aPoint ) ) + { + // es muss ein TextNode gefunden werden, denn nur dort + // ist ein inhaltsgebundenes DrawObjekt zu verankern + SwCrsrMoveState aState( MV_SETONLYTEXT ); + GetRootFrm()->GetCrsrOfst( &aPos, aPoint, &aState ); + } + else + { + SwCntntNode &rCNd = (SwCntntNode&) + *((SwCntntFrm*)pNewAnchorFrm)->GetNode(); + if ( pNewAnchorFrm->Frm().Bottom() < aPt.Y() ) + rCNd.MakeStartIndex( &aPos.nContent ); + else + rCNd.MakeEndIndex( &aPos.nContent ); + } + aNewAnch.SetAnchor( &aPos ); + SetAttr( aNewAnch, *pContact->GetFmt() ); + // OD 2004-04-13 #i26791# - adjust vertical positioning to + // 'center to baseline' + SetAttr( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME ), *pContact->GetFmt() ); + SwTxtNode *pNd = aPos.nNode.GetNode().GetTxtNode(); + ASSERT( pNd, "Cursor not positioned at TxtNode." ); + + SwFmtFlyCnt aFmt( pContact->GetFmt() ); + pNd->InsertItem( aFmt, aPos.nContent.GetIndex(), 0 ); + } + break; + default: + ASSERT( !this, "unexpected AnchorId." ); + } + + if ( (FLY_AS_CHAR != _eAnchorType) && + pNewAnchorFrm && + ( !_bSameOnly || pNewAnchorFrm != pOldAnchorFrm ) ) + { + // OD 2004-04-06 #i26791# - Direct object positioning no longer + // needed. Apply of attributes (method call <SetAttr(..)>) takes + // care of the invalidation of the object position. + SetAttr( aNewAnch, *pContact->GetFmt() ); + if ( _bPosCorr ) + { + // --> OD 2004-08-24 #i33313# - consider not connected + // 'virtual' drawing objects + if ( pObj->ISA(SwDrawVirtObj) && + !static_cast<SwDrawVirtObj*>(pObj)->IsConnected() ) + { + SwRect aNewObjRect( aObjRect ); + static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( 0L )) + ->AdjustPositioningAttr( pNewAnchorFrm, + &aNewObjRect ); + + } + else + { + static_cast<SwAnchoredDrawObject*>(pContact->GetAnchoredObj( pObj )) + ->AdjustPositioningAttr( pNewAnchorFrm ); + } + } + } + + // --> OD 2006-03-01 #i54336# + if ( pNewAnchorFrm && pOldAsCharAnchorPos ) + { + //Bei InCntnt's wird es spannend: Das TxtAttribut muss vernichtet + //werden. Leider reisst dies neben den Frms auch noch das Format mit + //in sein Grab. Um dass zu unterbinden loesen wir vorher die + //Verbindung zwischen Attribut und Format. + const xub_StrLen nIndx( pOldAsCharAnchorPos->nContent.GetIndex() ); + SwTxtNode* pTxtNode( pOldAsCharAnchorPos->nNode.GetNode().GetTxtNode() ); + ASSERT( pTxtNode, "<SwDoc::ChgAnchor(..)> - missing previous anchor text node for as-character anchored object" ); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt( nIndx, RES_TXTATR_FLYCNT ); + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt(); + + //Die Verbindung ist geloest, jetzt muss noch das Attribut vernichtet + //werden. + pTxtNode->DeleteAttributes( RES_TXTATR_FLYCNT, nIndx, nIndx ); + delete pOldAsCharAnchorPos; + } + // <-- + } + } + + GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + SetModified(); + + return bUnmark; +} + + +/* -----------------23.07.98 13:56------------------- + * + * --------------------------------------------------*/ +int SwDoc::Chainable( const SwFrmFmt &rSource, const SwFrmFmt &rDest ) +{ + //Die Source darf noch keinen Follow haben. + const SwFmtChain &rOldChain = rSource.GetChain(); + if ( rOldChain.GetNext() ) + return SW_CHAIN_SOURCE_CHAINED; + + //Ziel darf natuerlich nicht gleich Source sein und es + //darf keine geschlossene Kette entstehen. + const SwFrmFmt *pFmt = &rDest; + do { + if( pFmt == &rSource ) + return SW_CHAIN_SELF; + pFmt = pFmt->GetChain().GetNext(); + } while ( pFmt ); + + //Auch eine Verkettung von Innen nach aussen oder von aussen + //nach innen ist nicht zulaessig. + if( rDest.IsLowerOf( rSource ) || rSource .IsLowerOf( rDest ) ) + return SW_CHAIN_SELF; + + //Das Ziel darf noch keinen Master haben. + const SwFmtChain &rChain = rDest.GetChain(); + if( rChain.GetPrev() ) + return SW_CHAIN_IS_IN_CHAIN; + + //Das Ziel muss leer sein. + const SwNodeIndex* pCntIdx = rDest.GetCntnt().GetCntntIdx(); + if( !pCntIdx ) + return SW_CHAIN_NOT_FOUND; + + SwNodeIndex aNxtIdx( *pCntIdx, 1 ); + const SwTxtNode* pTxtNd = aNxtIdx.GetNode().GetTxtNode(); + if( !pTxtNd ) + return SW_CHAIN_NOT_FOUND; + + const sal_uLong nFlySttNd = pCntIdx->GetIndex(); + if( 2 != ( pCntIdx->GetNode().EndOfSectionIndex() - nFlySttNd ) || + pTxtNd->GetTxt().Len() ) + return SW_CHAIN_NOT_EMPTY; + + sal_uInt16 nArrLen = GetSpzFrmFmts()->Count(); + for( sal_uInt16 n = 0; n < nArrLen; ++n ) + { + const SwFmtAnchor& rAnchor = (*GetSpzFrmFmts())[ n ]->GetAnchor(); + sal_uLong nTstSttNd; + // OD 11.12.2003 #i20622# - to-frame anchored objects are allowed. + if ( ((rAnchor.GetAnchorId() == FLY_AT_PARA) || + (rAnchor.GetAnchorId() == FLY_AT_CHAR)) && + 0 != rAnchor.GetCntntAnchor() && + nFlySttNd <= ( nTstSttNd = + rAnchor.GetCntntAnchor()->nNode.GetIndex() ) && + nTstSttNd < nFlySttNd + 2 ) + { + return SW_CHAIN_NOT_EMPTY; + } + } + + //Auf die richtige Area muessen wir auch noch einen Blick werfen. + //Beide Flys muessen im selben Bereich (Body, Head/Foot, Fly) sitzen + //Wenn die Source nicht der selektierte Rahmen ist, so reicht es + //Wenn ein passender gefunden wird (Der Wunsch kann z.B. von der API + //kommen). + + // both in the same fly, header, footer or on the page? + const SwFmtAnchor &rSrcAnchor = rSource.GetAnchor(), + &rDstAnchor = rDest.GetAnchor(); + sal_uLong nEndOfExtras = GetNodes().GetEndOfExtras().GetIndex(); + sal_Bool bAllowed = sal_False; + if ( FLY_AT_PAGE == rSrcAnchor.GetAnchorId() ) + { + if ( (FLY_AT_PAGE == rDstAnchor.GetAnchorId()) || + ( rDstAnchor.GetCntntAnchor() && + rDstAnchor.GetCntntAnchor()->nNode.GetIndex() > nEndOfExtras )) + bAllowed = sal_True; + } + else if( rSrcAnchor.GetCntntAnchor() && rDstAnchor.GetCntntAnchor() ) + { + const SwNodeIndex &rSrcIdx = rSrcAnchor.GetCntntAnchor()->nNode, + &rDstIdx = rDstAnchor.GetCntntAnchor()->nNode; + const SwStartNode* pSttNd = 0; + if( rSrcIdx == rDstIdx || + ( !pSttNd && + 0 != ( pSttNd = rSrcIdx.GetNode().FindFlyStartNode() ) && + pSttNd == rDstIdx.GetNode().FindFlyStartNode() ) || + ( !pSttNd && + 0 != ( pSttNd = rSrcIdx.GetNode().FindFooterStartNode() ) && + pSttNd == rDstIdx.GetNode().FindFooterStartNode() ) || + ( !pSttNd && + 0 != ( pSttNd = rSrcIdx.GetNode().FindHeaderStartNode() ) && + pSttNd == rDstIdx.GetNode().FindHeaderStartNode() ) || + ( !pSttNd && rDstIdx.GetIndex() > nEndOfExtras && + rSrcIdx.GetIndex() > nEndOfExtras )) + bAllowed = sal_True; + } + + return bAllowed ? SW_CHAIN_OK : SW_CHAIN_WRONG_AREA; +} +/* -----------------23.07.98 13:56------------------- + * + * --------------------------------------------------*/ +int SwDoc::Chain( SwFrmFmt &rSource, const SwFrmFmt &rDest ) +{ + int nErr = Chainable( rSource, rDest ); + if ( !nErr ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_CHAINE, NULL ); + + SwFlyFrmFmt& rDestFmt = (SwFlyFrmFmt&)rDest; + + //Follow an den Master haengen. + SwFmtChain aChain = rDestFmt.GetChain(); + aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); + SetAttr( aChain, rDestFmt ); + + SfxItemSet aSet( GetAttrPool(), RES_FRM_SIZE, RES_FRM_SIZE, + RES_CHAIN, RES_CHAIN, 0 ); + + //Follow an den Master haengen. + aChain.SetPrev( &(SwFlyFrmFmt&)rSource ); + SetAttr( aChain, rDestFmt ); + + //Master an den Follow haengen und dafuer sorgen, dass der Master + //eine fixierte Hoehe hat. + aChain = rSource.GetChain(); + aChain.SetNext( &rDestFmt ); + aSet.Put( aChain ); + + SwFmtFrmSize aSize( rSource.GetFrmSize() ); + if ( aSize.GetHeightSizeType() != ATT_FIX_SIZE ) + { + SwClientIter aIter( rSource ); + SwFlyFrm *pFly = (SwFlyFrm*)aIter.First( TYPE(SwFlyFrm) ); + if ( pFly ) + aSize.SetHeight( pFly->Frm().Height() ); + aSize.SetHeightSizeType( ATT_FIX_SIZE ); + aSet.Put( aSize ); + } + SetAttr( aSet, rSource ); + + GetIDocumentUndoRedo().EndUndo( UNDO_CHAINE, NULL ); + } + return nErr; +} +/* -----------------23.07.98 13:56------------------- + * + * --------------------------------------------------*/ +void SwDoc::Unchain( SwFrmFmt &rFmt ) +{ + SwFmtChain aChain( rFmt.GetChain() ); + if ( aChain.GetNext() ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_UNCHAIN, NULL ); + SwFrmFmt *pFollow = aChain.GetNext(); + aChain.SetNext( 0 ); + SetAttr( aChain, rFmt ); + aChain = pFollow->GetChain(); + aChain.SetPrev( 0 ); + SetAttr( aChain, *pFollow ); + GetIDocumentUndoRedo().EndUndo( UNDO_UNCHAIN, NULL ); + } +} + + + diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx new file mode 100644 index 000000000000..1154fbf61d88 --- /dev/null +++ b/sw/source/core/doc/docfmt.cxx @@ -0,0 +1,2688 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#define _ZFORLIST_DECLARE_TABLE +#define _SVSTDARR_USHORTSSORT +#define _SVSTDARR_USHORTS +#include <hintids.hxx> +#include <rtl/logfile.hxx> +#include <svl/itemiter.hxx> +#include <sfx2/app.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/brkitem.hxx> +#include <svl/whiter.hxx> +#ifndef _ZFORLIST_HXX //autogen +#define _ZFORLIST_DECLARE_TABLE +#include <svl/zforlist.hxx> +#endif +#include <comphelper/processfactory.hxx> +#include <unotools/misccfg.hxx> +#include <com/sun/star/i18n/WordType.hdl> +#include <fmtpdsc.hxx> +#include <fmthdft.hxx> +#include <fmtcntnt.hxx> +#include <frmatr.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <hints.hxx> // fuer SwHyphenBug (in SetDefault) +#include <ndtxt.hxx> +#include <pam.hxx> +#include <UndoCore.hxx> +#include <UndoAttribute.hxx> +#include <ndgrf.hxx> +#include <pagedesc.hxx> // Fuer Sonderbehandlung in InsFrmFmt +#include <rolbck.hxx> // Undo-Attr +#include <mvsave.hxx> // servieren: Veraenderungen erkennen +#include <txatbase.hxx> +#include <swtable.hxx> +#include <swtblfmt.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <paratr.hxx> +#include <redline.hxx> +#include <reffld.hxx> +#include <txtinet.hxx> +#include <fmtinfmt.hxx> +#include <breakit.hxx> +#include <SwStyleNameMapper.hxx> +#include <fmtautofmt.hxx> +#include <istyleaccess.hxx> +#include <SwUndoFmt.hxx> +#include <docsh.hxx> + +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +SV_IMPL_PTRARR(SwFrmFmts,SwFrmFmtPtr) +SV_IMPL_PTRARR(SwCharFmts,SwCharFmtPtr) + +//Spezifische Frameformate (Rahmen) +SV_IMPL_PTRARR(SwSpzFrmFmts,SwFrmFmtPtr) + +/* + * interne Funktionen + */ + +sal_Bool SetTxtFmtCollNext( const SwTxtFmtCollPtr& rpTxtColl, void* pArgs ) +{ + SwTxtFmtColl *pDel = (SwTxtFmtColl*) pArgs; + if ( &rpTxtColl->GetNextTxtFmtColl() == pDel ) + { + rpTxtColl->SetNextTxtFmtColl( *rpTxtColl ); + } + return sal_True; +} + +/* + * Zuruecksetzen der harten Formatierung fuer Text + */ + +// Uebergabeparameter fuer _Rst und lcl_SetTxtFmtColl +struct ParaRstFmt +{ + SwFmtColl* pFmtColl; + SwHistory* pHistory; + const SwPosition *pSttNd, *pEndNd; + const SfxItemSet* pDelSet; + sal_uInt16 nWhich; + bool bReset; + // --> OD 2007-11-06 #i62575# + bool bResetListAttrs; + // <-- + bool bResetAll; + bool bInclRefToxMark; + + bool bKeepOutlineLevelAttr; //#outline level,add by zhaojianwei + + ParaRstFmt( const SwPosition* pStt, const SwPosition* pEnd, + SwHistory* pHst, sal_uInt16 nWhch = 0, const SfxItemSet* pSet = 0 ) + : pFmtColl(0), + pHistory(pHst), + pSttNd(pStt), + pEndNd(pEnd), + pDelSet(pSet), + nWhich(nWhch), + // --> OD 2007-11-06 #i62675# + bReset( false ), + bResetListAttrs( false ), + // <-- + bResetAll( true ), + bInclRefToxMark( false ), + bKeepOutlineLevelAttr( false ) //#outline level,add by zhaojianwei + {} + + ParaRstFmt( SwHistory* pHst ) + : pFmtColl(0), + pHistory(pHst), + pSttNd(0), + pEndNd(0), + pDelSet(0), + nWhich(0), + // --> OD 2007-11-06 #i62675# + bReset( false ), + bResetListAttrs( false ), + // <-- + bResetAll( true ), + bInclRefToxMark( false ), + bKeepOutlineLevelAttr( false ) //#outline level,add by zhaojianwei + {} +}; + +/* in pArgs steht die ChrFmtTablle vom Dokument + * (wird bei Selectionen am Start/Ende und bei keiner SSelection benoetigt) + */ + +sal_Bool lcl_RstTxtAttr( const SwNodePtr& rpNd, void* pArgs ) +{ + ParaRstFmt* pPara = (ParaRstFmt*)pArgs; + SwTxtNode * pTxtNode = (SwTxtNode*)rpNd->GetTxtNode(); + if( pTxtNode && pTxtNode->GetpSwpHints() ) + { + SwIndex aSt( pTxtNode, 0 ); + sal_uInt16 nEnd = pTxtNode->Len(); + + if( &pPara->pSttNd->nNode.GetNode() == pTxtNode && + pPara->pSttNd->nContent.GetIndex() ) + aSt = pPara->pSttNd->nContent.GetIndex(); + + if( &pPara->pEndNd->nNode.GetNode() == rpNd ) + nEnd = pPara->pEndNd->nContent.GetIndex(); + + if( pPara->pHistory ) + { + // fuers Undo alle Attribute sichern + SwRegHistory aRHst( *pTxtNode, pPara->pHistory ); + pTxtNode->GetpSwpHints()->Register( &aRHst ); + pTxtNode->RstAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich, + pPara->pDelSet, pPara->bInclRefToxMark ); + if( pTxtNode->GetpSwpHints() ) + pTxtNode->GetpSwpHints()->DeRegister(); + } + else + pTxtNode->RstAttr( aSt, nEnd - aSt.GetIndex(), pPara->nWhich, + pPara->pDelSet, pPara->bInclRefToxMark ); + } + return sal_True; +} + +sal_Bool lcl_RstAttr( const SwNodePtr& rpNd, void* pArgs ) +{ + ParaRstFmt* pPara = (ParaRstFmt*)pArgs; + SwCntntNode* pNode = (SwCntntNode*)rpNd->GetCntntNode(); + if( pNode && pNode->HasSwAttrSet() ) + { + const sal_Bool bLocked = pNode->IsModifyLocked(); + pNode->LockModify(); + + SwDoc* pDoc = pNode->GetDoc(); + + // --> OD 2008-04-14 #refactorlists# + // remove unused attribute RES_LR_SPACE + // add list attributes + SfxItemSet aSet( pDoc->GetAttrPool(), + RES_PAGEDESC, RES_BREAK, + RES_PARATR_NUMRULE, RES_PARATR_NUMRULE, + RES_PARATR_OUTLINELEVEL,RES_PARATR_OUTLINELEVEL,//#outline level,removed by zhaojianwei + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END - 1, + 0 ); + const SfxItemSet* pSet = pNode->GetpSwAttrSet(); + + // --> OD 2008-04-15 #refactorlists# +// std::vector<sal_uInt16> aClearWhichIds; + SvUShorts aClearWhichIds; + // <-- + // --> OD 2008-04-15 #refactorlists# + // restoring all paragraph list attributes + { + SfxItemSet aListAttrSet( pDoc->GetAttrPool(), + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END - 1, + 0 ); + aListAttrSet.Set( *pSet ); + if ( aListAttrSet.Count() ) + { + aSet.Put( aListAttrSet ); + SfxItemIter aIter( aListAttrSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( pItem ) + { + aClearWhichIds.Insert( pItem->Which(), aClearWhichIds.Count() ); + pItem = aIter.NextItem(); + } + } + } + // <-- + + const SfxPoolItem* pItem; + // sal_uInt16 __READONLY_DATA aSavIds[ 3 ] = { RES_PAGEDESC, RES_BREAK, //#outline level,removed by zhaojianwei + // RES_PARATR_NUMRULE }; + //for( sal_uInt16 n = 0; n < 3; ++n ) + sal_uInt16 __READONLY_DATA aSavIds[ 4 ] = { RES_PAGEDESC, RES_BREAK, //->add by zhaojianwei + RES_PARATR_NUMRULE, + RES_PARATR_OUTLINELEVEL }; + for( sal_uInt16 n = 0; n < 4; ++n ) //<-end,zhaojianwei + { + if( SFX_ITEM_SET == pSet->GetItemState( aSavIds[ n ], sal_False, &pItem )) + { + bool bSave = false; + switch( aSavIds[ n ] ) + { + case RES_PAGEDESC: + bSave = 0 != ((SwFmtPageDesc*)pItem)->GetPageDesc(); + break; + case RES_BREAK: + bSave = SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak(); + break; + case RES_PARATR_NUMRULE: + { + bSave = 0 != ((SwNumRuleItem*)pItem)->GetValue().Len(); + } + break; + case RES_PARATR_OUTLINELEVEL: //#outline level,add by zhaojianwei + { + bSave = pPara && pPara->bKeepOutlineLevelAttr; + } + break; //<-end,zhaojianwei + } + if( bSave ) + { + aSet.Put( *pItem ); + // --> OD 2008-04-15 #refactorlists# +// aClearWhichIds.push_back( aSavIds[n] ); + aClearWhichIds.Insert( aSavIds[n], aClearWhichIds.Count() ); + } + } + } + + // --> OD 2008-04-14 #refactorlists# + // do not clear items directly from item set and only clear to be kept + // attributes, if no deletion item set is found. +// pNode->ClearItemsFromAttrSet( aClearWhichIds ); + const bool bKeepAttributes = + !pPara || !pPara->pDelSet || pPara->pDelSet->Count() == 0; + if ( bKeepAttributes ) + { + pNode->ResetAttr( aClearWhichIds ); + } + // <-- + + if( !bLocked ) + pNode->UnlockModify(); + + if( pPara ) + { + SwRegHistory aRegH( pNode, *pNode, pPara->pHistory ); + + if( pPara->pDelSet && pPara->pDelSet->Count() ) + { + // --> OD 2008-04-15 #refactorlists# + ASSERT( !bKeepAttributes, + "<lcl_RstAttr(..)> - certain attributes are kept, but not needed. -> please inform OD" ); + // <-- + SfxItemIter aIter( *pPara->pDelSet ); + pItem = aIter.FirstItem(); + while( sal_True ) + { + // --> OD 2008-04-14 #refactorlists# + // + if ( ( pItem->Which() != RES_PAGEDESC && + pItem->Which() != RES_BREAK && + pItem->Which() != RES_PARATR_NUMRULE ) || + ( aSet.GetItemState( pItem->Which(), sal_False ) != SFX_ITEM_SET ) ) + { + pNode->ResetAttr( pItem->Which() ); + } + // <-- + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + } + else if( pPara->bResetAll ) + pNode->ResetAllAttr(); + else + pNode->ResetAttr( RES_PARATR_BEGIN, POOLATTR_END - 1 ); + } + else + pNode->ResetAllAttr(); + + // --> OD 2008-04-15 #refactorlists# + // only restore saved attributes, if needed + if ( bKeepAttributes && aSet.Count() ) + // <-- + { + pNode->LockModify(); + + pNode->SetAttr( aSet ); + + if( !bLocked ) + pNode->UnlockModify(); + } + } + return sal_True; +} + +void SwDoc::RstTxtAttrs(const SwPaM &rRg, sal_Bool bInclRefToxMark ) +{ + SwHistory* pHst = 0; + SwDataChanged aTmp( rRg, 0 ); + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoResetAttr* pUndo = new SwUndoResetAttr( rRg, RES_CHRFMT ); + pHst = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End(); + ParaRstFmt aPara( pStt, pEnd, pHst ); + aPara.bInclRefToxMark = ( bInclRefToxMark == sal_True ); + GetNodes().ForEach( pStt->nNode.GetIndex(), pEnd->nNode.GetIndex()+1, + lcl_RstTxtAttr, &aPara ); + SetModified(); +} + +void SwDoc::ResetAttrs( const SwPaM &rRg, + sal_Bool bTxtAttr, + const SvUShortsSort* pAttrs, + // --> OD 2008-11-28 #b96644# + const bool bSendDataChangedEvents ) + // <-- +{ + SwPaM* pPam = (SwPaM*)&rRg; + if( !bTxtAttr && pAttrs && pAttrs->Count() && + RES_TXTATR_END > (*pAttrs)[ 0 ] ) + bTxtAttr = sal_True; + + if( !rRg.HasMark() ) + { + SwTxtNode* pTxtNd = rRg.GetPoint()->nNode.GetNode().GetTxtNode(); + if( !pTxtNd ) + return ; + + pPam = new SwPaM( *rRg.GetPoint() ); + + SwIndex& rSt = pPam->GetPoint()->nContent; + sal_uInt16 nMkPos, nPtPos = rSt.GetIndex(); + + // JP 22.08.96: Sonderfall: steht der Crsr in einem URL-Attribut + // dann wird dessen Bereich genommen + SwTxtAttr const*const pURLAttr( + pTxtNd->GetTxtAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT)); + if (pURLAttr && pURLAttr->GetINetFmt().GetValue().Len()) + { + nMkPos = *pURLAttr->GetStart(); + nPtPos = *pURLAttr->GetEnd(); + } + else + { + Boundary aBndry; + if( pBreakIt->GetBreakIter().is() ) + aBndry = pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, + sal_True ); + + if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos ) + { + nMkPos = (xub_StrLen)aBndry.startPos; + nPtPos = (xub_StrLen)aBndry.endPos; + } + else + { + nPtPos = nMkPos = rSt.GetIndex(); + if( bTxtAttr ) + pTxtNd->DontExpandFmt( rSt, sal_True ); + } + } + + rSt = nMkPos; + pPam->SetMark(); + pPam->GetPoint()->nContent = nPtPos; + } + + // --> OD 2008-11-28 #i96644# +// SwDataChanged aTmp( *pPam, 0 ); + std::auto_ptr< SwDataChanged > pDataChanged; + if ( bSendDataChangedEvents ) + { + pDataChanged.reset( new SwDataChanged( *pPam, 0 ) ); + } + // <-- + SwHistory* pHst = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoResetAttr* pUndo = new SwUndoResetAttr( rRg, + static_cast<sal_uInt16>(bTxtAttr ? RES_CONDTXTFMTCOLL : RES_TXTFMTCOLL )); + if( pAttrs && pAttrs->Count() ) + { + pUndo->SetAttrs( *pAttrs ); + } + pHst = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + const SwPosition *pStt = pPam->Start(), *pEnd = pPam->End(); + ParaRstFmt aPara( pStt, pEnd, pHst ); + + // mst: not including META here; it seems attrs with CH_TXTATR are omitted + sal_uInt16 __FAR_DATA aResetableSetRange[] = { + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + // --> OD 2008-02-25 #refactorlists# + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + // <-- + RES_TXTATR_INETFMT, RES_TXTATR_INETFMT, + RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT, + RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY, + RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + 0 + }; + + SfxItemSet aDelSet( GetAttrPool(), aResetableSetRange ); + if( pAttrs && pAttrs->Count() ) + { + for( sal_uInt16 n = pAttrs->Count(); n; ) + if( POOLATTR_END > (*pAttrs)[ --n ] ) + aDelSet.Put( *GetDfltAttr( (*pAttrs)[ n ] )); + + if( aDelSet.Count() ) + aPara.pDelSet = &aDelSet; + } + + sal_Bool bAdd = sal_True; + SwNodeIndex aTmpStt( pStt->nNode ); + SwNodeIndex aTmpEnd( pEnd->nNode ); + if( pStt->nContent.GetIndex() ) // nur ein Teil + { + // dann spaeter aufsetzen und alle CharFmtAttr -> TxtFmtAttr + SwTxtNode* pTNd = aTmpStt.GetNode().GetTxtNode(); + if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() ) + { + SfxItemIter aIter( *pTNd->GetpSwAttrSet() ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_CHRATR_END ); + + while( sal_True ) + { + if( IsInRange( aCharFmtSetRange, pItem->Which() )) + { + pTNd->GetOrCreateSwpHints(); + + aCharSet.Put( *pItem ); + + if( pHst ) + { + SwRegHistory aRegH( pTNd, *pTNd, pHst ); + pTNd->ResetAttr( pItem->Which() ); + } + else + pTNd->ResetAttr( pItem->Which() ); + } + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + + if ( aCharSet.Count() ) + { + if ( pHst ) + { + SwRegHistory history( pTNd, *pTNd, pHst ); + history.InsertItems( aCharSet, 0, pTNd->GetTxt().Len(), + nsSetAttrMode::SETATTR_NOFORMATATTR ); + } + else + { + SwTxtAttr* pNew = + MakeTxtAttr( *this, aCharSet, 0, pTNd->GetTxt().Len() ); + pTNd->InsertHint( pNew ); + } + } + } + + aTmpStt++; + } + if( pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetCntntNode()->Len() ) + // dann spaeter aufsetzen und alle CharFmtAttr -> TxtFmtAttr + aTmpEnd++, bAdd = sal_False; + else if( pStt->nNode != pEnd->nNode || !pStt->nContent.GetIndex() ) + { + SwTxtNode* pTNd = aTmpEnd.GetNode().GetTxtNode(); + if( pTNd && pTNd->HasSwAttrSet() && pTNd->GetpSwAttrSet()->Count() ) + { + SfxItemIter aIter( *pTNd->GetpSwAttrSet() ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( sal_True ) + { + if( IsInRange( aCharFmtSetRange, pItem->Which() )) + { + SwTxtAttr* pTAttr = MakeTxtAttr( *this, + const_cast<SfxPoolItem&>(*pItem), + 0, pTNd->GetTxt().Len() ); + SwpHints & rHints = pTNd->GetOrCreateSwpHints(); + rHints.SwpHintsArray::Insert( pTAttr ); + if ( pHst ) + { + SwRegHistory aRegH( pTNd, *pTNd, pHst ); + pTNd->ResetAttr( pItem->Which() ); + pHst->Add( pTAttr, aTmpEnd.GetIndex(), true ); + } + else + pTNd->ResetAttr( pItem->Which() ); + } + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + } + } + + if( aTmpStt < aTmpEnd ) + GetNodes().ForEach( pStt->nNode, aTmpEnd, lcl_RstAttr, &aPara ); + else if( !rRg.HasMark() ) + { + aPara.bResetAll = false ; + ::lcl_RstAttr( &pStt->nNode.GetNode(), &aPara ); + aPara.bResetAll = true ; + } + + if( bTxtAttr ) + { + if( bAdd ) + aTmpEnd++; + GetNodes().ForEach( pStt->nNode, aTmpEnd, lcl_RstTxtAttr, &aPara ); + } + + if( pPam != &rRg ) + delete pPam; + + SetModified(); +} + +#define DELETECHARSETS if ( bDelete ) { delete pCharSet; delete pOtherSet; } + +// Einfuegen der Hints nach Inhaltsformen; +// wird in SwDoc::Insert(..., SwFmtHint &rHt) benutzt + +static bool +lcl_InsAttr(SwDoc *const pDoc, const SwPaM &rRg, const SfxItemSet& rChgSet, + const SetAttrMode nFlags, SwUndoAttr *const pUndo) +{ + // teil die Sets auf (fuer Selektion in Nodes) + const SfxItemSet* pCharSet = 0; + const SfxItemSet* pOtherSet = 0; + bool bDelete = false; + bool bCharAttr = false; + bool bOtherAttr = false; + + // Check, if we can work with rChgSet or if we have to create additional SfxItemSets + if ( 1 == rChgSet.Count() ) + { + SfxItemIter aIter( rChgSet ); + const SfxPoolItem* pItem = aIter.FirstItem(); + const sal_uInt16 nWhich = pItem->Which(); + + if ( isCHRATR(nWhich) || + (RES_TXTATR_CHARFMT == nWhich) || + (RES_TXTATR_INETFMT == nWhich) || + (RES_TXTATR_AUTOFMT == nWhich) || + (RES_TXTATR_UNKNOWN_CONTAINER == nWhich) ) + { + pCharSet = &rChgSet; + bCharAttr = true; + } + + if ( isPARATR(nWhich) + // --> OD 2008-02-25 #refactorlists# + || isPARATR_LIST(nWhich) + // <-- + || isFRMATR(nWhich) + || isGRFATR(nWhich) + || isUNKNOWNATR(nWhich) ) + { + pOtherSet = &rChgSet; + bOtherAttr = true; + } + } + + // Build new itemset if either + // - rChgSet.Count() > 1 or + // - The attribute in rChgSet does not belong to one of the above categories + if ( !bCharAttr && !bOtherAttr ) + { + SfxItemSet* pTmpCharItemSet = new SfxItemSet( pDoc->GetAttrPool(), + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_TXTATR_AUTOFMT, RES_TXTATR_AUTOFMT, + RES_TXTATR_INETFMT, RES_TXTATR_INETFMT, + RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT, + RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER, + 0 ); + + SfxItemSet* pTmpOtherItemSet = new SfxItemSet( pDoc->GetAttrPool(), + RES_PARATR_BEGIN, RES_PARATR_END-1, + // --> OD 2008-02-25 #refactorlists# + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + // <-- + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_GRFATR_BEGIN, RES_GRFATR_END-1, + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + 0 ); + + pTmpCharItemSet->Put( rChgSet ); + pTmpOtherItemSet->Put( rChgSet ); + + pCharSet = pTmpCharItemSet; + pOtherSet = pTmpOtherItemSet; + + bDelete = true; + } + + SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0; + bool bRet = false; + const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End(); + SwCntntNode* pNode = pStt->nNode.GetNode().GetCntntNode(); + + if( pNode && pNode->IsTxtNode() ) + { + // -> #i27615# + if (rRg.IsInFrontOfLabel()) + { + SwTxtNode * pTxtNd = pNode->GetTxtNode(); + SwNumRule * pNumRule = pTxtNd->GetNumRule(); + + // --> OD 2005-10-24 #126346# - make code robust: + if ( !pNumRule ) + { + ASSERT( false, + "<InsAttr(..)> - PaM in front of label, but text node has no numbering rule set. This is a serious defect, please inform OD." ); + DELETECHARSETS + return false; + } + // <-- + + SwNumFmt aNumFmt = pNumRule->Get(static_cast<sal_uInt16>(pTxtNd->GetActualListLevel())); + SwCharFmt * pCharFmt = + pDoc->FindCharFmtByName(aNumFmt.GetCharFmtName()); + + if (pCharFmt) + { + if (pHistory) + pHistory->Add(pCharFmt->GetAttrSet(), *pCharFmt); + + if ( pCharSet ) + pCharFmt->SetFmtAttr(*pCharSet); + } + + DELETECHARSETS + return true; + } + // <- #i27615# + + const SwIndex& rSt = pStt->nContent; + + // Attribute ohne Ende haben keinen Bereich + if ( !bCharAttr && !bOtherAttr ) + { + SfxItemSet aTxtSet( pDoc->GetAttrPool(), + RES_TXTATR_NOEND_BEGIN, RES_TXTATR_NOEND_END-1 ); + aTxtSet.Put( rChgSet ); + if( aTxtSet.Count() ) + { + SwRegHistory history( pNode, *pNode, pHistory ); + bRet = history.InsertItems( + aTxtSet, rSt.GetIndex(), rSt.GetIndex(), nFlags ) || bRet; + + if (bRet && (pDoc->IsRedlineOn() || (!pDoc->IsIgnoreRedline() + && pDoc->GetRedlineTbl().Count()))) + { + SwPaM aPam( pStt->nNode, pStt->nContent.GetIndex()-1, + pStt->nNode, pStt->nContent.GetIndex() ); + + if( pUndo ) + pUndo->SaveRedlineData( aPam, sal_True ); + + if( pDoc->IsRedlineOn() ) + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true); + else + pDoc->SplitRedline( aPam ); + } + } + } + + // TextAttribute mit Ende expandieren nie ihren Bereich + if ( !bCharAttr && !bOtherAttr ) + { + // CharFmt wird gesondert behandelt !!! + // JP 22.08.96: URL-Attribute auch!! + // TEST_TEMP ToDo: AutoFmt! + SfxItemSet aTxtSet( pDoc->GetAttrPool(), + RES_TXTATR_REFMARK, RES_TXTATR_TOXMARK, + RES_TXTATR_META, RES_TXTATR_METAFIELD, + RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY, + 0 ); + + aTxtSet.Put( rChgSet ); + if( aTxtSet.Count() ) + { + sal_uInt16 nInsCnt = rSt.GetIndex(); + sal_uInt16 nEnd = pStt->nNode == pEnd->nNode + ? pEnd->nContent.GetIndex() + : pNode->Len(); + SwRegHistory history( pNode, *pNode, pHistory ); + bRet = history.InsertItems( aTxtSet, nInsCnt, nEnd, nFlags ) + || bRet; + + if (bRet && (pDoc->IsRedlineOn() || (!pDoc->IsIgnoreRedline() + && pDoc->GetRedlineTbl().Count()))) + { + // wurde Text-Inhalt eingefuegt? (RefMark/TOXMarks ohne Ende) + sal_Bool bTxtIns = nInsCnt != rSt.GetIndex(); + // wurde Inhalt eingefuegt oder ueber die Selektion gesetzt? + SwPaM aPam( pStt->nNode, bTxtIns ? nInsCnt + 1 : nEnd, + pStt->nNode, nInsCnt ); + if( pUndo ) + pUndo->SaveRedlineData( aPam, bTxtIns ); + + if( pDoc->IsRedlineOn() ) + pDoc->AppendRedline( new SwRedline( bTxtIns + ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_FORMAT, aPam ), true); + else if( bTxtIns ) + pDoc->SplitRedline( aPam ); + } + } + } + } + + // bei PageDesc's, die am Node gesetzt werden, muss immer das + // Auto-Flag gesetzt werden!! + if( pOtherSet && pOtherSet->Count() ) + { + SwTableNode* pTblNd; + const SwFmtPageDesc* pDesc; + if( SFX_ITEM_SET == pOtherSet->GetItemState( RES_PAGEDESC, + sal_False, (const SfxPoolItem**)&pDesc )) + { + if( pNode ) + { + // Auto-Flag setzen, nur in Vorlagen ist ohne Auto ! + SwFmtPageDesc aNew( *pDesc ); + // Bug 38479: AutoFlag wird jetzt in der WrtShell gesetzt + // aNew.SetAuto(); + + // Tabellen kennen jetzt auch Umbrueche + if( 0 == (nFlags & nsSetAttrMode::SETATTR_APICALL) && + 0 != ( pTblNd = pNode->FindTableNode() ) ) + { + SwTableNode* pCurTblNd = pTblNd; + while ( 0 != ( pCurTblNd = pCurTblNd->StartOfSectionNode()->FindTableNode() ) ) + pTblNd = pCurTblNd; + + // dann am Tabellen Format setzen + SwFrmFmt* pFmt = pTblNd->GetTable().GetFrmFmt(); + SwRegHistory aRegH( pFmt, *pTblNd, pHistory ); + pFmt->SetFmtAttr( aNew ); + bRet = true; + } + else + { + SwRegHistory aRegH( pNode, *pNode, pHistory ); + bRet = pNode->SetAttr( aNew ) || bRet; + } + } + + // bOtherAttr = true means that pOtherSet == rChgSet. In this case + // we know, that there is only one attribute in pOtherSet. We cannot + // perform the following operations, instead we return: + if ( bOtherAttr ) + return bRet; + + const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_PAGEDESC ); + if( !pOtherSet->Count() ) + { + DELETECHARSETS + return bRet; + } + } + + // Tabellen kennen jetzt auch Umbrueche + const SvxFmtBreakItem* pBreak; + if( pNode && 0 == (nFlags & nsSetAttrMode::SETATTR_APICALL) && + 0 != (pTblNd = pNode->FindTableNode() ) && + SFX_ITEM_SET == pOtherSet->GetItemState( RES_BREAK, + sal_False, (const SfxPoolItem**)&pBreak ) ) + { + SwTableNode* pCurTblNd = pTblNd; + while ( 0 != ( pCurTblNd = pCurTblNd->StartOfSectionNode()->FindTableNode() ) ) + pTblNd = pCurTblNd; + + // dann am Tabellen Format setzen + SwFrmFmt* pFmt = pTblNd->GetTable().GetFrmFmt(); + SwRegHistory aRegH( pFmt, *pTblNd, pHistory ); + pFmt->SetFmtAttr( *pBreak ); + bRet = true; + + // bOtherAttr = true means that pOtherSet == rChgSet. In this case + // we know, that there is only one attribute in pOtherSet. We cannot + // perform the following operations, instead we return: + if ( bOtherAttr ) + return bRet; + + const_cast<SfxItemSet*>(pOtherSet)->ClearItem( RES_BREAK ); + if( !pOtherSet->Count() ) + { + DELETECHARSETS + return bRet; + } + } + + { + // wenns eine PoolNumRule ist, diese ggfs. anlegen + const SwNumRuleItem* pRule; + sal_uInt16 nPoolId; + if( SFX_ITEM_SET == pOtherSet->GetItemState( RES_PARATR_NUMRULE, + sal_False, (const SfxPoolItem**)&pRule ) && + !pDoc->FindNumRulePtr( pRule->GetValue() ) && + USHRT_MAX != (nPoolId = SwStyleNameMapper::GetPoolIdFromUIName ( pRule->GetValue(), + nsSwGetPoolIdFromName::GET_POOLID_NUMRULE )) ) + pDoc->GetNumRuleFromPool( nPoolId ); + } + + } + + if( !rRg.HasMark() ) // kein Bereich + { + if( !pNode ) + { + DELETECHARSETS + return bRet; + } + + if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() ) + { + SwTxtNode* pTxtNd = static_cast<SwTxtNode*>(pNode); + const SwIndex& rSt = pStt->nContent; + sal_uInt16 nMkPos, nPtPos = rSt.GetIndex(); + const String& rStr = pTxtNd->GetTxt(); + + // JP 22.08.96: Sonderfall: steht der Crsr in einem URL-Attribut + // dann wird dessen Bereich genommen + SwTxtAttr const*const pURLAttr( + pTxtNd->GetTxtAttrAt(rSt.GetIndex(), RES_TXTATR_INETFMT)); + if (pURLAttr && pURLAttr->GetINetFmt().GetValue().Len()) + { + nMkPos = *pURLAttr->GetStart(); + nPtPos = *pURLAttr->GetEnd(); + } + else + { + Boundary aBndry; + if( pBreakIt->GetBreakIter().is() ) + aBndry = pBreakIt->GetBreakIter()->getWordBoundary( + pTxtNd->GetTxt(), nPtPos, + pBreakIt->GetLocale( pTxtNd->GetLang( nPtPos ) ), + WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/, + sal_True ); + + if( aBndry.startPos < nPtPos && nPtPos < aBndry.endPos ) + { + nMkPos = (xub_StrLen)aBndry.startPos; + nPtPos = (xub_StrLen)aBndry.endPos; + } + else + nPtPos = nMkPos = rSt.GetIndex(); + } + + // erstmal die zu ueberschreibenden Attribute aus dem + // SwpHintsArray entfernen, wenn die Selektion den gesamten + // Absatz umspannt. (Diese Attribute werden als FormatAttr. + // eingefuegt und verdraengen nie die TextAttr.!) + if( !(nFlags & nsSetAttrMode::SETATTR_DONTREPLACE ) && + pTxtNd->HasHints() && !nMkPos && nPtPos == rStr.Len() ) + { + SwIndex aSt( pTxtNd ); + if( pHistory ) + { + // fuers Undo alle Attribute sichern + SwRegHistory aRHst( *pTxtNd, pHistory ); + pTxtNd->GetpSwpHints()->Register( &aRHst ); + pTxtNd->RstAttr( aSt, nPtPos, 0, pCharSet ); + if( pTxtNd->GetpSwpHints() ) + pTxtNd->GetpSwpHints()->DeRegister(); + } + else + pTxtNd->RstAttr( aSt, nPtPos, 0, pCharSet ); + } + + // the SwRegHistory inserts the attribute into the TxtNode! + SwRegHistory history( pNode, *pNode, pHistory ); + bRet = history.InsertItems( *pCharSet, nMkPos, nPtPos, nFlags ) + || bRet; + + if( pDoc->IsRedlineOn() ) + { + SwPaM aPam( *pNode, nMkPos, *pNode, nPtPos ); + + if( pUndo ) + pUndo->SaveRedlineData( aPam, sal_False ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_FORMAT, aPam ), true); + } + } + if( pOtherSet && pOtherSet->Count() ) + { + SwRegHistory aRegH( pNode, *pNode, pHistory ); + bRet = pNode->SetAttr( *pOtherSet ) || bRet; + } + + DELETECHARSETS + return bRet; + } + + if( pDoc->IsRedlineOn() && pCharSet && pCharSet->Count() ) + { + if( pUndo ) + pUndo->SaveRedlineData( rRg, sal_False ); + pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_FORMAT, rRg ), true); + } + + /* jetzt wenn Bereich */ + sal_uLong nNodes = 0; + + SwNodeIndex aSt( pDoc->GetNodes() ); + SwNodeIndex aEnd( pDoc->GetNodes() ); + SwIndex aCntEnd( pEnd->nContent ); + + if( pNode ) + { + sal_uInt16 nLen = pNode->Len(); + if( pStt->nNode != pEnd->nNode ) + aCntEnd.Assign( pNode, nLen ); + + if( pStt->nContent.GetIndex() != 0 || aCntEnd.GetIndex() != nLen ) + { + // the SwRegHistory inserts the attribute into the TxtNode! + if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() ) + { + SwRegHistory history( pNode, *pNode, pHistory ); + bRet = history.InsertItems(*pCharSet, + pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags) + || bRet; + } + + if( pOtherSet && pOtherSet->Count() ) + { + SwRegHistory aRegH( pNode, *pNode, pHistory ); + bRet = pNode->SetAttr( *pOtherSet ) || bRet; + } + + // lediglich Selektion in einem Node. + if( pStt->nNode == pEnd->nNode ) + { + DELETECHARSETS + return bRet; + } + ++nNodes; + aSt.Assign( pStt->nNode.GetNode(), +1 ); + } + else + aSt = pStt->nNode; + aCntEnd = pEnd->nContent; // aEnd wurde veraendert !! + } + else + aSt.Assign( pStt->nNode.GetNode(), +1 ); + + // aSt zeigt jetzt auf den ersten vollen Node + + /* + * die Selektion umfasst mehr als einen Node + */ + if( pStt->nNode < pEnd->nNode ) + { + pNode = pEnd->nNode.GetNode().GetCntntNode(); + if(pNode) + { + sal_uInt16 nLen = pNode->Len(); + if( aCntEnd.GetIndex() != nLen ) + { + // the SwRegHistory inserts the attribute into the TxtNode! + if( pNode->IsTxtNode() && pCharSet && pCharSet->Count() ) + { + SwRegHistory history( pNode, *pNode, pHistory ); + history.InsertItems(*pCharSet, + 0, aCntEnd.GetIndex(), nFlags); + } + + if( pOtherSet && pOtherSet->Count() ) + { + SwRegHistory aRegH( pNode, *pNode, pHistory ); + pNode->SetAttr( *pOtherSet ); + } + + ++nNodes; + aEnd = pEnd->nNode; + } + else + aEnd.Assign( pEnd->nNode.GetNode(), +1 ); + } + else + aEnd = pEnd->nNode; + } + else + aEnd.Assign( pEnd->nNode.GetNode(), +1 ); + + // aEnd zeigt jetzt HINTER den letzten voll Node + + /* Bearbeitung der vollstaendig selektierten Nodes. */ +// alle Attribute aus dem Set zuruecksetzen !! + if( pCharSet && pCharSet->Count() && !( nsSetAttrMode::SETATTR_DONTREPLACE & nFlags ) ) + { + + ParaRstFmt aPara( pStt, pEnd, pHistory, 0, pCharSet ); + pDoc->GetNodes().ForEach( aSt, aEnd, lcl_RstTxtAttr, &aPara ); + } + + sal_Bool bCreateSwpHints = pCharSet && ( + SFX_ITEM_SET == pCharSet->GetItemState( RES_TXTATR_CHARFMT, sal_False ) || + SFX_ITEM_SET == pCharSet->GetItemState( RES_TXTATR_INETFMT, sal_False ) ); + + for(; aSt < aEnd; aSt++ ) + { + pNode = aSt.GetNode().GetCntntNode(); + if( !pNode ) + continue; + + SwTxtNode* pTNd = pNode->GetTxtNode(); + if( pHistory ) + { + SwRegHistory aRegH( pNode, *pNode, pHistory ); + SwpHints *pSwpHints; + + if( pTNd && pCharSet && pCharSet->Count() ) + { + pSwpHints = bCreateSwpHints ? &pTNd->GetOrCreateSwpHints() + : pTNd->GetpSwpHints(); + if( pSwpHints ) + pSwpHints->Register( &aRegH ); + + pTNd->SetAttr( *pCharSet, 0, pTNd->GetTxt().Len(), nFlags ); + if( pSwpHints ) + pSwpHints->DeRegister(); + } + if( pOtherSet && pOtherSet->Count() ) + pNode->SetAttr( *pOtherSet ); + } + else + { + if( pTNd && pCharSet && pCharSet->Count() ) + pTNd->SetAttr( *pCharSet, 0, pTNd->GetTxt().Len(), nFlags ); + if( pOtherSet && pOtherSet->Count() ) + pNode->SetAttr( *pOtherSet ); + } + ++nNodes; + } + + DELETECHARSETS + return (nNodes != 0) || bRet; +} + + +bool SwDoc::InsertPoolItem( const SwPaM &rRg, const SfxPoolItem &rHt, + const SetAttrMode nFlags ) +{ + SwDataChanged aTmp( rRg, 0 ); + SwUndoAttr* pUndoAttr = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndoAttr = new SwUndoAttr( rRg, rHt, nFlags ); + } + + SfxItemSet aSet( GetAttrPool(), rHt.Which(), rHt.Which() ); + aSet.Put( rHt ); + bool bRet = lcl_InsAttr( this, rRg, aSet, nFlags, pUndoAttr ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( pUndoAttr ); + } + + if( bRet ) + SetModified(); + return bRet; +} + +bool SwDoc::InsertItemSet ( const SwPaM &rRg, const SfxItemSet &rSet, + const SetAttrMode nFlags ) +{ + SwDataChanged aTmp( rRg, 0 ); + SwUndoAttr* pUndoAttr = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndoAttr = new SwUndoAttr( rRg, rSet, nFlags ); + } + + bool bRet = lcl_InsAttr( this, rRg, rSet, nFlags, pUndoAttr ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( pUndoAttr ); + } + + if( bRet ) + SetModified(); + return bRet; +} + + + // Setze das Attribut im angegebenen Format. Ist Undo aktiv, wird + // das alte in die Undo-History aufgenommen +void SwDoc::SetAttr( const SfxPoolItem& rAttr, SwFmt& rFmt ) +{ + SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() ); + aSet.Put( rAttr ); + SetAttr( aSet, rFmt ); +} + + + // Setze das Attribut im angegebenen Format. Ist Undo aktiv, wird + // das alte in die Undo-History aufgenommen +void SwDoc::SetAttr( const SfxItemSet& rSet, SwFmt& rFmt ) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoFmtAttrHelper aTmp( rFmt ); + rFmt.SetFmtAttr( rSet ); + if ( aTmp.GetUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( aTmp.ReleaseUndo() ); + } + else + { + GetIDocumentUndoRedo().ClearRedo(); + } + } + else + { + rFmt.SetFmtAttr( rSet ); + } + SetModified(); +} + +// --> OD 2008-02-12 #newlistlevelattrs# +void SwDoc::ResetAttrAtFormat( const sal_uInt16 nWhichId, + SwFmt& rChangedFormat ) +{ + SwUndo *const pUndo = (GetIDocumentUndoRedo().DoesUndo()) + ? new SwUndoFmtResetAttr( rChangedFormat, nWhichId ) + : 0; + + const sal_Bool bAttrReset = rChangedFormat.ResetFmtAttr( nWhichId ); + + if ( bAttrReset ) + { + if ( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + + SetModified(); + } + else if ( pUndo ) + delete pUndo; +} +// <-- + +int lcl_SetNewDefTabStops( SwTwips nOldWidth, SwTwips nNewWidth, + SvxTabStopItem& rChgTabStop ) +{ + // dann aender bei allen TabStop die default's auf den neuen Wert + // !!! Achtung: hier wird immer auf dem PoolAttribut gearbeitet, + // damit nicht in allen Sets die gleiche Berechnung + // auf dem gleichen TabStop (gepoolt!) vorgenommen + // wird. Als Modify wird ein FmtChg verschickt. + + sal_uInt16 nOldCnt = rChgTabStop.Count(); + if( !nOldCnt || nOldWidth == nNewWidth ) + return sal_False; + + // suche den Anfang der Defaults + SvxTabStop* pTabs = ((SvxTabStop*)rChgTabStop.GetStart()) + + (nOldCnt-1); + sal_uInt16 n; + + for( n = nOldCnt; n ; --n, --pTabs ) + if( SVX_TAB_ADJUST_DEFAULT != pTabs->GetAdjustment() ) + break; + ++n; + if( n < nOldCnt ) // die DefTabStops loeschen + rChgTabStop.Remove( n, nOldCnt - n ); + return sal_True; +} + +// Setze das Attribut als neues default Attribut in diesem Dokument. +// Ist Undo aktiv, wird das alte in die Undo-History aufgenommen +void SwDoc::SetDefault( const SfxPoolItem& rAttr ) +{ + SfxItemSet aSet( GetAttrPool(), rAttr.Which(), rAttr.Which() ); + aSet.Put( rAttr ); + SetDefault( aSet ); +} + +void SwDoc::SetDefault( const SfxItemSet& rSet ) +{ + if( !rSet.Count() ) + return; + + SwModify aCallMod( 0 ); + SwAttrSet aOld( GetAttrPool(), rSet.GetRanges() ), + aNew( GetAttrPool(), rSet.GetRanges() ); + SfxItemIter aIter( rSet ); + sal_uInt16 nWhich; + const SfxPoolItem* pItem = aIter.GetCurItem(); + SfxItemPool* pSdrPool = GetAttrPool().GetSecondaryPool(); + while( sal_True ) + { + sal_Bool bCheckSdrDflt = sal_False; + nWhich = pItem->Which(); + aOld.Put( GetAttrPool().GetDefaultItem( nWhich ) ); + GetAttrPool().SetPoolDefaultItem( *pItem ); + aNew.Put( GetAttrPool().GetDefaultItem( nWhich ) ); + + if (isCHRATR(nWhich) || isTXTATR(nWhich)) + { + aCallMod.Add( pDfltTxtFmtColl ); + aCallMod.Add( pDfltCharFmt ); + bCheckSdrDflt = 0 != pSdrPool; + } + else if ( isPARATR(nWhich) || + // --> OD 2008-02-25 #refactorlists# + isPARATR_LIST(nWhich) ) + // <-- + { + aCallMod.Add( pDfltTxtFmtColl ); + bCheckSdrDflt = 0 != pSdrPool; + } + else if (isGRFATR(nWhich)) + { + aCallMod.Add( pDfltGrfFmtColl ); + } + else if (isFRMATR(nWhich)) + { + aCallMod.Add( pDfltGrfFmtColl ); + aCallMod.Add( pDfltTxtFmtColl ); + aCallMod.Add( pDfltFrmFmt ); + } + else if (isBOXATR(nWhich)) + { + aCallMod.Add( pDfltFrmFmt ); + } + + // copy also the defaults + if( bCheckSdrDflt ) + { + sal_uInt16 nEdtWhich, nSlotId; + if( 0 != (nSlotId = GetAttrPool().GetSlotId( nWhich ) ) && + nSlotId != nWhich && + 0 != (nEdtWhich = pSdrPool->GetWhich( nSlotId )) && + nSlotId != nEdtWhich ) + { + SfxPoolItem* pCpy = pItem->Clone(); + pCpy->SetWhich( nEdtWhich ); + pSdrPool->SetPoolDefaultItem( *pCpy ); + delete pCpy; + } + } + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + + if( aNew.Count() && aCallMod.GetDepends() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoDefaultAttr( aOld ) ); + } + + const SfxPoolItem* pTmpItem; + if( ( SFX_ITEM_SET == + aNew.GetItemState( RES_PARATR_TABSTOP, sal_False, &pTmpItem ) ) && + ((SvxTabStopItem*)pTmpItem)->Count() ) + { + // TabStop-Aenderungen behandeln wir erstmal anders: + // dann aender bei allen TabStop die dafault's auf den neuen Wert + // !!! Achtung: hier wird immer auf dem PoolAttribut gearbeitet, + // damit nicht in allen Sets die gleiche Berechnung + // auf dem gleichen TabStop (gepoolt!) vorgenommen + // wird. Als Modify wird ein FmtChg verschickt. + SwTwips nNewWidth = (*(SvxTabStopItem*)pTmpItem)[ 0 ].GetTabPos(), + nOldWidth = ((SvxTabStopItem&)aOld.Get(RES_PARATR_TABSTOP))[ 0 ].GetTabPos(); + + int bChg = sal_False; + sal_uInt32 nMaxItems = GetAttrPool().GetItemCount2( RES_PARATR_TABSTOP ); + for( sal_uInt32 n = 0; n < nMaxItems; ++n ) + if( 0 != (pTmpItem = GetAttrPool().GetItem2( RES_PARATR_TABSTOP, n ) )) + bChg |= lcl_SetNewDefTabStops( nOldWidth, nNewWidth, + *(SvxTabStopItem*)pTmpItem ); + + aNew.ClearItem( RES_PARATR_TABSTOP ); + aOld.ClearItem( RES_PARATR_TABSTOP ); + if( bChg ) + { + SwFmtChg aChgFmt( pDfltCharFmt ); + // dann sage mal den Frames bescheid + aCallMod.Modify( &aChgFmt, &aChgFmt ); + } + } + } + + if( aNew.Count() && aCallMod.GetDepends() ) + { + SwAttrSetChg aChgOld( aOld, aOld ); + SwAttrSetChg aChgNew( aNew, aNew ); + aCallMod.Modify( &aChgOld, &aChgNew ); // alle veraenderten werden verschickt + } + + // und die default-Formate wieder beim Object austragen + SwClient* pDep; + while( 0 != ( pDep = (SwClient*)aCallMod.GetDepends()) ) + aCallMod.Remove( pDep ); + + SetModified(); +} + + // Erfrage das Default Attribut in diesem Dokument. +const SfxPoolItem& SwDoc::GetDefault( sal_uInt16 nFmtHint ) const +{ + return GetAttrPool().GetDefaultItem( nFmtHint ); +} + +/* + * Loeschen der Formate + */ +void SwDoc::DelCharFmt(sal_uInt16 nFmt, sal_Bool bBroadcast) +{ + SwCharFmt * pDel = (*pCharFmtTbl)[nFmt]; + + if (bBroadcast) + BroadcastStyleOperation(pDel->GetName(), SFX_STYLE_FAMILY_CHAR, + SFX_STYLESHEET_ERASED); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = + new SwUndoCharFmtDelete(pDel, this); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + pCharFmtTbl->DeleteAndDestroy(nFmt); + + SetModified(); +} + +void SwDoc::DelCharFmt( SwCharFmt *pFmt, sal_Bool bBroadcast ) +{ + sal_uInt16 nFmt = pCharFmtTbl->GetPos( pFmt ); + ASSERT( USHRT_MAX != nFmt, "Fmt not found," ); + + DelCharFmt( nFmt, bBroadcast ); +} + +void SwDoc::DelFrmFmt( SwFrmFmt *pFmt, sal_Bool bBroadcast ) +{ + if( pFmt->ISA( SwTableBoxFmt ) || pFmt->ISA( SwTableLineFmt )) + { + ASSERT( !this, "Format steht nicht mehr im DocArray, " + "kann per delete geloescht werden" ); + delete pFmt; + } + else + { + + //Das Format muss in einem der beiden Arrays stehen, in welchem + //werden wir schon merken. + sal_uInt16 nPos; + if ( USHRT_MAX != ( nPos = pFrmFmtTbl->GetPos( pFmt )) ) + { + if (bBroadcast) + BroadcastStyleOperation(pFmt->GetName(), + SFX_STYLE_FAMILY_FRAME, + SFX_STYLESHEET_ERASED); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoFrmFmtDelete(pFmt, this); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + pFrmFmtTbl->DeleteAndDestroy( nPos ); + } + else + { + nPos = GetSpzFrmFmts()->GetPos( pFmt ); + ASSERT( nPos != USHRT_MAX, "FrmFmt not found." ); + if( USHRT_MAX != nPos ) + GetSpzFrmFmts()->DeleteAndDestroy( nPos ); + } + } +} + +void SwDoc::DelTblFrmFmt( SwTableFmt *pFmt ) +{ + sal_uInt16 nPos = pTblFrmFmtTbl->GetPos( pFmt ); + ASSERT( USHRT_MAX != nPos, "Fmt not found," ); + pTblFrmFmtTbl->DeleteAndDestroy( nPos ); +} + +/* + * Erzeugen der Formate + */ +SwFlyFrmFmt *SwDoc::MakeFlyFrmFmt( const String &rFmtName, + SwFrmFmt *pDerivedFrom ) +{ + SwFlyFrmFmt *pFmt = new SwFlyFrmFmt( GetAttrPool(), rFmtName, pDerivedFrom ); + GetSpzFrmFmts()->Insert(pFmt, GetSpzFrmFmts()->Count()); + SetModified(); + return pFmt; +} + +SwDrawFrmFmt *SwDoc::MakeDrawFrmFmt( const String &rFmtName, + SwFrmFmt *pDerivedFrom ) +{ + SwDrawFrmFmt *pFmt = new SwDrawFrmFmt( GetAttrPool(), rFmtName, pDerivedFrom); + GetSpzFrmFmts()->Insert(pFmt,GetSpzFrmFmts()->Count()); + SetModified(); + return pFmt; +} + + +sal_uInt16 SwDoc::GetTblFrmFmtCount(sal_Bool bUsed) const +{ + sal_uInt16 nCount = pTblFrmFmtTbl->Count(); + if(bUsed) + { + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + for ( sal_uInt16 i = nCount; i; ) + { + if((*pTblFrmFmtTbl)[--i]->GetInfo( aGetHt )) + + --nCount; + } + } + + return nCount; +} + + +SwFrmFmt& SwDoc::GetTblFrmFmt(sal_uInt16 nFmt, sal_Bool bUsed ) const +{ + sal_uInt16 nRemoved = 0; + if(bUsed) + { + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + for ( sal_uInt16 i = 0; i <= nFmt; i++ ) + { + while ( (*pTblFrmFmtTbl)[ i + nRemoved]->GetInfo( aGetHt )) + { + nRemoved++; + } + } + } + return *((*pTblFrmFmtTbl)[nRemoved + nFmt]); +} + +SwTableFmt* SwDoc::MakeTblFrmFmt( const String &rFmtName, + SwFrmFmt *pDerivedFrom ) +{ + SwTableFmt* pFmt = new SwTableFmt( GetAttrPool(), rFmtName, pDerivedFrom ); + pTblFrmFmtTbl->Insert( pFmt, pTblFrmFmtTbl->Count() ); + SetModified(); + + return pFmt; +} + +SwFrmFmt *SwDoc::MakeFrmFmt(const String &rFmtName, + SwFrmFmt *pDerivedFrom, + sal_Bool bBroadcast, sal_Bool bAuto) +{ + + SwFrmFmt *pFmt = new SwFrmFmt( GetAttrPool(), rFmtName, pDerivedFrom ); + + pFmt->SetAuto(bAuto); + pFrmFmtTbl->Insert( pFmt, pFrmFmtTbl->Count()); + SetModified(); + + if (bBroadcast) + { + BroadcastStyleOperation(rFmtName, SFX_STYLE_FAMILY_PARA, + SFX_STYLESHEET_CREATED); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoFrmFmtCreate(pFmt, pDerivedFrom, this); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + + return pFmt; +} + +SwFmt *SwDoc::_MakeFrmFmt(const String &rFmtName, + SwFmt *pDerivedFrom, + sal_Bool bBroadcast, sal_Bool bAuto) +{ + SwFrmFmt *pFrmFmt = dynamic_cast<SwFrmFmt*>(pDerivedFrom); + pFrmFmt = MakeFrmFmt( rFmtName, pFrmFmt, bBroadcast, bAuto ); + return dynamic_cast<SwFmt*>(pFrmFmt); +} + + +// --> OD 2005-01-13 #i40550# - add parameter <bAuto> - not relevant +SwCharFmt *SwDoc::MakeCharFmt( const String &rFmtName, + SwCharFmt *pDerivedFrom, + sal_Bool bBroadcast, + sal_Bool ) +// <-- +{ + SwCharFmt *pFmt = new SwCharFmt( GetAttrPool(), rFmtName, pDerivedFrom ); + pCharFmtTbl->Insert( pFmt, pCharFmtTbl->Count() ); + pFmt->SetAuto( sal_False ); + SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoCharFmtCreate(pFmt, pDerivedFrom, this); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if (bBroadcast) + { + BroadcastStyleOperation(rFmtName, SFX_STYLE_FAMILY_CHAR, + SFX_STYLESHEET_CREATED); + } + + return pFmt; +} + +SwFmt *SwDoc::_MakeCharFmt(const String &rFmtName, + SwFmt *pDerivedFrom, + sal_Bool bBroadcast, sal_Bool bAuto) +{ + SwCharFmt *pCharFmt = dynamic_cast<SwCharFmt*>(pDerivedFrom); + pCharFmt = MakeCharFmt( rFmtName, pCharFmt, bBroadcast, bAuto ); + return dynamic_cast<SwFmt*>(pCharFmt); +} + + +/* + * Erzeugen der FormatCollections + */ +// TXT +// --> OD 2005-01-13 #i40550# - add parameter <bAuto> - not relevant +SwTxtFmtColl* SwDoc::MakeTxtFmtColl( const String &rFmtName, + SwTxtFmtColl *pDerivedFrom, + sal_Bool bBroadcast, + sal_Bool ) +// <-- +{ + SwTxtFmtColl *pFmtColl = new SwTxtFmtColl( GetAttrPool(), rFmtName, + pDerivedFrom ); + pTxtFmtCollTbl->Insert(pFmtColl, pTxtFmtCollTbl->Count()); + pFmtColl->SetAuto( sal_False ); + SetModified(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoTxtFmtCollCreate(pFmtColl, pDerivedFrom, + this); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if (bBroadcast) + BroadcastStyleOperation(rFmtName, SFX_STYLE_FAMILY_PARA, + SFX_STYLESHEET_CREATED); + + return pFmtColl; +} + +SwFmt *SwDoc::_MakeTxtFmtColl(const String &rFmtName, + SwFmt *pDerivedFrom, + sal_Bool bBroadcast, sal_Bool bAuto) +{ + SwTxtFmtColl *pTxtFmtColl = dynamic_cast<SwTxtFmtColl*>(pDerivedFrom); + pTxtFmtColl = MakeTxtFmtColl( rFmtName, pTxtFmtColl, bBroadcast, bAuto ); + return dynamic_cast<SwFmt*>(pTxtFmtColl); +} + + +//FEATURE::CONDCOLL +SwConditionTxtFmtColl* SwDoc::MakeCondTxtFmtColl( const String &rFmtName, + SwTxtFmtColl *pDerivedFrom, + sal_Bool bBroadcast) +{ + SwConditionTxtFmtColl*pFmtColl = new SwConditionTxtFmtColl( GetAttrPool(), + rFmtName, pDerivedFrom ); + pTxtFmtCollTbl->Insert(pFmtColl, pTxtFmtCollTbl->Count()); + pFmtColl->SetAuto( sal_False ); + SetModified(); + + if (bBroadcast) + BroadcastStyleOperation(rFmtName, SFX_STYLE_FAMILY_PARA, + SFX_STYLESHEET_CREATED); + + return pFmtColl; +} +//FEATURE::CONDCOLL + +// GRF + +SwGrfFmtColl* SwDoc::MakeGrfFmtColl( const String &rFmtName, + SwGrfFmtColl *pDerivedFrom ) +{ + SwGrfFmtColl *pFmtColl = new SwGrfFmtColl( GetAttrPool(), rFmtName, + pDerivedFrom ); + pGrfFmtCollTbl->Insert( pFmtColl, pGrfFmtCollTbl->Count() ); + pFmtColl->SetAuto( sal_False ); + SetModified(); + return pFmtColl; +} + +void SwDoc::DelTxtFmtColl(sal_uInt16 nFmtColl, sal_Bool bBroadcast) +{ + ASSERT( nFmtColl, "Remove fuer Coll 0." ); + + // Wer hat die zu loeschende als Next + SwTxtFmtColl *pDel = (*pTxtFmtCollTbl)[nFmtColl]; + if( pDfltTxtFmtColl == pDel ) + return; // default nie loeschen !! + + if (bBroadcast) + BroadcastStyleOperation(pDel->GetName(), SFX_STYLE_FAMILY_PARA, + SFX_STYLESHEET_ERASED); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoTxtFmtCollDelete * pUndo = + new SwUndoTxtFmtCollDelete(pDel, this); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + // Die FmtColl austragen + pTxtFmtCollTbl->Remove(nFmtColl); + // Next korrigieren + pTxtFmtCollTbl->ForEach( 1, pTxtFmtCollTbl->Count(), + &SetTxtFmtCollNext, pDel ); + delete pDel; + SetModified(); +} + +void SwDoc::DelTxtFmtColl( SwTxtFmtColl *pColl, sal_Bool bBroadcast ) +{ + sal_uInt16 nFmt = pTxtFmtCollTbl->GetPos( pColl ); + ASSERT( USHRT_MAX != nFmt, "Collection not found," ); + DelTxtFmtColl( nFmt, bBroadcast ); +} + +sal_Bool lcl_SetTxtFmtColl( const SwNodePtr& rpNode, void* pArgs ) +{ + // ParaSetFmtColl * pPara = (ParaSetFmtColl*)pArgs; + SwCntntNode* pCNd = (SwCntntNode*)rpNode->GetTxtNode(); + if( pCNd ) + { + ParaRstFmt* pPara = (ParaRstFmt*)pArgs; + + SwTxtFmtColl* pFmt = static_cast<SwTxtFmtColl*>(pPara->pFmtColl); + if ( pPara->bReset ) + { + + if( pFmt->GetAttrOutlineLevel() == 0 && pPara ) + pPara->bKeepOutlineLevelAttr = true; + + lcl_RstAttr( pCNd, pPara ); + + // --> OD 2007-11-06 #i62675# + // --> OD 2008-04-15 #refactorlists# + // check, if paragraph style has changed + if ( pPara->bResetListAttrs && + pFmt != pCNd->GetFmtColl() && + pFmt->GetItemState( RES_PARATR_NUMRULE ) == SFX_ITEM_SET ) + { + // --> OD 2009-09-07 #b6876367# + // Check, if the list style of the paragraph will change. + bool bChangeOfListStyleAtParagraph( true ); + SwTxtNode* pTNd( dynamic_cast<SwTxtNode*>(pCNd) ); + ASSERT( pTNd, + "<lcl_SetTxtFmtColl(..)> - text node expected -> crash" ); + { + SwNumRule* pNumRuleAtParagraph( pTNd->GetNumRule() ); + if ( pNumRuleAtParagraph ) + { + const SwNumRuleItem& rNumRuleItemAtParagraphStyle = + pFmt->GetNumRule(); + if ( rNumRuleItemAtParagraphStyle.GetValue() == + pNumRuleAtParagraph->GetName() ) + { + bChangeOfListStyleAtParagraph = false; + } + } + } + + if ( bChangeOfListStyleAtParagraph ) + { + // --> OD 2008-04-08 #refactorlists# + std::auto_ptr< SwRegHistory > pRegH; + if ( pPara->pHistory ) + { + pRegH.reset( new SwRegHistory( pTNd, *pTNd, pPara->pHistory ) ); + } + + pCNd->ResetAttr( RES_PARATR_NUMRULE ); + + // reset all list attributes + pCNd->ResetAttr( RES_PARATR_LIST_LEVEL ); + pCNd->ResetAttr( RES_PARATR_LIST_ISRESTART ); + pCNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE ); + pCNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED ); + pCNd->ResetAttr( RES_PARATR_LIST_ID ); + } + // <-- + } + // <-- + } + + // erst in die History aufnehmen, damit ggfs. alte Daten + // gesichert werden koennen + if( pPara->pHistory ) + pPara->pHistory->Add( pCNd->GetFmtColl(), pCNd->GetIndex(), + ND_TEXTNODE ); + + pCNd->ChgFmtColl( pFmt ); + + pPara->nWhich++; + } + return sal_True; +} + +sal_Bool SwDoc::SetTxtFmtColl( const SwPaM &rRg, + SwTxtFmtColl *pFmt, + bool bReset, + bool bResetListAttrs ) +{ + SwDataChanged aTmp( rRg, 0 ); + const SwPosition *pStt = rRg.Start(), *pEnd = rRg.End(); + SwHistory* pHst = 0; + sal_Bool bRet = sal_True; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + // --> OD 2008-04-15 #refactorlists# + SwUndoFmtColl* pUndo = new SwUndoFmtColl( rRg, pFmt, + bReset, + bResetListAttrs ); + // <-- + pHst = pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + ParaRstFmt aPara( pStt, pEnd, pHst ); + aPara.pFmtColl = pFmt; + aPara.bReset = bReset; + // --> OD 2007-11-06 #i62675# + aPara.bResetListAttrs = bResetListAttrs; + // <-- + + GetNodes().ForEach( pStt->nNode.GetIndex(), pEnd->nNode.GetIndex()+1, + lcl_SetTxtFmtColl, &aPara ); + if( !aPara.nWhich ) + bRet = sal_False; // keinen gueltigen Node gefunden + + if( bRet ) + SetModified(); + return bRet; +} + + +// ---- Kopiere die Formate in sich selbst (SwDoc) ---------------------- + +SwFmt* SwDoc::CopyFmt( const SwFmt& rFmt, + const SvPtrarr& rFmtArr, + FNCopyFmt fnCopyFmt, const SwFmt& rDfltFmt ) +{ + // kein-Autoformat || default Format || Collection-Format + // dann suche danach. + if( !rFmt.IsAuto() || !rFmt.GetRegisteredIn() ) + for( sal_uInt16 n = 0; n < rFmtArr.Count(); n++ ) + { + // ist die Vorlage schon im Doc vorhanden ?? + if( ((SwFmt*)rFmtArr[n])->GetName().Equals( rFmt.GetName() )) + return (SwFmt*)rFmtArr[n]; + } + + // suche erstmal nach dem "Parent" + SwFmt* pParent = (SwFmt*)&rDfltFmt; + if( rFmt.DerivedFrom() && pParent != rFmt.DerivedFrom() ) + pParent = CopyFmt( *rFmt.DerivedFrom(), rFmtArr, + fnCopyFmt, rDfltFmt ); + + // erzeuge das Format und kopiere die Attribute + // --> OD 2005-01-13 #i40550# + SwFmt* pNewFmt = (this->*fnCopyFmt)( rFmt.GetName(), pParent, sal_False, sal_True ); + // <-- + pNewFmt->SetAuto( rFmt.IsAuto() ); + pNewFmt->CopyAttrs( rFmt, sal_True ); // kopiere Attribute + + pNewFmt->SetPoolFmtId( rFmt.GetPoolFmtId() ); + pNewFmt->SetPoolHelpId( rFmt.GetPoolHelpId() ); + + // HelpFile-Id immer auf dflt setzen !! + pNewFmt->SetPoolHlpFileId( UCHAR_MAX ); + + return pNewFmt; +} + + +// ---- kopiere das Frame-Format -------- +SwFrmFmt* SwDoc::CopyFrmFmt( const SwFrmFmt& rFmt ) +{ + + return (SwFrmFmt*)CopyFmt( rFmt, *GetFrmFmts(), &SwDoc::_MakeFrmFmt, + *GetDfltFrmFmt() ); +} + +// ---- kopiere das Char-Format -------- +SwCharFmt* SwDoc::CopyCharFmt( const SwCharFmt& rFmt ) +{ + return (SwCharFmt*)CopyFmt( rFmt, *GetCharFmts(), + &SwDoc::_MakeCharFmt, + *GetDfltCharFmt() ); +} + + +// --- Kopiere TextNodes ---- + +SwTxtFmtColl* SwDoc::CopyTxtColl( const SwTxtFmtColl& rColl ) +{ + SwTxtFmtColl* pNewColl = FindTxtFmtCollByName( rColl.GetName() ); + if( pNewColl ) + return pNewColl; + + // suche erstmal nach dem "Parent" + SwTxtFmtColl* pParent = pDfltTxtFmtColl; + if( pParent != rColl.DerivedFrom() ) + pParent = CopyTxtColl( *(SwTxtFmtColl*)rColl.DerivedFrom() ); + + +//FEATURE::CONDCOLL + if( RES_CONDTXTFMTCOLL == rColl.Which() ) + { + pNewColl = new SwConditionTxtFmtColl( GetAttrPool(), rColl.GetName(), + pParent); + pTxtFmtCollTbl->Insert( pNewColl, pTxtFmtCollTbl->Count() ); + pNewColl->SetAuto( sal_False ); + SetModified(); + + // Kopiere noch die Bedingungen + ((SwConditionTxtFmtColl*)pNewColl)->SetConditions( + ((SwConditionTxtFmtColl&)rColl).GetCondColls() ); + } + else +//FEATURE::CONDCOLL + pNewColl = MakeTxtFmtColl( rColl.GetName(), pParent ); + + // kopiere jetzt noch die Auto-Formate oder kopiere die Attribute + pNewColl->CopyAttrs( rColl, sal_True ); + + // setze noch den Outline-Level + //if( NO_NUMBERING != rColl.GetOutlineLevel() ) //#outline level,zhaojianwei + // pNewColl->SetOutlineLevel( rColl.GetOutlineLevel() ); + if(rColl.IsAssignedToListLevelOfOutlineStyle()) + pNewColl->AssignToListLevelOfOutlineStyle(rColl.GetAssignedOutlineStyleLevel());//<-end,zhaojianwei + //<-end + pNewColl->SetPoolFmtId( rColl.GetPoolFmtId() ); + pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() ); + + // HelpFile-Id immer auf dflt setzen !! + pNewColl->SetPoolHlpFileId( UCHAR_MAX ); + + if( &rColl.GetNextTxtFmtColl() != &rColl ) + pNewColl->SetNextTxtFmtColl( *CopyTxtColl( rColl.GetNextTxtFmtColl() )); + + // ggfs. die NumRule erzeugen + if( this != rColl.GetDoc() ) + { + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pNewColl->GetItemState( RES_PARATR_NUMRULE, + sal_False, &pItem )) + { + const SwNumRule* pRule; + const String& rName = ((SwNumRuleItem*)pItem)->GetValue(); + if( rName.Len() && + 0 != ( pRule = rColl.GetDoc()->FindNumRulePtr( rName )) && + !pRule->IsAutoRule() ) + { + SwNumRule* pDestRule = FindNumRulePtr( rName ); + if( pDestRule ) + pDestRule->SetInvalidRule( sal_True ); + else + MakeNumRule( rName, pRule ); + } + } + } + return pNewColl; +} + +// --- Kopiere GrafikNodes ---- + +SwGrfFmtColl* SwDoc::CopyGrfColl( const SwGrfFmtColl& rColl ) +{ + SwGrfFmtColl* pNewColl = FindGrfFmtCollByName( rColl.GetName() ); + if( pNewColl ) + return pNewColl; + + // suche erstmal nach dem "Parent" + SwGrfFmtColl* pParent = pDfltGrfFmtColl; + if( pParent != rColl.DerivedFrom() ) + pParent = CopyGrfColl( *(SwGrfFmtColl*)rColl.DerivedFrom() ); + + // falls nicht, so kopiere sie + pNewColl = MakeGrfFmtColl( rColl.GetName(), pParent ); + + // noch die Attribute kopieren + pNewColl->CopyAttrs( rColl ); + + pNewColl->SetPoolFmtId( rColl.GetPoolFmtId() ); + pNewColl->SetPoolHelpId( rColl.GetPoolHelpId() ); + + // HelpFile-Id immer auf dflt setzen !! + pNewColl->SetPoolHlpFileId( UCHAR_MAX ); + + return pNewColl; +} + +SwPageDesc* lcl_FindPageDesc( const SwPageDescs& rArr, const String& rName ) +{ + for( sal_uInt16 n = rArr.Count(); n; ) + { + SwPageDesc* pDesc = rArr[ --n ]; + if( pDesc->GetName() == rName ) + return pDesc; + } + return 0; +} + +void SwDoc::CopyFmtArr( const SvPtrarr& rSourceArr, + SvPtrarr& rDestArr, + FNCopyFmt fnCopyFmt, + SwFmt& rDfltFmt ) +{ + sal_uInt16 nSrc; + SwFmt* pSrc, *pDest; + + // 1. Schritt alle Formate anlegen (das 0. ueberspringen - Default!) + for( nSrc = rSourceArr.Count(); nSrc > 1; ) + { + pSrc = (SwFmt*)rSourceArr[ --nSrc ]; + if( pSrc->IsDefault() || pSrc->IsAuto() ) + continue; + + if( 0 == FindFmtByName( rDestArr, pSrc->GetName() ) ) + { + if( RES_CONDTXTFMTCOLL == pSrc->Which() ) + MakeCondTxtFmtColl( pSrc->GetName(), (SwTxtFmtColl*)&rDfltFmt ); + else + // --> OD 2005-01-13 #i40550# + (this->*fnCopyFmt)( pSrc->GetName(), &rDfltFmt, sal_False, sal_True ); + // <-- + } + } + + // 2. Schritt alle Attribute kopieren, richtige Parents setzen + for( nSrc = rSourceArr.Count(); nSrc > 1; ) + { + pSrc = (SwFmt*)rSourceArr[ --nSrc ]; + if( pSrc->IsDefault() || pSrc->IsAuto() ) + continue; + + pDest = FindFmtByName( rDestArr, pSrc->GetName() ); + pDest->SetAuto( sal_False ); +// pDest->ResetAllAttr(); +// pDest->CopyAttrs( *pSrc, sal_True ); // kopiere Attribute +//JP 19.02.96: ist so wohl optimaler - loest ggfs. kein Modify aus! + pDest->DelDiffs( *pSrc ); + // --> OD 2009-03-23 #i94285# + // copy existing <SwFmtPageDesc> instance, before copying attributes +// pDest->SetFmtAttr( pSrc->GetAttrSet() ); // kopiere Attribute + //JP 18.08.98: Bug 55115 - copy PageDescAttribute in this case + const SfxPoolItem* pItem; + if( &GetAttrPool() != pSrc->GetAttrSet().GetPool() && + SFX_ITEM_SET == pSrc->GetAttrSet().GetItemState( + RES_PAGEDESC, sal_False, &pItem ) && + ((SwFmtPageDesc*)pItem)->GetPageDesc() ) + { + SwFmtPageDesc aPageDesc( *(SwFmtPageDesc*)pItem ); + const String& rNm = aPageDesc.GetPageDesc()->GetName(); + SwPageDesc* pPageDesc = ::lcl_FindPageDesc( aPageDescs, rNm ); + if( !pPageDesc ) + { + pPageDesc = aPageDescs[ MakePageDesc( rNm ) ]; + } + pPageDesc->Add( &aPageDesc ); +// pDest->SetFmtAttr( aPageDesc ); + SwAttrSet aTmpAttrSet( pSrc->GetAttrSet() ); + aTmpAttrSet.Put( aPageDesc ); + pDest->SetFmtAttr( aTmpAttrSet ); + } + else + { + pDest->SetFmtAttr( pSrc->GetAttrSet() ); + } + // <-- + + pDest->SetPoolFmtId( pSrc->GetPoolFmtId() ); + pDest->SetPoolHelpId( pSrc->GetPoolHelpId() ); + + // HelpFile-Id immer auf dflt setzen !! + pDest->SetPoolHlpFileId( UCHAR_MAX ); + + if( pSrc->DerivedFrom() ) + pDest->SetDerivedFrom( FindFmtByName( rDestArr, + pSrc->DerivedFrom()->GetName() ) ); + if( RES_TXTFMTCOLL == pSrc->Which() || + RES_CONDTXTFMTCOLL == pSrc->Which() ) + { + SwTxtFmtColl* pSrcColl = (SwTxtFmtColl*)pSrc, + * pDstColl = (SwTxtFmtColl*)pDest; + if( &pSrcColl->GetNextTxtFmtColl() != pSrcColl ) + pDstColl->SetNextTxtFmtColl( *(SwTxtFmtColl*)FindFmtByName( + rDestArr, pSrcColl->GetNextTxtFmtColl().GetName() ) ); + + // setze noch den Outline-Level + //if( NO_NUMBERING != pSrcColl->GetOutlineLevel() ) //#outline level,zhaojianwei + // pDstColl->SetOutlineLevel( pSrcColl->GetOutlineLevel() ); + if(pSrcColl->IsAssignedToListLevelOfOutlineStyle()) + pDstColl->AssignToListLevelOfOutlineStyle(pSrcColl->GetAssignedOutlineStyleLevel());//<-end,zhaojianwei + //<-end + +//FEATURE::CONDCOLL + if( RES_CONDTXTFMTCOLL == pSrc->Which() ) + // Kopiere noch die Bedingungen + // aber erst die alten loeschen! + ((SwConditionTxtFmtColl*)pDstColl)->SetConditions( + ((SwConditionTxtFmtColl*)pSrc)->GetCondColls() ); +//FEATURE::CONDCOLL + } + } +} + +void SwDoc::CopyPageDescHeaderFooterImpl( bool bCpyHeader, + const SwFrmFmt& rSrcFmt, SwFrmFmt& rDestFmt ) +{ + // jetzt noch Header-/Footer-Attribute richtig behandeln + // Contenten Nodes Dokumentuebergreifend kopieren! + sal_uInt16 nAttr = static_cast<sal_uInt16>( bCpyHeader ? RES_HEADER : RES_FOOTER ); + const SfxPoolItem* pItem; + if( SFX_ITEM_SET != rSrcFmt.GetAttrSet().GetItemState( nAttr, sal_False, &pItem )) + return ; + + // Im Header steht noch der Verweis auf das Format aus dem + // anderen Document!! + SfxPoolItem* pNewItem = pItem->Clone(); + + SwFrmFmt* pOldFmt; + if( bCpyHeader ) + pOldFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); + else + pOldFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); + + if( pOldFmt ) + { + SwFrmFmt* pNewFmt = new SwFrmFmt( GetAttrPool(), "CpyDesc", + GetDfltFrmFmt() ); + pNewFmt->CopyAttrs( *pOldFmt, sal_True ); + + if( SFX_ITEM_SET == pNewFmt->GetAttrSet().GetItemState( + RES_CNTNT, sal_False, &pItem )) + { + SwFmtCntnt* pCntnt = (SwFmtCntnt*)pItem; + if( pCntnt->GetCntntIdx() ) + { + SwNodeIndex aTmpIdx( GetNodes().GetEndOfAutotext() ); + const SwNodes& rSrcNds = rSrcFmt.GetDoc()->GetNodes(); + SwStartNode* pSttNd = GetNodes().MakeEmptySection( aTmpIdx, + bCpyHeader + ? SwHeaderStartNode + : SwFooterStartNode ); + const SwNode& rCSttNd = pCntnt->GetCntntIdx()->GetNode(); + SwNodeRange aRg( rCSttNd, 0, *rCSttNd.EndOfSectionNode() ); + aTmpIdx = *pSttNd->EndOfSectionNode(); + rSrcNds._Copy( aRg, aTmpIdx ); + aTmpIdx = *pSttNd; + rSrcFmt.GetDoc()->CopyFlyInFlyImpl( aRg, 0, aTmpIdx ); + pNewFmt->SetFmtAttr( SwFmtCntnt( pSttNd )); + } + else + pNewFmt->ResetFmtAttr( RES_CNTNT ); + } + if( bCpyHeader ) + pNewFmt->Add( (SwFmtHeader*)pNewItem ); + else + pNewFmt->Add( (SwFmtFooter*)pNewItem ); + rDestFmt.SetFmtAttr( *pNewItem ); + } + delete pNewItem; +} + +void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc, + sal_Bool bCopyPoolIds ) +{ + sal_Bool bNotifyLayout = sal_False; + + rDstDesc.SetLandscape( rSrcDesc.GetLandscape() ); + rDstDesc.SetNumType( rSrcDesc.GetNumType() ); + if( rDstDesc.ReadUseOn() != rSrcDesc.ReadUseOn() ) + { + rDstDesc.WriteUseOn( rSrcDesc.ReadUseOn() ); + bNotifyLayout = sal_True; + } + + if( bCopyPoolIds ) + { + rDstDesc.SetPoolFmtId( rSrcDesc.GetPoolFmtId() ); + rDstDesc.SetPoolHelpId( rSrcDesc.GetPoolHelpId() ); + // HelpFile-Id immer auf dflt setzen !! + rDstDesc.SetPoolHlpFileId( UCHAR_MAX ); + } + + if( rSrcDesc.GetFollow() != &rSrcDesc ) + { + SwPageDesc* pFollow = ::lcl_FindPageDesc( aPageDescs, + rSrcDesc.GetFollow()->GetName() ); + if( !pFollow ) + { + // dann mal kopieren + sal_uInt16 nPos = MakePageDesc( rSrcDesc.GetFollow()->GetName() ); + pFollow = aPageDescs[ nPos ]; + CopyPageDesc( *rSrcDesc.GetFollow(), *pFollow ); + } + rDstDesc.SetFollow( pFollow ); + bNotifyLayout = sal_True; + } + + // die Header/Footer-Attribute werden gesondert kopiert, die Content- + // Sections muessen vollstaendig mitgenommen werden! + { + SfxItemSet aAttrSet( rSrcDesc.GetMaster().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetMaster().DelDiffs( aAttrSet ); + rDstDesc.GetMaster().SetFmtAttr( aAttrSet ); + + aAttrSet.ClearItem(); + aAttrSet.Put( rSrcDesc.GetLeft().GetAttrSet() ); + aAttrSet.ClearItem( RES_HEADER ); + aAttrSet.ClearItem( RES_FOOTER ); + + rDstDesc.GetLeft().DelDiffs( aAttrSet ); + rDstDesc.GetLeft().SetFmtAttr( aAttrSet ); + } + + CopyHeader( rSrcDesc.GetMaster(), rDstDesc.GetMaster() ); + CopyFooter( rSrcDesc.GetMaster(), rDstDesc.GetMaster() ); + if( !rDstDesc.IsHeaderShared() ) + CopyHeader( rSrcDesc.GetLeft(), rDstDesc.GetLeft() ); + else + rDstDesc.GetLeft().SetFmtAttr( rDstDesc.GetMaster().GetHeader() ); + + if( !rDstDesc.IsFooterShared() ) + CopyFooter( rSrcDesc.GetLeft(), rDstDesc.GetLeft() ); + else + rDstDesc.GetLeft().SetFmtAttr( rDstDesc.GetMaster().GetFooter() ); + + if( bNotifyLayout && GetRootFrm() ) + //Layot benachrichtigen! + GetRootFrm()->CheckPageDescs( (SwPageFrm*)GetRootFrm()->Lower() ); + + //Wenn sich FussnotenInfo veraendert, so werden die Seiten + //angetriggert. + if( !(rDstDesc.GetFtnInfo() == rSrcDesc.GetFtnInfo()) ) + { + rDstDesc.SetFtnInfo( rSrcDesc.GetFtnInfo() ); + SwMsgPoolItem aInfo( RES_PAGEDESC_FTNINFO ); + { + SwClientIter aIter( rDstDesc.GetMaster() ); + for( SwClient* pLast = aIter.First(TYPE(SwFrm)); pLast; + pLast = aIter.Next() ) + pLast->Modify( &aInfo, 0 ); + } + { + SwClientIter aIter( rDstDesc.GetLeft() ); + for( SwClient* pLast = aIter.First(TYPE(SwFrm)); pLast; + pLast = aIter.Next() ) + pLast->Modify( &aInfo, 0 ); + } + } +} + +void SwDoc::ReplaceStyles( SwDoc& rSource ) +{ + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + CopyFmtArr( *rSource.pCharFmtTbl, *pCharFmtTbl, + &SwDoc::_MakeCharFmt, *pDfltCharFmt ); + CopyFmtArr( *rSource.pFrmFmtTbl, *pFrmFmtTbl, + &SwDoc::_MakeFrmFmt, *pDfltFrmFmt ); + CopyFmtArr( *rSource.pTxtFmtCollTbl, *pTxtFmtCollTbl, + &SwDoc::_MakeTxtFmtColl, *pDfltTxtFmtColl ); + + // und jetzt noch die Seiten-Vorlagen + sal_uInt16 nCnt = rSource.aPageDescs.Count(); + if( nCnt ) + { + // ein anderes Doc -> Numberformatter muessen gemergt werden + SwTblNumFmtMerge aTNFM( rSource, *this ); + + // 1. Schritt alle Formate anlegen (das 0. ueberspringen - Default!) + while( nCnt ) + { + SwPageDesc *pSrc = rSource.aPageDescs[ --nCnt ]; + if( 0 == ::lcl_FindPageDesc( aPageDescs, pSrc->GetName() ) ) + MakePageDesc( pSrc->GetName() ); + } + + // 2. Schritt alle Attribute kopieren, richtige Parents setzen + for( nCnt = rSource.aPageDescs.Count(); nCnt; ) + { + SwPageDesc *pSrc = rSource.aPageDescs[ --nCnt ]; + CopyPageDesc( *pSrc, *::lcl_FindPageDesc( aPageDescs, pSrc->GetName() )); + } + } + + //JP 08.04.99: und dann sind da noch die Numerierungs-Vorlagen + nCnt = rSource.GetNumRuleTbl().Count(); + if( nCnt ) + { + const SwNumRuleTbl& rArr = rSource.GetNumRuleTbl(); + for( sal_uInt16 n = 0; n < nCnt; ++n ) + { + const SwNumRule& rR = *rArr[ n ]; + if( !rR.IsAutoRule() ) + { + SwNumRule* pNew = FindNumRulePtr( rR.GetName()); + if( pNew ) + pNew->CopyNumRule( this, rR ); + else + MakeNumRule( rR.GetName(), &rR ); + } + } + } + + if (undoGuard.UndoWasEnabled()) + { + // nodes array was modified! + GetIDocumentUndoRedo().DelAllUndoObj(); + } + + SetModified(); +} + +SwFmt* SwDoc::FindFmtByName( const SvPtrarr& rFmtArr, + const String& rName ) const +{ + SwFmt* pFnd = 0; + for( sal_uInt16 n = 0; n < rFmtArr.Count(); n++ ) + { + // ist die Vorlage schon im Doc vorhanden ?? + if( ((SwFmt*)rFmtArr[n])->GetName() == rName ) + { + pFnd = (SwFmt*)rFmtArr[n]; + break; + } + } + return pFnd; +} + +void SwDoc::MoveLeftMargin( const SwPaM& rPam, sal_Bool bRight, sal_Bool bModulus ) +{ + SwHistory* pHistory = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoMoveLeftMargin* pUndo = new SwUndoMoveLeftMargin( rPam, bRight, + bModulus ); + pHistory = &pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + + const SvxTabStopItem& rTabItem = (SvxTabStopItem&)GetDefault( RES_PARATR_TABSTOP ); + sal_uInt16 nDefDist = rTabItem.Count() ? + static_cast<sal_uInt16>(rTabItem[0].GetTabPos()) : 1134; + const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End(); + SwNodeIndex aIdx( rStt.nNode ); + while( aIdx <= rEnd.nNode ) + { + SwTxtNode* pTNd = aIdx.GetNode().GetTxtNode(); + if( pTNd ) + { + SvxLRSpaceItem aLS( (SvxLRSpaceItem&)pTNd->SwCntntNode::GetAttr( RES_LR_SPACE ) ); + + // --> FME 2008-09-16 #i93873# See also lcl_MergeListLevelIndentAsLRSpaceItem in thints.cxx + if ( pTNd->AreListLevelIndentsApplicable() ) + { + const SwNumRule* pRule = pTNd->GetNumRule(); + if ( pRule ) + { + const int nListLevel = pTNd->GetActualListLevel(); + if ( nListLevel >= 0 ) + { + const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(nListLevel)); + if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aLS.SetTxtLeft( rFmt.GetIndentAt() ); + aLS.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) ); + } + } + } + } + + long nNext = aLS.GetTxtLeft(); + if( bModulus ) + nNext = ( nNext / nDefDist ) * nDefDist; + + if( bRight ) + nNext += nDefDist; + else + nNext -= nDefDist; + + aLS.SetTxtLeft( nNext ); + + SwRegHistory aRegH( pTNd, *pTNd, pHistory ); + pTNd->SetAttr( aLS ); + } + aIdx++; + } + SetModified(); +} + +sal_Bool SwDoc::DontExpandFmt( const SwPosition& rPos, sal_Bool bFlag ) +{ + sal_Bool bRet = sal_False; + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + if( pTxtNd ) + { + bRet = pTxtNd->DontExpandFmt( rPos.nContent, bFlag ); + if( bRet && GetIDocumentUndoRedo().DoesUndo() ) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoDontExpandFmt(rPos) ); + } + } + return bRet; +} + +SwTableBoxFmt* SwDoc::MakeTableBoxFmt() +{ + SwTableBoxFmt* pFmt = new SwTableBoxFmt( GetAttrPool(), aEmptyStr, + pDfltFrmFmt ); + SetModified(); + return pFmt; +} + +SwTableLineFmt* SwDoc::MakeTableLineFmt() +{ + SwTableLineFmt* pFmt = new SwTableLineFmt( GetAttrPool(), aEmptyStr, + pDfltFrmFmt ); + SetModified(); + return pFmt; +} + +void SwDoc::_CreateNumberFormatter() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLog, "SW", "JP93722", "SwDoc::_CreateNumberFormatter" ); + + ASSERT( !pNumberFormatter, "ist doch schon vorhanden" ); + + + LanguageType eLang = LANGUAGE_SYSTEM; //System::GetLanguage(); +/* ((const SvxLanguageItem&)GetAttrPool(). + GetDefaultItem( RES_CHRATR_LANGUAGE )).GetLanguage(); +*/ + Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + pNumberFormatter = new SvNumberFormatter( xMSF, eLang ); + pNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT_INTL ); + pNumberFormatter->SetYear2000(static_cast<sal_uInt16>(::utl::MiscCfg().GetYear2000())); + +} + +SwTblNumFmtMerge::SwTblNumFmtMerge( const SwDoc& rSrc, SwDoc& rDest ) + : pNFmt( 0 ) +{ + // ein anderes Doc -> Numberformatter muessen gemergt werden + SvNumberFormatter* pN; + if( &rSrc != &rDest && 0 != ( pN = ((SwDoc&)rSrc).GetNumberFormatter( sal_False ) )) + ( pNFmt = rDest.GetNumberFormatter( sal_True ))->MergeFormatter( *pN ); + + if( &rSrc != &rDest ) + ((SwGetRefFieldType*)rSrc.GetSysFldType( RES_GETREFFLD ))-> + MergeWithOtherDoc( rDest ); +} + +SwTblNumFmtMerge::~SwTblNumFmtMerge() +{ + if( pNFmt ) + pNFmt->ClearMergeTable(); +} + + +void SwDoc::SetTxtFmtCollByAutoFmt( const SwPosition& rPos, sal_uInt16 nPoolId, + const SfxItemSet* pSet ) +{ + SwPaM aPam( rPos ); + SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode(); + + if( mbIsAutoFmtRedline && pTNd ) + { + // dann das Redline Object anlegen + const SwTxtFmtColl& rColl = *pTNd->GetTxtColl(); + SwRedline* pRedl = new SwRedline( nsRedlineType_t::REDLINE_FMTCOLL, aPam ); + pRedl->SetMark(); + + // interressant sind nur die Items, die vom Set NICHT wieder + // in den Node gesetzt werden. Also muss man die Differenz nehmen + SwRedlineExtraData_FmtColl aExtraData( rColl.GetName(), + rColl.GetPoolFmtId() ); + if( pSet && pTNd->HasSwAttrSet() ) + { + SfxItemSet aTmp( *pTNd->GetpSwAttrSet() ); + aTmp.Differentiate( *pSet ); + // das Adjust Item behalten wir extra + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pTNd->GetpSwAttrSet()->GetItemState( + RES_PARATR_ADJUST, sal_False, &pItem )) + aTmp.Put( *pItem ); + aExtraData.SetItemSet( aTmp ); + } + pRedl->SetExtraData( &aExtraData ); + +// !!!!!!!!! Undo fehlt noch !!!!!!!!!!!!!!!!!! + AppendRedline( pRedl, true ); + } + + SetTxtFmtColl( aPam, GetTxtCollFromPool( nPoolId ) ); + + if( pSet && pTNd && pSet->Count() ) + { + aPam.SetMark(); + aPam.GetMark()->nContent.Assign( pTNd, pTNd->GetTxt().Len() ); + InsertItemSet( aPam, *pSet, 0 ); + } +} + +void SwDoc::SetFmtItemByAutoFmt( const SwPaM& rPam, const SfxItemSet& rSet ) +{ + SwTxtNode* pTNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + + RedlineMode_t eOld = GetRedlineMode(); + + if( mbIsAutoFmtRedline && pTNd ) + { + // dann das Redline Object anlegen + SwRedline* pRedl = new SwRedline( nsRedlineType_t::REDLINE_FORMAT, rPam ); + if( !pRedl->HasMark() ) + pRedl->SetMark(); + + // interressant sind nur die Items, die vom Set NICHT wieder + // in den Node gesetzt werden. Also muss man die Differenz nehmen + SwRedlineExtraData_Format aExtraData( rSet ); + +/* + if( pSet && pTNd->HasSwAttrSet() ) + { + SfxItemSet aTmp( *pTNd->GetpSwAttrSet() ); + aTmp.Differentiate( *pSet ); + // das Adjust Item behalten wir extra + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pTNd->GetpSwAttrSet()->GetItemState( + RES_PARATR_ADJUST, sal_False, &pItem )) + aTmp.Put( *pItem ); + aExtraData.SetItemSet( aTmp ); + } +*/ + pRedl->SetExtraData( &aExtraData ); + +// !!!!!!!!! Undo fehlt noch !!!!!!!!!!!!!!!!!! + AppendRedline( pRedl, true ); + + SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + } + + InsertItemSet( rPam, rSet, nsSetAttrMode::SETATTR_DONTEXPAND ); + SetRedlineMode_intern( eOld ); +} + +void SwDoc::ChgFmt(SwFmt & rFmt, const SfxItemSet & rSet) +{ + if (GetIDocumentUndoRedo().DoesUndo()) + { + // copying <rSet> to <aSet> + SfxItemSet aSet(rSet); + // remove from <aSet> all items, which are already set at the format + aSet.Differentiate(rFmt.GetAttrSet()); + // <aSet> contains now all *new* items for the format + + // copying current format item set to <aOldSet> + SfxItemSet aOldSet(rFmt.GetAttrSet()); + // insert new items into <aOldSet> + aOldSet.Put(aSet); + // invalidate all new items in <aOldSet> in order to clear these items, + // if the undo action is triggered. + { + SfxItemIter aIter(aSet); + + const SfxPoolItem * pItem = aIter.FirstItem(); + while (pItem != NULL) + { + aOldSet.InvalidateItem(pItem->Which()); + + pItem = aIter.NextItem(); + } + } + + SwUndo * pUndo = new SwUndoFmtAttr(aOldSet, rFmt); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + rFmt.SetFmtAttr(rSet); +} + +void SwDoc::RenameFmt(SwFmt & rFmt, const String & sNewName, + sal_Bool bBroadcast) +{ + SfxStyleFamily eFamily = SFX_STYLE_FAMILY_ALL; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = NULL; + + switch (rFmt.Which()) + { + case RES_CHRFMT: + pUndo = new SwUndoRenameCharFmt(rFmt.GetName(), sNewName, this); + eFamily = SFX_STYLE_FAMILY_PARA; + break; + case RES_TXTFMTCOLL: + pUndo = new SwUndoRenameFmtColl(rFmt.GetName(), sNewName, this); + eFamily = SFX_STYLE_FAMILY_CHAR; + break; + case RES_FRMFMT: + pUndo = new SwUndoRenameFrmFmt(rFmt.GetName(), sNewName, this); + eFamily = SFX_STYLE_FAMILY_FRAME; + break; + + default: + break; + } + + if (pUndo) + { + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + + rFmt.SetName(sNewName); + + if (bBroadcast) + BroadcastStyleOperation(sNewName, eFamily, SFX_STYLESHEET_MODIFIED); +} + +// --> OD 2006-09-27 #i69627# +namespace docfunc +{ + bool HasOutlineStyleToBeWrittenAsNormalListStyle( SwDoc& rDoc ) + { + // If a parent paragraph style of one of the parargraph styles, which + // are assigned to the list levels of the outline style, has a list style + // set or inherits a list style from its parent style, the outline style + // has to be written as a normal list style to the OpenDocument file + // format or the OpenOffice.org file format. + bool bRet( false ); + + const SwTxtFmtColls* pTxtFmtColls( rDoc.GetTxtFmtColls() ); + if ( pTxtFmtColls ) + { + const sal_uInt16 nCount = pTxtFmtColls->Count(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + SwTxtFmtColl* pTxtFmtColl = (*pTxtFmtColls)[i]; + + if ( pTxtFmtColl->IsDefault() || + // pTxtFmtColl->GetOutlineLevel() == NO_NUMBERING ) //#outline level,zhaojianwei + ! pTxtFmtColl->IsAssignedToListLevelOfOutlineStyle() ) //<-end,zhaojianwei + { + continue; + } + + const SwTxtFmtColl* pParentTxtFmtColl = + dynamic_cast<const SwTxtFmtColl*>( pTxtFmtColl->DerivedFrom()); + if ( !pParentTxtFmtColl ) + continue; + + if ( SFX_ITEM_SET == pParentTxtFmtColl->GetItemState( RES_PARATR_NUMRULE ) ) + { + // --> OD 2009-11-12 #i106218# + // consider that the outline style is set + const SwNumRuleItem& rDirectItem = pParentTxtFmtColl->GetNumRule(); + if ( rDirectItem.GetValue() != rDoc.GetOutlineNumRule()->GetName() ) + { + bRet = true; + break; + } + // <-- + } + } + + } + return bRet; + } +} +// <-- diff --git a/sw/source/core/doc/docftn.cxx b/sw/source/core/doc/docftn.cxx new file mode 100644 index 000000000000..80798546d041 --- /dev/null +++ b/sw/source/core/doc/docftn.cxx @@ -0,0 +1,505 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <ftnidx.hxx> +#include <rootfrm.hxx> +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <pam.hxx> +#include <pagedesc.hxx> +#include <charfmt.hxx> +#include <UndoAttribute.hxx> +#include <hints.hxx> +#include <rolbck.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <ndtxt.hxx> +#include <poolfmt.hxx> +#include <ftninfo.hxx> + +/*********************** SwFtnInfo ***************************/ + +SwEndNoteInfo& SwEndNoteInfo::operator=(const SwEndNoteInfo& rInfo) +{ + if( rInfo.GetFtnTxtColl() ) + rInfo.GetFtnTxtColl()->Add(this); + else if ( pRegisteredIn) + pRegisteredIn->Remove(this); + + if ( rInfo.aPageDescDep.GetRegisteredIn() ) + ((SwModify*)rInfo.aPageDescDep.GetRegisteredIn())->Add( &aPageDescDep ); + else if ( aPageDescDep.GetRegisteredIn() ) + ((SwModify*)aPageDescDep.GetRegisteredIn())->Remove( &aPageDescDep ); + + if ( rInfo.aCharFmtDep.GetRegisteredIn() ) + ((SwModify*)rInfo.aCharFmtDep.GetRegisteredIn())->Add( &aCharFmtDep ); + else if ( aCharFmtDep.GetRegisteredIn() ) + ((SwModify*)aCharFmtDep.GetRegisteredIn())->Remove( &aCharFmtDep ); + + if ( rInfo.aAnchorCharFmtDep.GetRegisteredIn() ) + ((SwModify*)rInfo.aAnchorCharFmtDep.GetRegisteredIn())->Add( + &aAnchorCharFmtDep ); + else if( aAnchorCharFmtDep.GetRegisteredIn() ) + ((SwModify*)aAnchorCharFmtDep.GetRegisteredIn())->Remove( + &aAnchorCharFmtDep ); + + aFmt = rInfo.aFmt; + nFtnOffset = rInfo.nFtnOffset; + m_bEndNote = rInfo.m_bEndNote; + sPrefix = rInfo.sPrefix; + sSuffix = rInfo.sSuffix; + return *this; +} + + +sal_Bool SwEndNoteInfo::operator==( const SwEndNoteInfo& rInfo ) const +{ + return aPageDescDep.GetRegisteredIn() == + rInfo.aPageDescDep.GetRegisteredIn() && + aCharFmtDep.GetRegisteredIn() == + rInfo.aCharFmtDep.GetRegisteredIn() && + aAnchorCharFmtDep.GetRegisteredIn() == + rInfo.aAnchorCharFmtDep.GetRegisteredIn() && + GetFtnTxtColl() == rInfo.GetFtnTxtColl() && + aFmt.GetNumberingType() == rInfo.aFmt.GetNumberingType() && + nFtnOffset == rInfo.nFtnOffset && + m_bEndNote == rInfo.m_bEndNote && + sPrefix == rInfo.sPrefix && + sSuffix == rInfo.sSuffix; +} + + +SwEndNoteInfo::SwEndNoteInfo(const SwEndNoteInfo& rInfo) : + SwClient( rInfo.GetFtnTxtColl() ), + aPageDescDep( this, 0 ), + aCharFmtDep( this, 0 ), + aAnchorCharFmtDep( this, 0 ), + sPrefix( rInfo.sPrefix ), + sSuffix( rInfo.sSuffix ), + m_bEndNote( true ), + aFmt( rInfo.aFmt ), + nFtnOffset( rInfo.nFtnOffset ) +{ + if( rInfo.GetPageDescDep()->GetRegisteredIn() ) + ((SwModify*)rInfo.GetPageDescDep()->GetRegisteredIn())->Add( &aPageDescDep ); + + if( rInfo.aCharFmtDep.GetRegisteredIn() ) + ((SwModify*)rInfo.aCharFmtDep.GetRegisteredIn())->Add( &aCharFmtDep ); + + if( rInfo.aAnchorCharFmtDep.GetRegisteredIn() ) + ((SwModify*)rInfo.aAnchorCharFmtDep.GetRegisteredIn())->Add( + &aAnchorCharFmtDep ); +} + +SwEndNoteInfo::SwEndNoteInfo(SwTxtFmtColl *pFmt) : + SwClient(pFmt), + aPageDescDep( this, 0 ), + aCharFmtDep( this, 0 ), + aAnchorCharFmtDep( this, 0 ), + m_bEndNote( true ), + nFtnOffset( 0 ) +{ + aFmt.SetNumberingType(SVX_NUM_ROMAN_LOWER); +} + +SwPageDesc *SwEndNoteInfo::GetPageDesc( SwDoc &rDoc ) const +{ + if ( !aPageDescDep.GetRegisteredIn() ) + { + SwPageDesc *pDesc = rDoc.GetPageDescFromPool( static_cast<sal_uInt16>( + m_bEndNote ? RES_POOLPAGE_ENDNOTE : RES_POOLPAGE_FOOTNOTE ) ); + pDesc->Add( &((SwClient&)aPageDescDep) ); + } + return (SwPageDesc*)aPageDescDep.GetRegisteredIn(); +} + +void SwEndNoteInfo::ChgPageDesc( SwPageDesc *pDesc ) +{ + pDesc->Add( &((SwClient&)aPageDescDep) ); +} + +void SwEndNoteInfo::SetFtnTxtColl(SwTxtFmtColl& rFmt) +{ + rFmt.Add(this); +} + +SwCharFmt* SwEndNoteInfo::GetCharFmt(SwDoc &rDoc) const +{ + if ( !aCharFmtDep.GetRegisteredIn() ) + { + SwCharFmt* pFmt = rDoc.GetCharFmtFromPool( static_cast<sal_uInt16>( + m_bEndNote ? RES_POOLCHR_ENDNOTE : RES_POOLCHR_FOOTNOTE ) ); + pFmt->Add( &((SwClient&)aCharFmtDep) ); + } + return (SwCharFmt*)aCharFmtDep.GetRegisteredIn(); +} + +void SwEndNoteInfo::SetCharFmt( SwCharFmt* pChFmt ) +{ + DBG_ASSERT(pChFmt, "kein CharFmt?"); + pChFmt->Add( &((SwClient&)aCharFmtDep) ); +} + +SwCharFmt* SwEndNoteInfo::GetAnchorCharFmt(SwDoc &rDoc) const +{ + if( !aAnchorCharFmtDep.GetRegisteredIn() ) + { + SwCharFmt* pFmt = rDoc.GetCharFmtFromPool( static_cast<sal_uInt16>( + m_bEndNote ? RES_POOLCHR_ENDNOTE_ANCHOR : RES_POOLCHR_FOOTNOTE_ANCHOR ) ); + pFmt->Add( &((SwClient&)aAnchorCharFmtDep) ); + } + return (SwCharFmt*)aAnchorCharFmtDep.GetRegisteredIn(); +} + +void SwEndNoteInfo::SetAnchorCharFmt( SwCharFmt* pChFmt ) +{ + DBG_ASSERT(pChFmt, "kein CharFmt?"); + pChFmt->Add( &((SwClient&)aAnchorCharFmtDep) ); +} + +void SwEndNoteInfo::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ; + + if( RES_ATTRSET_CHG == nWhich || + RES_FMT_CHG == nWhich ) + { + SwDoc* pDoc; + if( aCharFmtDep.GetRegisteredIn() ) + pDoc = ((SwCharFmt*)aCharFmtDep.GetRegisteredIn())->GetDoc(); + else + pDoc = ((SwCharFmt*)aAnchorCharFmtDep.GetRegisteredIn())->GetDoc(); + SwFtnIdxs& rFtnIdxs = pDoc->GetFtnIdxs(); + for( sal_uInt16 nPos = 0; nPos < rFtnIdxs.Count(); ++nPos ) + { + SwTxtFtn *pTxtFtn = rFtnIdxs[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if ( rFtn.IsEndNote() == m_bEndNote ) + { + pTxtFtn->SetNumber( rFtn.GetNumber(), &rFtn.GetNumStr()); + } + } + } + else + SwClient::Modify( pOld, pNew ); +} + +SwFtnInfo& SwFtnInfo::operator=(const SwFtnInfo& rInfo) +{ + SwEndNoteInfo::operator=(rInfo); + aQuoVadis = rInfo.aQuoVadis; + aErgoSum = rInfo.aErgoSum; + ePos = rInfo.ePos; + eNum = rInfo.eNum; + return *this; +} + + +sal_Bool SwFtnInfo::operator==( const SwFtnInfo& rInfo ) const +{ + return ePos == rInfo.ePos && + eNum == rInfo.eNum && + SwEndNoteInfo::operator==(rInfo) && + aQuoVadis == rInfo.aQuoVadis && + aErgoSum == rInfo.aErgoSum; +} + + +SwFtnInfo::SwFtnInfo(const SwFtnInfo& rInfo) : + SwEndNoteInfo( rInfo ), + aQuoVadis( rInfo.aQuoVadis ), + aErgoSum( rInfo.aErgoSum ), + ePos( rInfo.ePos ), + eNum( rInfo.eNum ) +{ + m_bEndNote = false; +} + +SwFtnInfo::SwFtnInfo(SwTxtFmtColl *pFmt) : + SwEndNoteInfo( pFmt ), + ePos( FTNPOS_PAGE ), + eNum( FTNNUM_DOC ) +{ + aFmt.SetNumberingType(SVX_NUM_ARABIC); + m_bEndNote = false; +} + +/*********************** SwDoc ***************************/ + + +void SwDoc::SetFtnInfo(const SwFtnInfo& rInfo) +{ + if( !(GetFtnInfo() == rInfo) ) + { + const SwFtnInfo &rOld = GetFtnInfo(); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoFootNoteInfo(rOld) ); + } + + sal_Bool bFtnPos = rInfo.ePos != rOld.ePos; + sal_Bool bFtnDesc = rOld.ePos == FTNPOS_CHAPTER && + rInfo.GetPageDesc( *this ) != rOld.GetPageDesc( *this ); + sal_Bool bExtra = rInfo.aQuoVadis != rOld.aQuoVadis || + rInfo.aErgoSum != rOld.aErgoSum || + rInfo.aFmt.GetNumberingType() != rOld.aFmt.GetNumberingType() || + rInfo.GetPrefix() != rOld.GetPrefix() || + rInfo.GetSuffix() != rOld.GetSuffix(); + SwCharFmt *pOldChrFmt = rOld.GetCharFmt( *this ), + *pNewChrFmt = rInfo.GetCharFmt( *this ); + sal_Bool bFtnChrFmts = pOldChrFmt != pNewChrFmt; + + *pFtnInfo = rInfo; + + if ( GetRootFrm() ) + { + if ( bFtnPos ) + GetRootFrm()->RemoveFtns(); + else + { + GetRootFrm()->UpdateFtnNums(); + if ( bFtnDesc ) + GetRootFrm()->CheckFtnPageDescs( sal_False ); + if ( bExtra ) + { + //Fuer die Benachrichtung bezueglich ErgoSum usw. sparen wir uns + //extra-Code und nutzen die vorhandenen Wege. + SwFtnIdxs& rFtnIdxs = GetFtnIdxs(); + for( sal_uInt16 nPos = 0; nPos < rFtnIdxs.Count(); ++nPos ) + { + SwTxtFtn *pTxtFtn = rFtnIdxs[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if ( !rFtn.IsEndNote() ) + pTxtFtn->SetNumber( rFtn.GetNumber(), &rFtn.GetNumStr()); + } + } + } + } + if( FTNNUM_PAGE != rInfo.eNum ) + GetFtnIdxs().UpdateAllFtn(); + else if( bFtnChrFmts ) + { + SwFmtChg aOld( pOldChrFmt ); + SwFmtChg aNew( pNewChrFmt ); + pFtnInfo->Modify( &aOld, &aNew ); + } + + // --> OD 2008-01-09 #i81002# + // no update during loading + if ( !IsInReading() ) + { + UpdateRefFlds(NULL); + } + SetModified(); + } +} + +void SwDoc::SetEndNoteInfo(const SwEndNoteInfo& rInfo) +{ + if( !(GetEndNoteInfo() == rInfo) ) + { + if(GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoEndNoteInfo( GetEndNoteInfo() ) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + sal_Bool bNumChg = rInfo.nFtnOffset != GetEndNoteInfo().nFtnOffset; + // this seems to be an optimization: UpdateAllFtn() is only called + // if the offset changes; if the offset is the same, + // but type/prefix/suffix changes, just set new numbers. + bool const bExtra = !bNumChg && + ( (rInfo.aFmt.GetNumberingType() != + GetEndNoteInfo().aFmt.GetNumberingType()) + || (rInfo.GetPrefix() != GetEndNoteInfo().GetPrefix()) + || (rInfo.GetSuffix() != GetEndNoteInfo().GetSuffix()) + ); + sal_Bool bFtnDesc = rInfo.GetPageDesc( *this ) != + GetEndNoteInfo().GetPageDesc( *this ); + SwCharFmt *pOldChrFmt = GetEndNoteInfo().GetCharFmt( *this ), + *pNewChrFmt = rInfo.GetCharFmt( *this ); + sal_Bool bFtnChrFmts = pOldChrFmt != pNewChrFmt; + + *pEndNoteInfo = rInfo; + + if ( GetRootFrm() ) + { + if ( bFtnDesc ) + GetRootFrm()->CheckFtnPageDescs( sal_True ); + if ( bExtra ) + { + //Fuer die Benachrichtung bezueglich ErgoSum usw. sparen wir uns + //extra-Code und nutzen die vorhandenen Wege. + SwFtnIdxs& rFtnIdxs = GetFtnIdxs(); + for( sal_uInt16 nPos = 0; nPos < rFtnIdxs.Count(); ++nPos ) + { + SwTxtFtn *pTxtFtn = rFtnIdxs[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if ( rFtn.IsEndNote() ) + pTxtFtn->SetNumber( rFtn.GetNumber(), &rFtn.GetNumStr()); + } + } + } + if( bNumChg ) + GetFtnIdxs().UpdateAllFtn(); + else if( bFtnChrFmts ) + { + SwFmtChg aOld( pOldChrFmt ); + SwFmtChg aNew( pNewChrFmt ); + pEndNoteInfo->Modify( &aOld, &aNew ); + } + + // --> OD 2008-01-09 #i81002# + // no update during loading + if ( !IsInReading() ) + { + UpdateRefFlds(NULL); + } + SetModified(); + } +} + + +bool SwDoc::SetCurFtn( const SwPaM& rPam, const String& rNumStr, + sal_uInt16 nNumber, bool bIsEndNote ) +{ + SwFtnIdxs& rFtnArr = GetFtnIdxs(); + + const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End(); + const sal_uLong nSttNd = pStt->nNode.GetIndex(); + const xub_StrLen nSttCnt = pStt->nContent.GetIndex(); + const sal_uLong nEndNd = pEnd->nNode.GetIndex(); + const xub_StrLen nEndCnt = pEnd->nContent.GetIndex(); + + sal_uInt16 nPos; + rFtnArr.SeekEntry( pStt->nNode, &nPos ); + + SwUndoChangeFootNote* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); // AppendUndo far below, so leave it + pUndo = new SwUndoChangeFootNote( rPam, rNumStr, nNumber, bIsEndNote ); + } + + SwTxtFtn* pTxtFtn; + sal_uLong nIdx; + sal_Bool bChg = sal_False; + sal_Bool bTypeChgd = sal_False; + sal_uInt16 n = nPos; // sichern + while( nPos < rFtnArr.Count() && + (( nIdx = _SwTxtFtn_GetIndex((pTxtFtn = rFtnArr[ nPos++ ] ))) + < nEndNd || ( nIdx == nEndNd && + nEndCnt >= *pTxtFtn->GetStart() )) ) + if( nIdx > nSttNd || ( nIdx == nSttNd && + nSttCnt <= *pTxtFtn->GetStart() ) ) + { + const SwFmtFtn& rFtn = pTxtFtn->GetFtn(); + if( /*rFtn.GetNumber() != nNumber ||*/ + rFtn.GetNumStr() != rNumStr || + rFtn.IsEndNote() != bIsEndNote ) + { + bChg = sal_True; + if ( pUndo ) + { + pUndo->GetHistory().Add( *pTxtFtn ); + } + + pTxtFtn->SetNumber( nNumber, &rNumStr ); + if( rFtn.IsEndNote() != bIsEndNote ) + { + ((SwFmtFtn&)rFtn).SetEndNote( bIsEndNote ); + bTypeChgd = sal_True; + pTxtFtn->CheckCondColl(); + //#i11339# dispose UNO wrapper when a footnote is changed to an endnote or vice versa + SwPtrMsgPoolItem aMsgHint( RES_FOOTNOTE_DELETED, (void*)&pTxtFtn->GetAttr() ); + GetUnoCallBack()->Modify( &aMsgHint, &aMsgHint ); + } + } + } + + nPos = n; // nach vorne gibt es auch noch welche ! + while( nPos && + (( nIdx = _SwTxtFtn_GetIndex((pTxtFtn = rFtnArr[ --nPos ] ))) + > nSttNd || ( nIdx == nSttNd && + nSttCnt <= *pTxtFtn->GetStart() )) ) + if( nIdx < nEndNd || ( nIdx == nEndNd && + nEndCnt >= *pTxtFtn->GetStart() ) ) + { + const SwFmtFtn& rFtn = pTxtFtn->GetFtn(); + if( /*rFtn.GetNumber() != nNumber ||*/ + rFtn.GetNumStr() != rNumStr || + rFtn.IsEndNote() != bIsEndNote ) + { + bChg = sal_True; + if ( pUndo ) + { + pUndo->GetHistory().Add( *pTxtFtn ); + } + + pTxtFtn->SetNumber( nNumber, &rNumStr ); + if( rFtn.IsEndNote() != bIsEndNote ) + { + ((SwFmtFtn&)rFtn).SetEndNote( bIsEndNote ); + bTypeChgd = sal_True; + pTxtFtn->CheckCondColl(); + } + } + } + + // wer muss angestossen werden ?? + if( bChg ) + { + if( pUndo ) + { + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if ( bTypeChgd ) + rFtnArr.UpdateAllFtn(); + if( FTNNUM_PAGE != GetFtnInfo().eNum ) + { + if ( !bTypeChgd ) + rFtnArr.UpdateAllFtn(); + } + else if( GetRootFrm() ) + GetRootFrm()->UpdateFtnNums(); + SetModified(); + } + else + delete pUndo; + return bChg; +} + + + + + diff --git a/sw/source/core/doc/docglbl.cxx b/sw/source/core/doc/docglbl.cxx new file mode 100644 index 000000000000..d31bc4df722a --- /dev/null +++ b/sw/source/core/doc/docglbl.cxx @@ -0,0 +1,856 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <unotools/tempfile.hxx> +#include <svl/urihelper.hxx> +#include <svl/stritem.hxx> +#include <svl/eitem.hxx> +#include <sfx2/app.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <fmtinfmt.hxx> +#include <fmtanchr.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <docsh.hxx> +#include <globdoc.hxx> +#include <shellio.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <section.hxx> +#include <doctxm.hxx> +#include <poolfmt.hxx> + +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +using namespace ::com::sun::star; + +enum SwSplitDocType +{ + SPLITDOC_TO_GLOBALDOC, + SPLITDOC_TO_HTML +}; + +sal_Bool SwDoc::GenerateGlobalDoc( const String& rPath, + const SwTxtFmtColl* pSplitColl ) +{ + return SplitDoc( SPLITDOC_TO_GLOBALDOC, rPath, pSplitColl ); +} + +//#outline level,add by zhaojianwei +sal_Bool SwDoc::GenerateGlobalDoc( const String& rPath, int nOutlineLevel ) +{ + return SplitDoc( SPLITDOC_TO_GLOBALDOC, rPath, nOutlineLevel ); +} +sal_Bool SwDoc::GenerateHTMLDoc( const String& rPath, int nOutlineLevel ) +{ + return SplitDoc( SPLITDOC_TO_HTML, rPath, nOutlineLevel ); +} +//<-end,zhaojianwei + +sal_Bool SwDoc::GenerateHTMLDoc( const String& rPath, + const SwTxtFmtColl* pSplitColl ) +{ +#ifdef JP_TEST + if( !pSplitColl ) + { + sal_uInt8 nLvl = 1; + const SwTxtFmtColls& rFmtColls =*GetTxtFmtColls(); + for( sal_uInt16 n = rFmtColls.Count(); n; ) + //if( nLvl == rFmtColls[ --n ]->GetOutlineLevel() )//#outline level,zhaojianwei + if( nLvl == rFmtColls[ --n ]->GetAttrOutlineLevel() -1 )//<-end,zhaojianwei 0814 + { + pSplitColl = rFmtColls[ n ]; + break; + } + + if( !pSplitColl ) + pSplitColl = GetTxtCollFromPool( RES_POOLCOLL_HEADLINE2 ); + } +#endif + + return SplitDoc( SPLITDOC_TO_HTML, rPath, pSplitColl ); +} + +sal_Bool SwDoc::SplitDoc( sal_uInt16 eDocType, const String& rPath, + const SwTxtFmtColl* pSplitColl ) +{ + // ueber alle Node der Vorlage Iterieren und dafuer einzelne + // Dokumente erzeugen und in diesem gegen + // - gelinkte Bereiche (GlobalDoc) + // - Links (HTML) + // austauschen. + // Am Ende wird dieses Doc als GlobalDoc/HTML-Doc gespreichert. + if( !pDocShell || !pDocShell->GetMedium() || + ( SPLITDOC_TO_GLOBALDOC == eDocType && get(IDocumentSettingAccess::GLOBAL_DOCUMENT) ) ) + return sal_False; + + sal_uInt16 nOutl = 0; + SwOutlineNodes* pOutlNds = (SwOutlineNodes*)&GetNodes().GetOutLineNds(); + SwNodePtr pSttNd; + + if( pSplitColl ) + { + // wenn keine OutlineNumerierung ist, dann benutze eigenes Array + // und sammel die Nodes zusammen. + //if( NO_NUMBERING == pSplitColl->GetOutlineLevel() )//#outline level,zhaojianwei + if( pSplitColl->GetAttrOutlineLevel() == 0 )//<-end,zhaojianwei, 0814 + { + pOutlNds = new SwOutlineNodes( 8, 8 ); + SwClientIter aIter( *(SwModify*)pSplitColl ); + for( SwTxtNode* pTNd = (SwTxtNode*)aIter.First( TYPE( SwTxtNode )); + pTNd; pTNd = (SwTxtNode*)aIter.Next() ) + if( pTNd->GetNodes().IsDocNodes() ) + pOutlNds->Insert( pTNd ); + + if( !pOutlNds->Count() ) + { + delete pOutlNds; + return sal_False; + } + } + } + else + { + // dann suche die Gliederungs - Vorlage, der 1. Ebene + const SwTxtFmtColls& rFmtColls =*GetTxtFmtColls(); + for( sal_uInt16 n = rFmtColls.Count(); n; ) + //if( !rFmtColls[ --n ]->GetOutlineLevel() )//#outline level,zhaojianwei + if ( rFmtColls[ --n ]->GetAttrOutlineLevel() == 1 )//<-end,zhaojianwei + { + pSplitColl = rFmtColls[ n ]; + break; + } + + if( !pSplitColl ) + return sal_False; + } + + const SfxFilter* pFilter; + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + pFilter = SwIoSystem::GetFilterOfFormat( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "HTML" ))); + break; + + default: +// case SPLITDOC_TO_GLOBALDOC: + pFilter = SwIoSystem::GetFilterOfFormat( + String::CreateFromAscii( FILTER_XML )); + eDocType = SPLITDOC_TO_GLOBALDOC; + break; + } + + if( !pFilter ) + return sal_False; + + // Undo/Redline aufjedenfall abschalten + GetIDocumentUndoRedo().DoUndo(false); + SetRedlineMode_intern( (RedlineMode_t)(GetRedlineMode() & ~nsRedlineMode_t::REDLINE_ON)); + + String sExt( pFilter->GetSuffixes().GetToken(0, ',') ); + if( !sExt.Len() ) + sExt.AssignAscii( "sxw" ); + if( '.' != sExt.GetChar( 0 ) ) + sExt.Insert( '.', 0 ); + + INetURLObject aEntry(rPath); + String sLeading(aEntry.GetBase()); + aEntry.removeSegment(); + String sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE ); + utl::TempFile aTemp(sLeading,&sExt,&sPath ); + aTemp.EnableKillingFile(); + + DateTime aTmplDate; + { + Time a2Min( 0 ); a2Min.SetMin( 2 ); + aTmplDate += a2Min; + } + + + // alle Ungueltigen ueberspringen + while( nOutl < pOutlNds->Count() && + pOutlNds->GetObject( nOutl )->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) + ++nOutl; + + do { + pSttNd = 0; + + SwNodePtr pNd; + for( ; nOutl < pOutlNds->Count(); ++nOutl ) + if( ( pNd = pOutlNds->GetObject( nOutl ))->GetTxtNode()-> + GetTxtColl() == pSplitColl && + !pNd->FindTableNode() ) + { + pSttNd = pNd; + break; + } + + if( pSttNd ) + { + SwNodePtr pEndNd = 0; + for( ++nOutl; nOutl < pOutlNds->Count(); ++nOutl ) + { + pNd = pOutlNds->GetObject( nOutl ); + SwTxtFmtColl* pTColl = pNd->GetTxtNode()->GetTxtColl(); + + //if( ( pTColl == pSplitColl || //#outline level,zhaojianwei + // ( NO_NUMBERING != pSplitColl->GetOutlineLevel() && + // pTColl->GetOutlineLevel() < + // pSplitColl->GetOutlineLevel() )) && + // !pNd->FindTableNode() ) + if( ( pTColl == pSplitColl || + ( pSplitColl->GetAttrOutlineLevel() > 0 && + pTColl->GetAttrOutlineLevel() > 0 && + pTColl->GetAttrOutlineLevel() < + pSplitColl->GetAttrOutlineLevel() )) && + !pNd->FindTableNode() ) //<-end,zhaojianwei + { + pEndNd = pNd; + + break; + } + } + SwNodeIndex aEndIdx( pEndNd ? *pEndNd + : GetNodes().GetEndOfContent() ); + + // die Nodes komplett rausschreiben + String sFileName; + if( pSttNd->GetIndex() + 1 < aEndIdx.GetIndex() ) + { + SfxObjectShellLock xDocSh( new SwDocShell( SFX_CREATE_MODE_INTERNAL )); + if( xDocSh->DoInitNew( 0 ) ) + { + SwDoc* pDoc = ((SwDocShell*)(&xDocSh))->GetDoc(); + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + ((SwDocShell*)(&xDocSh))->GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); + // the GlobalDoc is the template + xDocProps->setTemplateName(aEmptyStr); + ::util::DateTime uDT(aTmplDate.Get100Sec(), + aTmplDate.GetSec(), aTmplDate.GetMin(), + aTmplDate.GetHour(), aTmplDate.GetDay(), + aTmplDate.GetMonth(), aTmplDate.GetYear()); + xDocProps->setTemplateDate(uDT); + xDocProps->setTemplateURL(rPath); + //JP 14.06.99: Set the text of the "split para" as title + // from the new doc. Is the current doc has + // a title, insert it at begin. + String sTitle( xDocProps->getTitle() ); + if( sTitle.Len() ) + sTitle.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ": " )); + sTitle += ((SwTxtNode*)pSttNd)->GetExpandTxt(); + xDocProps->setTitle( sTitle ); + + // Vorlagen ersetzen + pDoc->ReplaceStyles( *this ); + + // KapitelNumerierung uebernehmen + if( pOutlineRule ) + pDoc->SetOutlineNumRule( *pOutlineRule ); + + SwNodeRange aRg( *pSttNd, 0, aEndIdx.GetNode() ); + SwNodeIndex aTmpIdx( pDoc->GetNodes().GetEndOfContent() ); + GetNodes()._Copy( aRg, aTmpIdx, sal_False ); + + // den initialen TextNode loeschen + SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), 2 ); + if( aIdx.GetIndex() + 1 != + pDoc->GetNodes().GetEndOfContent().GetIndex() ) + pDoc->GetNodes().Delete( aIdx, 1 ); + + // alle Flys in dem Bereich + CopyFlyInFlyImpl( aRg, 0, aIdx ); + + + // und noch alle Bookmarks + // ????? + + utl::TempFile aTempFile2(sLeading,&sExt,&sPath ); + sFileName = aTempFile2.GetURL(); + SfxMedium* pTmpMed = new SfxMedium( sFileName, + STREAM_STD_READWRITE, sal_True ); + pTmpMed->SetFilter( pFilter ); + + // fuer den HTML-Filter mussen wir aber ein Layout + // haben, damit Textrahmen/Controls/OLE-Objecte korrekt + // als Grafik exportiert werden koennen. + if( SPLITDOC_TO_HTML == eDocType && + pDoc->GetSpzFrmFmts()->Count() ) + { + /* SfxViewFrame* pFrame = */ + SfxViewFrame::LoadHiddenDocument( *xDocSh, 0 ); + } + xDocSh->DoSaveAs( *pTmpMed ); + xDocSh->DoSaveCompleted( pTmpMed ); + + // beim Fehler wird keine FileLinkSection eingefuegt + if( xDocSh->GetError() ) + sFileName.Erase(); + } + xDocSh->DoClose(); + } + + // dann koennen ja die Bereiche eingefuegt werden + if( sFileName.Len() ) + { + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + { + // loesche alle Nodes im Bereich und setze im "Start- + // Node" den Link auf das gespeicherte Doc + sal_uLong nNodeDiff = aEndIdx.GetIndex() - + pSttNd->GetIndex() - 1; + if( nNodeDiff ) + { + SwPaM aTmp( *pSttNd, aEndIdx.GetNode(), 1, -1 ); + aTmp.GetPoint()->nContent.Assign( 0, 0 ); + aTmp.GetMark()->nContent.Assign( 0, 0 ); + SwNodeIndex aSIdx( aTmp.GetMark()->nNode ); + SwNodeIndex aEIdx( aTmp.GetPoint()->nNode ); + + // versuche hinters Ende zu verschieben + if( !aTmp.Move( fnMoveForward, fnGoNode ) ) + { + // na gut, dann an den Anfang + aTmp.Exchange(); + if( !aTmp.Move( fnMoveBackward, fnGoNode )) + { + ASSERT( sal_False, "kein Node mehr vorhanden" ); + } + } + // Bookmarks usw. verschieben + CorrAbs( aSIdx, aEIdx, *aTmp.GetPoint(), sal_True); + + // stehen noch FlyFrames rum, loesche auch diese + for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + SwFrmFmt* pFly = (*GetSpzFrmFmts())[n]; + const SwFmtAnchor* pAnchor = &pFly->GetAnchor(); + SwPosition const*const pAPos = + pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + aSIdx <= pAPos->nNode && + pAPos->nNode < aEIdx ) + { + DelLayoutFmt( pFly ); + --n; + } + } + + GetNodes().Delete( aSIdx, nNodeDiff ); + } + + // dann setze im StartNode noch den Link: + SwFmtINetFmt aINet( sFileName , aEmptyStr ); + SwTxtNode* pTNd = (SwTxtNode*)pSttNd; + pTNd->InsertItem( aINet, 0, pTNd->GetTxt().Len() ); + + // wenn der nicht mehr gefunden wird, kann das nur + // ein Bug sein! + if( !pOutlNds->Seek_Entry( pSttNd, &nOutl )) + pSttNd = 0; + ++nOutl; + } + break; + + default: + { + String sNm( INetURLObject( sFileName ).GetName() ); + SwSectionData aSectData( FILE_LINK_SECTION, + GetUniqueSectionName( &sNm )); + SwSectionFmt* pFmt = MakeSectionFmt( 0 ); + aSectData.SetLinkFileName(sFileName); + aSectData.SetProtectFlag(true); + + aEndIdx--; // im InsertSection ist Ende inclusive + while( aEndIdx.GetNode().IsStartNode() ) + aEndIdx--; + + // JP 06.07.99 - Bug 67361 - is any Section ends or + // starts in the new sectionrange, they must end or + // start before or behind the range! + SwSectionNode* pSectNd = pSttNd->FindSectionNode(); + while( pSectNd && pSectNd->EndOfSectionIndex() + <= aEndIdx.GetIndex() ) + { + const SwNode* pSectEnd = pSectNd->EndOfSectionNode(); + if( pSectNd->GetIndex() + 1 == + pSttNd->GetIndex() ) + { + sal_Bool bMvIdx = aEndIdx == *pSectEnd; + DelSectionFmt( pSectNd->GetSection().GetFmt() ); + if( bMvIdx ) + aEndIdx--; + } + else + { + SwNodeRange aRg( *pSttNd, *pSectEnd ); + SwNodeIndex aIdx( *pSectEnd, 1 ); + GetNodes()._MoveNodes( aRg, GetNodes(), aIdx ); + } + pSectNd = pSttNd->FindSectionNode(); + } + + pSectNd = aEndIdx.GetNode().FindSectionNode(); + while( pSectNd && pSectNd->GetIndex() > + pSttNd->GetIndex() ) + { + // #i15712# don't attempt to split sections if + // they are fully enclosed in [pSectNd,aEndIdx]. + if( aEndIdx < pSectNd->EndOfSectionIndex() ) + { + SwNodeRange aRg( *pSectNd, 1, aEndIdx, 1 ); + SwNodeIndex aIdx( *pSectNd ); + GetNodes()._MoveNodes( aRg, GetNodes(), aIdx ); + } + + pSectNd = pSttNd->FindSectionNode(); + } + + // -> #i26762# + // Ensure order of start and end of section is sane. + SwNodeIndex aStartIdx(*pSttNd); + + if (aEndIdx >= aStartIdx) + { + pSectNd = GetNodes().InsertTextSection(aStartIdx, + *pFmt, aSectData, 0, &aEndIdx, false); + } + else + { + pSectNd = GetNodes().InsertTextSection(aEndIdx, + *pFmt, aSectData, 0, &aStartIdx, false); + } + // <- #i26762# + + pSectNd->GetSection().CreateLink( CREATE_CONNECT ); + } + break; + } + } + } + } while( pSttNd ); + +// if( pOutlNds != (SwOutlineNodes*)&GetNodes().GetOutLineNds(); + if( pOutlNds != &GetNodes().GetOutLineNds() ) + delete pOutlNds; + + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + if( get(IDocumentSettingAccess::GLOBAL_DOCUMENT) ) + { + // dann alles verbliebenen Bereiche aufheben + while( GetSections().Count() ) + DelSectionFmt( GetSections()[ 0 ] ); + + SfxFilterContainer* pFCntnr = pDocShell->GetFactory().GetFilterContainer(); + pFilter = pFCntnr->GetFilter4EA( pFilter->GetTypeName(), SFX_FILTER_EXPORT ); + } + break; + +// case SPLITDOC_TO_GLOBALDOC: + default: + // dann das Globaldoc speichern + set(IDocumentSettingAccess::GLOBAL_DOCUMENT, true); + set(IDocumentSettingAccess::GLOBAL_DOCUMENT_SAVE_LINKS, false); + } + + // Medium istn't locked after reopen the document. Bug 91462 + SfxRequest aReq( SID_SAVEASDOC, SFX_CALLMODE_SYNCHRON, GetAttrPool() ); + aReq.AppendItem( SfxStringItem( SID_FILE_NAME, rPath ) ); + aReq.AppendItem( SfxBoolItem( SID_SAVETO, sal_True ) ); + if(pFilter) + aReq.AppendItem( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) ); + const SfxBoolItem *pRet = (const SfxBoolItem*)pDocShell->ExecuteSlot( aReq ); + + return pRet && pRet->GetValue(); +} + +//#outline level,add by zhaojianwei +sal_Bool SwDoc::SplitDoc( sal_uInt16 eDocType, const String& rPath, int nOutlineLevel ) +{ + if( !pDocShell || !pDocShell->GetMedium() || + ( SPLITDOC_TO_GLOBALDOC == eDocType && get(IDocumentSettingAccess::GLOBAL_DOCUMENT) ) ) + return sal_False; + + sal_uInt16 nOutl = 0; + SwOutlineNodes* pOutlNds = (SwOutlineNodes*)&GetNodes().GetOutLineNds(); + SwNodePtr pSttNd; + + const SfxFilter* pFilter; + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + pFilter = SwIoSystem::GetFilterOfFormat( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "HTML" ))); + break; + + default: +// case SPLITDOC_TO_GLOBALDOC: + pFilter = SwIoSystem::GetFilterOfFormat( + String::CreateFromAscii( FILTER_XML )); + eDocType = SPLITDOC_TO_GLOBALDOC; + break; + } + + if( !pFilter ) + return sal_False; + + // Undo/Redline aufjedenfall abschalten + GetIDocumentUndoRedo().DoUndo(false); + SetRedlineMode_intern( (RedlineMode_t)(GetRedlineMode() & ~nsRedlineMode_t::REDLINE_ON)); + + String sExt( pFilter->GetSuffixes().GetToken(0, ',') ); + if( !sExt.Len() ) + sExt.AssignAscii( "sxw" ); + if( '.' != sExt.GetChar( 0 ) ) + sExt.Insert( '.', 0 ); + + INetURLObject aEntry(rPath); + String sLeading(aEntry.GetBase()); + aEntry.removeSegment(); + String sPath = aEntry.GetMainURL( INetURLObject::NO_DECODE ); + utl::TempFile aTemp(sLeading,&sExt,&sPath ); + aTemp.EnableKillingFile(); + + DateTime aTmplDate; + { + Time a2Min( 0 ); a2Min.SetMin( 2 ); + aTmplDate += a2Min; + } + + + // alle Ungueltigen ueberspringen + while( nOutl < pOutlNds->Count() && + pOutlNds->GetObject( nOutl )->GetIndex() < GetNodes().GetEndOfExtras().GetIndex() ) + ++nOutl; + + do { + pSttNd = 0; + + SwNodePtr pNd; + for( ; nOutl < pOutlNds->Count(); ++nOutl ) + if( ( pNd = pOutlNds->GetObject( nOutl ))->GetTxtNode()->GetAttrOutlineLevel() == nOutlineLevel && + !pNd->FindTableNode() ) + { + pSttNd = pNd; + break; + } + + if( pSttNd ) + { + SwNodePtr pEndNd = 0; + for( ++nOutl; nOutl < pOutlNds->Count(); ++nOutl ) + { + pNd = pOutlNds->GetObject( nOutl ); + + const int nLevel = pNd->GetTxtNode()->GetAttrOutlineLevel(); + + if( ( 0 < nLevel && nLevel <= nOutlineLevel ) && + !pNd->FindTableNode() ) + { + pEndNd = pNd; + + break; + } + } + SwNodeIndex aEndIdx( pEndNd ? *pEndNd + : GetNodes().GetEndOfContent() ); + + String sFileName; + if( pSttNd->GetIndex() + 1 < aEndIdx.GetIndex() ) + { + SfxObjectShellLock xDocSh( new SwDocShell( SFX_CREATE_MODE_INTERNAL )); + if( xDocSh->DoInitNew( 0 ) ) + { + SwDoc* pDoc = ((SwDocShell*)(&xDocSh))->GetDoc(); + + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + ((SwDocShell*)(&xDocSh))->GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + DBG_ASSERT(xDocProps.is(), "Doc has no DocumentProperties"); + // the GlobalDoc is the template + xDocProps->setTemplateName(aEmptyStr); + ::util::DateTime uDT(aTmplDate.Get100Sec(), + aTmplDate.GetSec(), aTmplDate.GetMin(), + aTmplDate.GetHour(), aTmplDate.GetDay(), + aTmplDate.GetMonth(), aTmplDate.GetYear()); + xDocProps->setTemplateDate(uDT); + xDocProps->setTemplateURL(rPath); + //JP 14.06.99: Set the text of the "split para" as title + // from the new doc. Is the current doc has + // a title, insert it at begin. + String sTitle( xDocProps->getTitle() ); + if( sTitle.Len() ) + sTitle.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ": " )); + sTitle += ((SwTxtNode*)pSttNd)->GetExpandTxt(); + xDocProps->setTitle( sTitle ); + + // Vorlagen ersetzen + pDoc->ReplaceStyles( *this ); + + // KapitelNumerierung uebernehmen + if( pOutlineRule ) + pDoc->SetOutlineNumRule( *pOutlineRule ); + + SwNodeRange aRg( *pSttNd, 0, aEndIdx.GetNode() ); + SwNodeIndex aTmpIdx( pDoc->GetNodes().GetEndOfContent() ); + GetNodes()._Copy( aRg, aTmpIdx, sal_False ); + + // den initialen TextNode loeschen + SwNodeIndex aIdx( pDoc->GetNodes().GetEndOfExtras(), 2 ); + if( aIdx.GetIndex() + 1 != + pDoc->GetNodes().GetEndOfContent().GetIndex() ) + pDoc->GetNodes().Delete( aIdx, 1 ); + + // alle Flys in dem Bereich + CopyFlyInFlyImpl( aRg, 0, aIdx ); + + + // und noch alle Bookmarks + // ????? + + utl::TempFile aTempFile2(sLeading,&sExt,&sPath ); + sFileName = aTempFile2.GetURL(); + SfxMedium* pTmpMed = new SfxMedium( sFileName, + STREAM_STD_READWRITE, sal_True ); + pTmpMed->SetFilter( pFilter ); + + // fuer den HTML-Filter mussen wir aber ein Layout + // haben, damit Textrahmen/Controls/OLE-Objecte korrekt + // als Grafik exportiert werden koennen. + if( SPLITDOC_TO_HTML == eDocType && + pDoc->GetSpzFrmFmts()->Count() ) + { + /* SfxViewFrame* pFrame = */ + SfxViewFrame::LoadHiddenDocument( *xDocSh, 0 ); + } + xDocSh->DoSaveAs( *pTmpMed ); + xDocSh->DoSaveCompleted( pTmpMed ); + + // beim Fehler wird keine FileLinkSection eingefuegt + if( xDocSh->GetError() ) + sFileName.Erase(); + } + xDocSh->DoClose(); + } + + // dann koennen ja die Bereiche eingefuegt werden + if( sFileName.Len() ) + { + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + { + // loesche alle Nodes im Bereich und setze im "Start- + // Node" den Link auf das gespeicherte Doc + sal_uLong nNodeDiff = aEndIdx.GetIndex() - + pSttNd->GetIndex() - 1; + if( nNodeDiff ) + { + SwPaM aTmp( *pSttNd, aEndIdx.GetNode(), 1, -1 ); + aTmp.GetPoint()->nContent.Assign( 0, 0 ); + aTmp.GetMark()->nContent.Assign( 0, 0 ); + SwNodeIndex aSIdx( aTmp.GetMark()->nNode ); + SwNodeIndex aEIdx( aTmp.GetPoint()->nNode ); + + // versuche hinters Ende zu verschieben + if( !aTmp.Move( fnMoveForward, fnGoNode ) ) + { + // na gut, dann an den Anfang + aTmp.Exchange(); + if( !aTmp.Move( fnMoveBackward, fnGoNode )) + { + ASSERT( sal_False, "kein Node mehr vorhanden" ); + } + } + // Bookmarks usw. verschieben + CorrAbs( aSIdx, aEIdx, *aTmp.GetPoint(), sal_True); + + // stehen noch FlyFrames rum, loesche auch diese + for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + SwFrmFmt* pFly = (*GetSpzFrmFmts())[n]; + const SwFmtAnchor* pAnchor = &pFly->GetAnchor(); + SwPosition const*const pAPos = + pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + aSIdx <= pAPos->nNode && + pAPos->nNode < aEIdx ) + { + DelLayoutFmt( pFly ); + --n; + } + } + + GetNodes().Delete( aSIdx, nNodeDiff ); + } + + // dann setze im StartNode noch den Link: + SwFmtINetFmt aINet( sFileName , aEmptyStr ); + SwTxtNode* pTNd = (SwTxtNode*)pSttNd; + pTNd->InsertItem( aINet, 0, pTNd->GetTxt().Len() ); + + // wenn der nicht mehr gefunden wird, kann das nur + // ein Bug sein! + if( !pOutlNds->Seek_Entry( pSttNd, &nOutl )) + pSttNd = 0; + ++nOutl; + } + break; + + default: + { + String sNm( INetURLObject( sFileName ).GetName() ); + SwSectionData aSectData( FILE_LINK_SECTION, + GetUniqueSectionName( &sNm )); + SwSectionFmt* pFmt = MakeSectionFmt( 0 ); + aSectData.SetLinkFileName(sFileName); + aSectData.SetProtectFlag(true); + + aEndIdx--; // im InsertSection ist Ende inclusive + while( aEndIdx.GetNode().IsStartNode() ) + aEndIdx--; + + // JP 06.07.99 - Bug 67361 - is any Section ends or + // starts in the new sectionrange, they must end or + // start before or behind the range! + SwSectionNode* pSectNd = pSttNd->FindSectionNode(); + while( pSectNd && pSectNd->EndOfSectionIndex() + <= aEndIdx.GetIndex() ) + { + const SwNode* pSectEnd = pSectNd->EndOfSectionNode(); + if( pSectNd->GetIndex() + 1 == + pSttNd->GetIndex() ) + { + sal_Bool bMvIdx = aEndIdx == *pSectEnd; + DelSectionFmt( pSectNd->GetSection().GetFmt() ); + if( bMvIdx ) + aEndIdx--; + } + else + { + SwNodeRange aRg( *pSttNd, *pSectEnd ); + SwNodeIndex aIdx( *pSectEnd, 1 ); + GetNodes()._MoveNodes( aRg, GetNodes(), aIdx ); + } + pSectNd = pSttNd->FindSectionNode(); + } + + pSectNd = aEndIdx.GetNode().FindSectionNode(); + while( pSectNd && pSectNd->GetIndex() > + pSttNd->GetIndex() ) + { + if( aEndIdx < pSectNd->EndOfSectionIndex() ) + { + SwNodeRange aRg( *pSectNd, 1, aEndIdx, 1 ); + SwNodeIndex aIdx( *pSectNd ); + GetNodes()._MoveNodes( aRg, GetNodes(), aIdx ); + } + + pSectNd = pSttNd->FindSectionNode(); + } + + SwNodeIndex aStartIdx(*pSttNd); + + if (aEndIdx >= aStartIdx) + { + pSectNd = GetNodes().InsertTextSection(aStartIdx, + *pFmt, aSectData, 0, &aEndIdx, false); + } + else + { + pSectNd = GetNodes().InsertTextSection(aEndIdx, + *pFmt, aSectData, 0, &aStartIdx, false); + } + + pSectNd->GetSection().CreateLink( CREATE_CONNECT ); + } + break; + } + } + } + } while( pSttNd ); + + if( pOutlNds != &GetNodes().GetOutLineNds() ) + delete pOutlNds; + + switch( eDocType ) + { + case SPLITDOC_TO_HTML: + if( get(IDocumentSettingAccess::GLOBAL_DOCUMENT) ) + { + while( GetSections().Count() ) + DelSectionFmt( GetSections()[ 0 ] ); + + SfxFilterContainer* pFCntnr = pDocShell->GetFactory().GetFilterContainer(); + pFilter = pFCntnr->GetFilter4EA( pFilter->GetTypeName(), SFX_FILTER_EXPORT ); + } + break; + +// case SPLITDOC_TO_GLOBALDOC: + default: + set(IDocumentSettingAccess::GLOBAL_DOCUMENT, true); + set(IDocumentSettingAccess::GLOBAL_DOCUMENT_SAVE_LINKS, false); + } + + SfxRequest aReq( SID_SAVEASDOC, SFX_CALLMODE_SYNCHRON, GetAttrPool() ); + aReq.AppendItem( SfxStringItem( SID_FILE_NAME, rPath ) ); + aReq.AppendItem( SfxBoolItem( SID_SAVETO, sal_True ) ); + if(pFilter) + aReq.AppendItem( SfxStringItem( SID_FILTER_NAME, pFilter->GetName() ) ); + const SfxBoolItem *pRet = (const SfxBoolItem*)pDocShell->ExecuteSlot( aReq ); + + return pRet && pRet->GetValue(); +}//<-end,zhaojianwei + diff --git a/sw/source/core/doc/docglos.cxx b/sw/source/core/doc/docglos.cxx new file mode 100644 index 000000000000..610a8fb170b8 --- /dev/null +++ b/sw/source/core/doc/docglos.cxx @@ -0,0 +1,203 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> + +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <shellio.hxx> +#include <pam.hxx> +#include <swundo.hxx> +#include <ndtxt.hxx> +#include <acorrect.hxx> +#include <crsrsh.hxx> +#include <docsh.hxx> + + +using namespace ::com::sun::star; + + +/// copy document properties via public interface +static void lcl_copyDocumentProperties( + uno::Reference<document::XDocumentProperties> i_xSource, + uno::Reference<document::XDocumentProperties> i_xTarget) { + DBG_ASSERT(i_xSource.is(), "null reference"); + DBG_ASSERT(i_xTarget.is(), "null reference"); + + i_xTarget->setAuthor(i_xSource->getAuthor()); + i_xTarget->setGenerator(i_xSource->getGenerator()); + i_xTarget->setCreationDate(i_xSource->getCreationDate()); + i_xTarget->setTitle(i_xSource->getTitle()); + i_xTarget->setSubject(i_xSource->getSubject()); + i_xTarget->setDescription(i_xSource->getDescription()); + i_xTarget->setKeywords(i_xSource->getKeywords()); + i_xTarget->setLanguage(i_xSource->getLanguage()); + i_xTarget->setModifiedBy(i_xSource->getModifiedBy()); + i_xTarget->setModificationDate(i_xSource->getModificationDate()); + i_xTarget->setPrintedBy(i_xSource->getPrintedBy()); + i_xTarget->setPrintDate(i_xSource->getPrintDate()); + i_xTarget->setTemplateName(i_xSource->getTemplateName()); + i_xTarget->setTemplateURL(i_xSource->getTemplateURL()); + i_xTarget->setTemplateDate(i_xSource->getTemplateDate()); + i_xTarget->setAutoloadURL(i_xSource->getAutoloadURL()); + i_xTarget->setAutoloadSecs(i_xSource->getAutoloadSecs()); + i_xTarget->setDefaultTarget(i_xSource->getDefaultTarget()); + i_xTarget->setDocumentStatistics(i_xSource->getDocumentStatistics()); + i_xTarget->setEditingCycles(i_xSource->getEditingCycles()); + i_xTarget->setEditingDuration(i_xSource->getEditingDuration()); + + uno::Reference<beans::XPropertySet> xSourceUDSet( + i_xSource->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertyContainer> xTargetUD( + i_xTarget->getUserDefinedProperties()); + uno::Reference<beans::XPropertySet> xTargetUDSet(xTargetUD, + uno::UNO_QUERY_THROW); + uno::Sequence<beans::Property> tgtprops + = xTargetUDSet->getPropertySetInfo()->getProperties(); + for (sal_Int32 i = 0; i < tgtprops.getLength(); ++i) { + try { + xTargetUD->removeProperty(tgtprops [i].Name); + } catch (uno::Exception &) { + // ignore + } + } + try { + uno::Reference<beans::XPropertySetInfo> xSetInfo + = xSourceUDSet->getPropertySetInfo(); + uno::Sequence<beans::Property> srcprops = xSetInfo->getProperties(); + for (sal_Int32 i = 0; i < srcprops.getLength(); ++i) { + ::rtl::OUString name = srcprops[i].Name; + xTargetUD->addProperty(name, srcprops[i].Attributes, + xSourceUDSet->getPropertyValue(name)); + } + } catch (uno::Exception &) { + // ignore + } +} + +/* -----------------22.07.99 11:47------------------- + Description: inserts an AutoText block + --------------------------------------------------*/ +sal_Bool SwDoc::InsertGlossary( SwTextBlocks& rBlock, const String& rEntry, + SwPaM& rPaM, SwCrsrShell* pShell ) +{ + sal_Bool bRet = sal_False; + sal_uInt16 nIdx = rBlock.GetIndex( rEntry ); + if( (sal_uInt16) -1 != nIdx ) + { + // Bug #70238# ask the TextOnly-Flag before BeginGetDoc, because + // the method closed the Storage! + sal_Bool bSav_IsInsGlossary = mbInsOnlyTxtGlssry; + mbInsOnlyTxtGlssry = rBlock.IsOnlyTextBlock( nIdx ); + + if( rBlock.BeginGetDoc( nIdx ) ) + { + SwDoc* pGDoc = rBlock.GetDoc(); + + // alle FixFelder aktualisieren. Dann aber auch mit der + // richtigen DocInfo! + // FIXME: UGLY: Because we cannot limit the range in which to do + // field updates, we must update the fixed fields at the glossary + // entry document. + // To be able to do this, we copy the document properties of the + // target document to the glossary document +// DBG_ASSERT(GetDocShell(), "no SwDocShell"); // may be clipboard! + DBG_ASSERT(pGDoc->GetDocShell(), "no SwDocShell at glossary"); + if (GetDocShell() && pGDoc->GetDocShell()) { + uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + GetDocShell()->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties() ); + uno::Reference<document::XDocumentPropertiesSupplier> xGlosDPS( + pGDoc->GetDocShell()->GetModel(), uno::UNO_QUERY_THROW); + uno::Reference<document::XDocumentProperties> xGlosDocProps( + xGlosDPS->getDocumentProperties() ); + lcl_copyDocumentProperties(xDocProps, xGlosDocProps); + } + pGDoc->SetFixFields(false, NULL); + + //StartAllAction(); + LockExpFlds(); + + SwNodeIndex aStt( pGDoc->GetNodes().GetEndOfExtras(), 1 ); + SwCntntNode* pCntntNd = pGDoc->GetNodes().GoNext( &aStt ); + const SwTableNode* pTblNd = pCntntNd->FindTableNode(); + SwPaM aCpyPam( pTblNd ? *(SwNode*)pTblNd : *(SwNode*)pCntntNd ); + aCpyPam.SetMark(); + + // dann bis zum Ende vom Nodes Array + aCpyPam.GetPoint()->nNode = pGDoc->GetNodes().GetEndOfContent().GetIndex()-1; + pCntntNd = aCpyPam.GetCntntNode(); + aCpyPam.GetPoint()->nContent.Assign( pCntntNd, pCntntNd->Len() ); + + GetIDocumentUndoRedo().StartUndo( UNDO_INSGLOSSARY, NULL ); + SwPaM *_pStartCrsr = &rPaM, *__pStartCrsr = _pStartCrsr; + do { + + SwPosition& rInsPos = *_pStartCrsr->GetPoint(); + SwStartNode* pBoxSttNd = (SwStartNode*)rInsPos.nNode.GetNode(). + FindTableBoxStartNode(); + + if( pBoxSttNd && 2 == pBoxSttNd->EndOfSectionIndex() - + pBoxSttNd->GetIndex() && + aCpyPam.GetPoint()->nNode != aCpyPam.GetMark()->nNode ) + { + // es wird mehr als 1 Node in die akt. Box kopiert. + // Dann muessen die BoxAttribute aber entfernt werden. + ClearBoxNumAttrs( rInsPos.nNode ); + } + + SwDontExpandItem aACD; + aACD.SaveDontExpandItems( rInsPos ); + + pGDoc->CopyRange( aCpyPam, rInsPos, false ); + + aACD.RestoreDontExpandItems( rInsPos ); + if( pShell ) + pShell->SaveTblBoxCntnt( &rInsPos ); + } while( (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != + __pStartCrsr ); + GetIDocumentUndoRedo().EndUndo( UNDO_INSGLOSSARY, NULL ); + + UnlockExpFlds(); + if( !IsExpFldsLocked() ) + UpdateExpFlds(NULL, true); + bRet = sal_True; + } + mbInsOnlyTxtGlssry = bSav_IsInsGlossary; + } + rBlock.EndGetDoc(); + return bRet; +} + + diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx new file mode 100644 index 000000000000..d5e7354df745 --- /dev/null +++ b/sw/source/core/doc/doclay.cxx @@ -0,0 +1,2369 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <unotools/linguprops.hxx> +#include <unotools/lingucfg.hxx> +#include <com/sun/star/embed/EmbedStates.hpp> +#include <hintids.hxx> +#include <com/sun/star/util/XCloseable.hpp> +#include <sfx2/progress.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdpage.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/prntitem.hxx> +#include <svx/fmglob.hxx> +#include <svx/svdouno.hxx> +#include <svx/fmpage.hxx> +#include <editeng/frmdiritem.hxx> + +#include <swmodule.hxx> +#include <modcfg.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <rtl/logfile.hxx> +#include <SwStyleNameMapper.hxx> +#include <fchrfmt.hxx> +#include <errhdl.hxx> +#include <frmatr.hxx> +#include <txatbase.hxx> +#include <fmtfld.hxx> +#include <fmtornt.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <fmtflcnt.hxx> +#include <fmtcnct.hxx> +#include <frmfmt.hxx> +#include <dcontact.hxx> +#include <txtflcnt.hxx> +#include <docfld.hxx> // fuer Expression-Felder +#include <pam.hxx> +#include <ndtxt.hxx> +#include <ndnotxt.hxx> +#include <ndole.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <flyfrm.hxx> +#include <fesh.hxx> +#include <docsh.hxx> +#include <dflyobj.hxx> +#include <dcontact.hxx> +#include <swundo.hxx> +#include <flypos.hxx> +#include <UndoInsert.hxx> +#include <expfld.hxx> // InsertLabel +#include <poolfmt.hxx> // PoolVorlagen-Id's +#include <docary.hxx> +#include <swtable.hxx> +#include <tblsel.hxx> +#include <viewopt.hxx> +#include <fldupde.hxx> +#include <txtftn.hxx> +#include <ftnidx.hxx> +#include <ftninfo.hxx> +#include <pagedesc.hxx> +#include <PostItMgr.hxx> +#include <comcore.hrc> // STR-ResId's + +// #i11176# +#include <unoframe.hxx> +// OD 2004-05-24 #i28701# +#include <sortedobjs.hxx> + +// --> OD 2004-07-26 #i32089# +#include <vector> +// <-- + +using namespace ::com::sun::star; +using ::rtl::OUString; + +#define DEF_FLY_WIDTH 2268 //Defaultbreite fuer FlyFrms (2268 == 4cm) + +/* #109161# */ +static bool lcl_IsItemSet(const SwCntntNode & rNode, sal_uInt16 which) +{ + bool bResult = false; + + if (SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState(which)) + bResult = true; + + return bResult; +} + +/************************************************************************* +|* +|* SwDoc::MakeLayoutFmt() +|* +|* Beschreibung Erzeugt ein neues Format das in seinen Einstellungen +|* Defaultmaessig zu dem Request passt. Das Format wird in das +|* entsprechende Formate-Array gestellt. +|* Wenn bereits ein passendes Format existiert, so wird dies +|* zurueckgeliefert. +|* Ersterstellung MA 22. Sep. 92 +|* Letzte Aenderung JP 08.05.98 +|* +|*************************************************************************/ + +SwFrmFmt *SwDoc::MakeLayoutFmt( RndStdIds eRequest, const SfxItemSet* pSet ) +{ + SwFrmFmt *pFmt = 0; + const sal_Bool bMod = IsModified(); + sal_Bool bHeader = sal_False; + + switch ( eRequest ) + { + case RND_STD_HEADER: + case RND_STD_HEADERL: + case RND_STD_HEADERR: + { + bHeader = sal_True; + // kein break, es geht unten weiter + } + case RND_STD_FOOTER: + case RND_STD_FOOTERL: + case RND_STD_FOOTERR: + { + pFmt = new SwFrmFmt( GetAttrPool(), + (bHeader ? "Header" : "Footer"), + GetDfltFrmFmt() ); + + SwNodeIndex aTmpIdx( GetNodes().GetEndOfAutotext() ); + SwStartNode* pSttNd = + GetNodes().MakeTextSection + ( aTmpIdx, + bHeader ? SwHeaderStartNode : SwFooterStartNode, + GetTxtCollFromPool(static_cast<sal_uInt16>( bHeader + ? ( eRequest == RND_STD_HEADERL + ? RES_POOLCOLL_HEADERL + : eRequest == RND_STD_HEADERR + ? RES_POOLCOLL_HEADERR + : RES_POOLCOLL_HEADER ) + : ( eRequest == RND_STD_FOOTERL + ? RES_POOLCOLL_FOOTERL + : eRequest == RND_STD_FOOTERR + ? RES_POOLCOLL_FOOTERR + : RES_POOLCOLL_FOOTER ) + ) ) ); + pFmt->SetFmtAttr( SwFmtCntnt( pSttNd )); + + if( pSet ) // noch ein paar Attribute setzen ? + pFmt->SetFmtAttr( *pSet ); + + // JP: warum zuruecksetzen ??? Doc. ist doch veraendert ??? + // bei den Fly auf jedenfall verkehrt !! + if ( !bMod ) + ResetModified(); + } + break; + + case RND_DRAW_OBJECT: + { + pFmt = MakeDrawFrmFmt( aEmptyStr, GetDfltFrmFmt() ); + if( pSet ) // noch ein paar Attribute setzen ? + pFmt->SetFmtAttr( *pSet ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( + new SwUndoInsLayFmt(pFmt, 0, 0)); + } + } + break; + +#ifdef DBG_UTIL + case FLY_AT_PAGE: + case FLY_AT_CHAR: + case FLY_AT_FLY: + case FLY_AT_PARA: + case FLY_AS_CHAR: + ASSERT( false, "use new interface instead: SwDoc::MakeFlySection!" ); + break; +#endif + + default: + ASSERT( !this, + "Layoutformat mit ungueltigem Request angefordert." ); + + } + return pFmt; +} +/************************************************************************* +|* +|* SwDoc::DelLayoutFmt() +|* +|* Beschreibung Loescht das angegebene Format, der Inhalt wird mit +|* geloescht. +|* Ersterstellung MA 23. Sep. 92 +|* Letzte Aenderung MA 05. Feb. 93 +|* +|*************************************************************************/ + +void SwDoc::DelLayoutFmt( SwFrmFmt *pFmt ) +{ + //Verkettung von Rahmen muss ggf. zusammengefuehrt werden. + //Bevor die Frames vernichtet werden, damit die Inhalte der Rahmen + //ggf. entsprechend gerichtet werden. + const SwFmtChain &rChain = pFmt->GetChain(); + if ( rChain.GetPrev() ) + { + SwFmtChain aChain( rChain.GetPrev()->GetChain() ); + aChain.SetNext( rChain.GetNext() ); + SetAttr( aChain, *rChain.GetPrev() ); + } + if ( rChain.GetNext() ) + { + SwFmtChain aChain( rChain.GetNext()->GetChain() ); + aChain.SetPrev( rChain.GetPrev() ); + SetAttr( aChain, *rChain.GetNext() ); + } + + const SwNodeIndex* pCntIdx = pFmt->GetCntnt().GetCntntIdx(); + if (pCntIdx && !GetIDocumentUndoRedo().DoesUndo()) + { + //Verbindung abbauen, falls es sich um ein OLE-Objekt handelt. + SwOLENode* pOLENd = GetNodes()[ pCntIdx->GetIndex()+1 ]->GetOLENode(); + if( pOLENd && pOLENd->GetOLEObj().IsOleRef() ) + { + /* + SwDoc* pDoc = (SwDoc*)pFmt->GetDoc(); + if( pDoc ) + { + SfxObjectShell* p = pDoc->GetPersist(); + if( p ) // muss da sein + { + SvInfoObjectRef aRef( p->Find( pOLENd->GetOLEObj().GetName() ) ); + if( aRef.Is() ) + aRef->SetObj(0); + } + } */ + + // TODO/MBA: the old object closed the object, cleared all references to it, but didn't remove it from the container. + // I have no idea, why, nobody could explain it - so I do my very best to mimic this behavior + //uno::Reference < util::XCloseable > xClose( pOLENd->GetOLEObj().GetOleRef(), uno::UNO_QUERY ); + //if ( xClose.is() ) + { + try + { + pOLENd->GetOLEObj().GetOleRef()->changeState( embed::EmbedStates::LOADED ); + } + catch ( uno::Exception& ) + { + } + } + + //pOLENd->GetOLEObj().GetOleRef() = 0; + } + } + + //Frms vernichten. + pFmt->DelFrms(); + + // erstmal sind nur Fly's Undofaehig + const sal_uInt16 nWh = pFmt->Which(); + if (GetIDocumentUndoRedo().DoesUndo() && + (RES_FLYFRMFMT == nWh || RES_DRAWFRMFMT == nWh)) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoDelLayFmt( pFmt )); + } + else + { + // --> OD 2004-07-26 #i32089# - delete at-frame anchored objects + if ( nWh == RES_FLYFRMFMT ) + { + // determine frame formats of at-frame anchored objects + const SwNodeIndex* pCntntIdx = pFmt->GetCntnt().GetCntntIdx(); + if ( pCntntIdx ) + { + const SwSpzFrmFmts* pTbl = pFmt->GetDoc()->GetSpzFrmFmts(); + if ( pTbl ) + { + std::vector<SwFrmFmt*> aToDeleteFrmFmts; + const sal_uLong nNodeIdxOfFlyFmt( pCntntIdx->GetIndex() ); + + for ( sal_uInt16 i = 0; i < pTbl->Count(); ++i ) + { + SwFrmFmt* pTmpFmt = (*pTbl)[i]; + const SwFmtAnchor &rAnch = pTmpFmt->GetAnchor(); + if ( rAnch.GetAnchorId() == FLY_AT_FLY && + rAnch.GetCntntAnchor()->nNode.GetIndex() == nNodeIdxOfFlyFmt ) + { + aToDeleteFrmFmts.push_back( pTmpFmt ); + } + } + + // delete found frame formats + while ( !aToDeleteFrmFmts.empty() ) + { + SwFrmFmt* pTmpFmt = aToDeleteFrmFmts.back(); + pFmt->GetDoc()->DelLayoutFmt( pTmpFmt ); + + aToDeleteFrmFmts.pop_back(); + } + } + } + } + // <-- + + //Inhalt Loeschen. + if( pCntIdx ) + { + SwNode *pNode = &pCntIdx->GetNode(); + ((SwFmtCntnt&)pFmt->GetFmtAttr( RES_CNTNT )).SetNewCntntIdx( 0 ); + DeleteSection( pNode ); + } + + // ggfs. bei Zeichengebundenen Flys das Zeichen loeschen + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + if ((FLY_AS_CHAR == rAnchor.GetAnchorId()) && rAnchor.GetCntntAnchor()) + { + const SwPosition* pPos = rAnchor.GetCntntAnchor(); + SwTxtNode *pTxtNd = pPos->nNode.GetNode().GetTxtNode(); + + // attribute is still in text node, delete it + if ( pTxtNd ) + { + SwTxtFlyCnt* const pAttr = static_cast<SwTxtFlyCnt*>( + pTxtNd->GetTxtAttrForCharAt( pPos->nContent.GetIndex(), + RES_TXTATR_FLYCNT )); + if ( pAttr && (pAttr->GetFlyCnt().GetFrmFmt() == pFmt) ) + { + // dont delete, set pointer to 0 + const_cast<SwFmtFlyCnt&>(pAttr->GetFlyCnt()).SetFlyFmt(); + SwIndex aIdx( pPos->nContent ); + pTxtNd->EraseText( aIdx, 1 ); + } + } + } + + DelFrmFmt( pFmt ); + } + SetModified(); +} + +/************************************************************************* +|* +|* SwDoc::CopyLayoutFmt() +|* +|* Beschreibung Kopiert das angegebene Format pSrc in pDest und +|* returnt pDest. Wenn es noch kein pDest gibt, wird +|* eins angelegt. +|* JP: steht das Source Format in einem anderen +|* Dokument, so kopiere auch dann noch richtig !! +|* Vom chaos::Anchor-Attribut wird die Position immer +|* auf 0 gesetzt !!! +|* +|* Ersterstellung BP 18.12.92 +|* Letzte Aenderung MA 17. Jul. 96 +|* +|*************************************************************************/ + +SwFrmFmt *SwDoc::CopyLayoutFmt( const SwFrmFmt& rSource, + const SwFmtAnchor& rNewAnchor, + bool bSetTxtFlyAtt, bool bMakeFrms ) +{ + const bool bFly = RES_FLYFRMFMT == rSource.Which(); + const bool bDraw = RES_DRAWFRMFMT == rSource.Which(); + ASSERT( bFly || bDraw, "this method only works for fly or draw" ); + + SwDoc* pSrcDoc = (SwDoc*)rSource.GetDoc(); + + // #108784# may we copy this object? + // We may, unless it's 1) it's a control (and therfore a draw) + // 2) anchored in a header/footer + // 3) anchored (to paragraph?) + bool bMayNotCopy = false; + if( bDraw ) + { + const SwDrawContact* pDrawContact = + static_cast<const SwDrawContact*>( rSource.FindContactObj() ); + + bMayNotCopy = + ((FLY_AT_PARA == rNewAnchor.GetAnchorId()) || + (FLY_AT_FLY == rNewAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rNewAnchor.GetAnchorId())) && + rNewAnchor.GetCntntAnchor() && + IsInHeaderFooter( rNewAnchor.GetCntntAnchor()->nNode ) && + pDrawContact != NULL && + pDrawContact->GetMaster() != NULL && + CheckControlLayer( pDrawContact->GetMaster() ); + } + + // just return if we can't copy this + if( bMayNotCopy ) + return NULL; + + SwFrmFmt* pDest = GetDfltFrmFmt(); + if( rSource.GetRegisteredIn() != pSrcDoc->GetDfltFrmFmt() ) + pDest = CopyFrmFmt( *(SwFrmFmt*)rSource.GetRegisteredIn() ); + if( bFly ) + { + // #i11176# + // To do a correct cloning concerning the ZOrder for all objects + // it is necessary to actually create a draw object for fly frames, too. + // These are then added to the DrawingLayer (which needs to exist). + // Together with correct sorting of all drawinglayer based objects + // before cloning ZOrder transfer works correctly then. + SwFlyFrmFmt *pFormat = MakeFlyFrmFmt( rSource.GetName(), pDest ); + pDest = pFormat; + + SwXFrame::GetOrCreateSdrObject(pFormat); + } + else + pDest = MakeDrawFrmFmt( aEmptyStr, pDest ); + + // alle anderen/neue Attribute kopieren. + pDest->CopyAttrs( rSource ); + + //Chains werden nicht kopiert. + pDest->ResetFmtAttr( RES_CHAIN ); + + if( bFly ) + { + //Der Inhalt wird dupliziert. + const SwNode& rCSttNd = rSource.GetCntnt().GetCntntIdx()->GetNode(); + SwNodeRange aRg( rCSttNd, 1, *rCSttNd.EndOfSectionNode() ); + + SwNodeIndex aIdx( GetNodes().GetEndOfAutotext() ); + SwStartNode* pSttNd = GetNodes().MakeEmptySection( aIdx, SwFlyStartNode ); + + // erst den chaos::Anchor/CntntIndex setzen, innerhalb des Kopierens + // auf die Werte zugegriffen werden kann (DrawFmt in Kopf-/Fusszeilen) + aIdx = *pSttNd; + SwFmtCntnt aAttr( rSource.GetCntnt() ); + aAttr.SetNewCntntIdx( &aIdx ); + pDest->SetFmtAttr( aAttr ); + pDest->SetFmtAttr( rNewAnchor ); + + if( !mbCopyIsMove || this != pSrcDoc ) + { + if( mbInReading ) + pDest->SetName( aEmptyStr ); + else + { + // Teste erstmal ob der Name schon vergeben ist. + // Wenn ja -> neuen generieren + sal_Int8 nNdTyp = aRg.aStart.GetNode().GetNodeType(); + + String sOld( pDest->GetName() ); + pDest->SetName( aEmptyStr ); + if( FindFlyByName( sOld, nNdTyp ) ) // einen gefunden + switch( nNdTyp ) + { + case ND_GRFNODE: sOld = GetUniqueGrfName(); break; + case ND_OLENODE: sOld = GetUniqueOLEName(); break; + default: sOld = GetUniqueFrameName(); break; + } + + pDest->SetName( sOld ); + } + } + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoInsLayFmt(pDest,0,0)); + } + + // sorge dafuer das auch Fly's in Fly's kopiert werden + aIdx = *pSttNd->EndOfSectionNode(); + pSrcDoc->CopyWithFlyInFly( aRg, 0, aIdx, sal_False, sal_True, sal_True ); + } + else + { + ASSERT( RES_DRAWFRMFMT == rSource.Which(), "Weder Fly noch Draw." ); + // OD 2005-08-02 #i52780# - Note: moving object to visible layer not needed. + SwDrawContact* pSourceContact = (SwDrawContact *)rSource.FindContactObj(); + + SwDrawContact* pContact = new SwDrawContact( (SwDrawFrmFmt*)pDest, + CloneSdrObj( *pSourceContact->GetMaster(), + mbCopyIsMove && this == pSrcDoc ) ); + // --> OD 2005-05-23 #i49730# - notify draw frame format + // that position attributes are already set, if the position attributes + // are already set at the source draw frame format. + if ( pDest->ISA(SwDrawFrmFmt) && + rSource.ISA(SwDrawFrmFmt) && + static_cast<const SwDrawFrmFmt&>(rSource).IsPosAttrSet() ) + { + static_cast<SwDrawFrmFmt*>(pDest)->PosAttrSet(); + } + // <-- + + if( pDest->GetAnchor() == rNewAnchor ) + { + // OD 03.07.2003 #108784# - do *not* connect to layout, if + // a <MakeFrms> will not be called. + if ( bMakeFrms ) + { + pContact->ConnectToLayout( &rNewAnchor ); + } + } + else + pDest->SetFmtAttr( rNewAnchor ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(new SwUndoInsLayFmt(pDest,0,0)); + } + } + + if (bSetTxtFlyAtt && (FLY_AS_CHAR == rNewAnchor.GetAnchorId())) + { + const SwPosition* pPos = rNewAnchor.GetCntntAnchor(); + SwFmtFlyCnt aFmt( pDest ); + pPos->nNode.GetNode().GetTxtNode()->InsertItem( + aFmt, pPos->nContent.GetIndex(), 0 ); + } + + if( bMakeFrms ) + pDest->MakeFrms(); + + return pDest; +} + +SdrObject* SwDoc::CloneSdrObj( const SdrObject& rObj, sal_Bool bMoveWithinDoc, + sal_Bool bInsInPage ) +{ + // --> OD 2005-08-08 #i52858# - method name changed + SdrPage *pPg = GetOrCreateDrawModel()->GetPage( 0 ); + // <-- + if( !pPg ) + { + pPg = GetDrawModel()->AllocPage( sal_False ); + GetDrawModel()->InsertPage( pPg ); + } + + SdrObject *pObj = rObj.Clone(); + if( bMoveWithinDoc && FmFormInventor == pObj->GetObjInventor() ) + { + // bei Controls muss der Name erhalten bleiben + uno::Reference< awt::XControlModel > xModel = ((SdrUnoObj*)pObj)->GetUnoControlModel(); + uno::Any aVal; + uno::Reference< beans::XPropertySet > xSet(xModel, uno::UNO_QUERY); + OUString sName( rtl::OUString::createFromAscii("Name") ); + if( xSet.is() ) + aVal = xSet->getPropertyValue( sName ); + if( bInsInPage ) + pPg->InsertObject( pObj ); + if( xSet.is() ) + xSet->setPropertyValue( sName, aVal ); + } + else if( bInsInPage ) + pPg->InsertObject( pObj ); + + // OD 02.07.2003 #108784# - for drawing objects: set layer of cloned object + // to invisible layer + SdrLayerID nLayerIdForClone = rObj.GetLayer(); + if ( !pObj->ISA(SwFlyDrawObj) && + !pObj->ISA(SwVirtFlyDrawObj) && + !IS_TYPE(SdrObject,pObj) ) + { + if ( IsVisibleLayerId( nLayerIdForClone ) ) + { + nLayerIdForClone = GetInvisibleLayerIdByVisibleOne( nLayerIdForClone ); + } + } + pObj->SetLayer( nLayerIdForClone ); + + + return pObj; +} + +SwFlyFrmFmt* SwDoc::_MakeFlySection( const SwPosition& rAnchPos, + const SwCntntNode& rNode, + RndStdIds eRequestId, + const SfxItemSet* pFlySet, + SwFrmFmt* pFrmFmt ) +{ + if( !pFrmFmt ) + pFrmFmt = GetFrmFmtFromPool( RES_POOLFRM_FRAME ); + + String sName; + if( !mbInReading ) + switch( rNode.GetNodeType() ) + { + case ND_GRFNODE: sName = GetUniqueGrfName(); break; + case ND_OLENODE: sName = GetUniqueOLEName(); break; + default: sName = GetUniqueFrameName(); break; + } + SwFlyFrmFmt* pFmt = MakeFlyFrmFmt( sName, pFrmFmt ); + + //Inhalt erzeugen und mit dem Format verbinden. + //CntntNode erzeugen und in die Autotextsection stellen + SwNodeRange aRange( GetNodes().GetEndOfAutotext(), -1, + GetNodes().GetEndOfAutotext() ); + GetNodes().SectionDown( &aRange, SwFlyStartNode ); + + pFmt->SetFmtAttr( SwFmtCntnt( rNode.StartOfSectionNode() )); + + + const SwFmtAnchor* pAnchor = 0; + if( pFlySet ) + { + pFlySet->GetItemState( RES_ANCHOR, sal_False, + (const SfxPoolItem**)&pAnchor ); + if( SFX_ITEM_SET == pFlySet->GetItemState( RES_CNTNT, sal_False )) + { + SfxItemSet aTmpSet( *pFlySet ); + aTmpSet.ClearItem( RES_CNTNT ); + pFmt->SetFmtAttr( aTmpSet ); + } + else + pFmt->SetFmtAttr( *pFlySet ); + } + + // Anker noch nicht gesetzt ? + RndStdIds eAnchorId = pAnchor ? pAnchor->GetAnchorId() + : pFmt->GetAnchor().GetAnchorId(); + // --> OD 2010-01-07 #i107811# + // Assure that at-page anchored fly frames have a page num or a content anchor set. + if ( !pAnchor || + ( FLY_AT_PAGE != pAnchor->GetAnchorId() && + !pAnchor->GetCntntAnchor() ) || + ( FLY_AT_PAGE == pAnchor->GetAnchorId() && + !pAnchor->GetCntntAnchor() && + pAnchor->GetPageNum() == 0 ) ) + { + // dann setze ihn, wird im Undo gebraucht + SwFmtAnchor aAnch( pFmt->GetAnchor() ); + if (pAnchor && (FLY_AT_FLY == pAnchor->GetAnchorId())) + { + SwPosition aPos( *rAnchPos.nNode.GetNode().FindFlyStartNode() ); + aAnch.SetAnchor( &aPos ); + eAnchorId = FLY_AT_FLY; + } + else + { + if( eRequestId != aAnch.GetAnchorId() && + SFX_ITEM_SET != pFmt->GetItemState( RES_ANCHOR, sal_True ) ) + { + aAnch.SetType( eRequestId ); + } + + eAnchorId = aAnch.GetAnchorId(); + if ( FLY_AT_PAGE != eAnchorId || + ( FLY_AT_PAGE == eAnchorId && + ( !pAnchor || + aAnch.GetPageNum() == 0 ) ) ) + { + aAnch.SetAnchor( &rAnchPos ); + } + } + // <-- + pFmt->SetFmtAttr( aAnch ); + } + else + eAnchorId = pFmt->GetAnchor().GetAnchorId(); + + if ( FLY_AS_CHAR == eAnchorId ) + { + xub_StrLen nStt = rAnchPos.nContent.GetIndex(); + SwTxtNode * pTxtNode = rAnchPos.nNode.GetNode().GetTxtNode(); + + ASSERT(pTxtNode!= 0, "There should be a SwTxtNode!"); + + if (pTxtNode != NULL) + { + SwFmtFlyCnt aFmt( pFmt ); + pTxtNode->InsertItem( aFmt, nStt, nStt ); + } + } + + if( SFX_ITEM_SET != pFmt->GetAttrSet().GetItemState( RES_FRM_SIZE )) + { + SwFmtFrmSize aFmtSize( ATT_VAR_SIZE, 0, DEF_FLY_WIDTH ); + const SwNoTxtNode* pNoTxtNode = rNode.GetNoTxtNode(); + if( pNoTxtNode ) + { + //Groesse einstellen. + Size aSize( pNoTxtNode->GetTwipSize() ); + if( MINFLY > aSize.Width() ) + aSize.Width() = DEF_FLY_WIDTH; + aFmtSize.SetWidth( aSize.Width() ); + if( aSize.Height() ) + { + aFmtSize.SetHeight( aSize.Height() ); + aFmtSize.SetHeightSizeType( ATT_FIX_SIZE ); + } + } + pFmt->SetFmtAttr( aFmtSize ); + } + + // Frames anlegen + if( GetRootFrm() ) + pFmt->MakeFrms(); // ??? + + if (GetIDocumentUndoRedo().DoesUndo()) + { + sal_uLong nNodeIdx = rAnchPos.nNode.GetIndex(); + xub_StrLen nCntIdx = rAnchPos.nContent.GetIndex(); + GetIDocumentUndoRedo().AppendUndo( + new SwUndoInsLayFmt( pFmt, nNodeIdx, nCntIdx )); + } + + SetModified(); + return pFmt; +} + +SwFlyFrmFmt* SwDoc::MakeFlySection( RndStdIds eAnchorType, + const SwPosition* pAnchorPos, + const SfxItemSet* pFlySet, + SwFrmFmt* pFrmFmt, sal_Bool bCalledFromShell ) +{ + SwFlyFrmFmt* pFmt = 0; + sal_Bool bCallMake = sal_True; + if ( !pAnchorPos && (FLY_AT_PAGE != eAnchorType) ) + { + const SwFmtAnchor* pAnch; + if( (pFlySet && SFX_ITEM_SET == pFlySet->GetItemState( + RES_ANCHOR, sal_False, (const SfxPoolItem**)&pAnch )) || + ( pFrmFmt && SFX_ITEM_SET == pFrmFmt->GetItemState( + RES_ANCHOR, sal_True, (const SfxPoolItem**)&pAnch )) ) + { + if ( (FLY_AT_PAGE != pAnch->GetAnchorId()) ) + { + pAnchorPos = pAnch->GetCntntAnchor(); + if (pAnchorPos) + { + bCallMake = sal_False; + } + } + } + } + + if( bCallMake ) + { + if( !pFrmFmt ) + pFrmFmt = GetFrmFmtFromPool( RES_POOLFRM_FRAME ); + + sal_uInt16 nCollId = static_cast<sal_uInt16>( + get(IDocumentSettingAccess::HTML_MODE) ? RES_POOLCOLL_TEXT : RES_POOLCOLL_FRAME ); + + /* #109161# If there exists no adjust item in the paragraph + style for the content node of the new fly section + propagate an existing adjust item at the anchor to the new + content node. */ + SwCntntNode * pNewTxtNd = GetNodes().MakeTxtNode + (SwNodeIndex( GetNodes().GetEndOfAutotext()), + GetTxtCollFromPool( nCollId )); + SwCntntNode * pAnchorNode = pAnchorPos->nNode.GetNode().GetCntntNode(); + + const SfxPoolItem * pItem = NULL; + + if (bCalledFromShell && !lcl_IsItemSet(*pNewTxtNd, RES_PARATR_ADJUST) && + SFX_ITEM_SET == pAnchorNode->GetSwAttrSet(). + GetItemState(RES_PARATR_ADJUST, sal_True, &pItem)) + static_cast<SwCntntNode *>(pNewTxtNd)->SetAttr(*pItem); + + pFmt = _MakeFlySection( *pAnchorPos, *pNewTxtNd, + eAnchorType, pFlySet, pFrmFmt ); + } + return pFmt; +} + +SwFlyFrmFmt* SwDoc::MakeFlyAndMove( const SwPaM& rPam, const SfxItemSet& rSet, + const SwSelBoxes* pSelBoxes, + SwFrmFmt *pParent ) +{ + SwFmtAnchor& rAnch = (SwFmtAnchor&)rSet.Get( RES_ANCHOR ); + + GetIDocumentUndoRedo().StartUndo( UNDO_INSLAYFMT, NULL ); + + SwFlyFrmFmt* pFmt = MakeFlySection( rAnch.GetAnchorId(), rPam.GetPoint(), + &rSet, pParent ); + + // Wenn Inhalt selektiert ist, so wird dieser jetzt zum Inhalt des + // neuen Rahmen. Sprich er wird in die entspr. Sektion des NodesArr + //gemoved. + + if( pFmt ) + { + do { // middle check loop + const SwFmtCntnt &rCntnt = pFmt->GetCntnt(); + ASSERT( rCntnt.GetCntntIdx(), "Kein Inhalt vorbereitet." ); + SwNodeIndex aIndex( *(rCntnt.GetCntntIdx()), 1 ); + SwCntntNode *pNode = aIndex.GetNode().GetCntntNode(); + + // ACHTUNG: nicht einen Index auf dem Stack erzeugen, sonst + // kann der CntntnNode am Ende nicht geloscht werden !! + SwPosition aPos( aIndex ); + aPos.nContent.Assign( pNode, 0 ); + + if( pSelBoxes && pSelBoxes->Count() ) + { + // Tabellenselection + // kopiere Teile aus einer Tabelle: lege eine Tabelle mit der + // Breite der Originalen an und move (kopiere/loesche) die + // selektierten Boxen. Die Groessen werden prozentual + // korrigiert. + + SwTableNode* pTblNd = (SwTableNode*)(*pSelBoxes)[0]-> + GetSttNd()->FindTableNode(); + if( !pTblNd ) + break; + + SwTable& rTbl = pTblNd->GetTable(); + + // ist die gesamte Tabelle selektiert ? + if( pSelBoxes->Count() == rTbl.GetTabSortBoxes().Count() ) + { + // verschiebe die gesamte Tabelle + SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode(), 1 ); + + // wird die gesamte Tabelle verschoben und steht diese + // in einem FlyFrame, dann erzeuge dahinter einen neuen + // TextNode. Dadurch bleibt dieser Fly erhalten ! + if( aRg.aEnd.GetNode().IsEndNode() ) + GetNodes().MakeTxtNode( aRg.aStart, + (SwTxtFmtColl*)GetDfltTxtFmtColl() ); + + MoveNodeRange( aRg, aPos.nNode, DOC_MOVEDEFAULT ); + } + else + { + rTbl.MakeCopy( this, aPos, *pSelBoxes ); + // Don't delete a part of a table with row span!! + // You could delete the content instead -> ToDo + //rTbl.DeleteSel( this, *pSelBoxes, 0, 0, sal_True, sal_True ); + } + + // wenn Tabelle im Rahmen, dann ohne nachfolgenden TextNode + aIndex = rCntnt.GetCntntIdx()->GetNode().EndOfSectionIndex() - 1; + ASSERT( aIndex.GetNode().GetTxtNode(), + "hier sollte ein TextNode stehen" ); + aPos.nContent.Assign( 0, 0 ); // Index abmelden !! + GetNodes().Delete( aIndex, 1 ); + +//JP erstmal ein Hack, solange keine Flys/Headers/Footers Undofaehig sind +// werden erstmal alle Undo - Objecte geloescht. +if( GetIDocumentUndoRedo().DoesUndo() ) +{ + GetIDocumentUndoRedo().DelAllUndoObj(); +} + + } + else + { +/* + // alle Pams verschieben + SwPaM* pTmp = (SwPaM*)&rPam; + do { + if( pTmp->HasMark() && + *pTmp->GetPoint() != *pTmp->GetMark() ) + MoveAndJoin( *pTmp, aPos ); + } while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) ); +*/ + // copy all Pams and then delete all + SwPaM* pTmp = (SwPaM*)&rPam; + sal_Bool bOldFlag = mbCopyIsMove; + bool const bOldUndo = GetIDocumentUndoRedo().DoesUndo(); + mbCopyIsMove = sal_True; + GetIDocumentUndoRedo().DoUndo(false); + do { + if( pTmp->HasMark() && + *pTmp->GetPoint() != *pTmp->GetMark() ) + { + CopyRange( *pTmp, aPos, false ); + } + pTmp = static_cast<SwPaM*>(pTmp->GetNext()); + } while ( &rPam != pTmp ); + mbCopyIsMove = bOldFlag; + GetIDocumentUndoRedo().DoUndo(bOldUndo); + + pTmp = (SwPaM*)&rPam; + do { + if( pTmp->HasMark() && + *pTmp->GetPoint() != *pTmp->GetMark() ) + { + DeleteAndJoin( *pTmp ); + } + pTmp = static_cast<SwPaM*>(pTmp->GetNext()); + } while ( &rPam != pTmp ); + } + } while( sal_False ); + } + + SetModified(); + + GetIDocumentUndoRedo().EndUndo( UNDO_INSLAYFMT, NULL ); + + return pFmt; +} + + + //Einfuegen eines DrawObjectes. Das Object muss bereits im DrawModel + // angemeldet sein. +SwDrawFrmFmt* SwDoc::Insert( const SwPaM &rRg, + SdrObject& rDrawObj, + const SfxItemSet* pFlyAttrSet, + SwFrmFmt* pDefFmt ) +{ + SwDrawFrmFmt *pFmt = MakeDrawFrmFmt( aEmptyStr, + pDefFmt ? pDefFmt : GetDfltFrmFmt() ); + + const SwFmtAnchor* pAnchor = 0; + if( pFlyAttrSet ) + { + pFlyAttrSet->GetItemState( RES_ANCHOR, sal_False, + (const SfxPoolItem**)&pAnchor ); + pFmt->SetFmtAttr( *pFlyAttrSet ); + } + + RndStdIds eAnchorId = pAnchor ? pAnchor->GetAnchorId() + : pFmt->GetAnchor().GetAnchorId(); + + // Anker noch nicht gesetzt ? + // DrawObjecte duerfen niemals in Kopf-/Fusszeilen landen. + const bool bIsAtCntnt = (FLY_AT_PAGE != eAnchorId); + + const SwNodeIndex* pChkIdx = 0; + if( !pAnchor ) + { + pChkIdx = &rRg.GetPoint()->nNode; + } + else if( bIsAtCntnt ) + { + pChkIdx = pAnchor->GetCntntAnchor() + ? &pAnchor->GetCntntAnchor()->nNode + : &rRg.GetPoint()->nNode; + } + + // OD 24.06.2003 #108784# - allow drawing objects in header/footer, but + // control objects aren't allowed in header/footer. + if( pChkIdx && + ::CheckControlLayer( &rDrawObj ) && + IsInHeaderFooter( *pChkIdx ) ) + { + pFmt->SetFmtAttr( SwFmtAnchor( eAnchorId = FLY_AT_PAGE ) ); + } + else if( !pAnchor || (bIsAtCntnt && !pAnchor->GetCntntAnchor() )) + { + // dann setze ihn, wird im Undo gebraucht + SwFmtAnchor aAnch( pAnchor ? *pAnchor : pFmt->GetAnchor() ); + eAnchorId = aAnch.GetAnchorId(); + if( FLY_AT_FLY == eAnchorId ) + { + SwPosition aPos( *rRg.GetNode()->FindFlyStartNode() ); + aAnch.SetAnchor( &aPos ); + } + else + { + aAnch.SetAnchor( rRg.GetPoint() ); + if ( FLY_AT_PAGE == eAnchorId ) + { + eAnchorId = rDrawObj.ISA( SdrUnoObj ) + ? FLY_AS_CHAR : FLY_AT_PARA; + aAnch.SetType( eAnchorId ); + } + } + pFmt->SetFmtAttr( aAnch ); + } + + // bei als Zeichen gebundenen Draws das Attribut im Absatz setzen + if ( FLY_AS_CHAR == eAnchorId ) + { + xub_StrLen nStt = rRg.GetPoint()->nContent.GetIndex(); + SwFmtFlyCnt aFmt( pFmt ); + rRg.GetPoint()->nNode.GetNode().GetTxtNode()->InsertItem( + aFmt, nStt, nStt ); + } + + SwDrawContact* pContact = new SwDrawContact( pFmt, &rDrawObj ); + + // ggfs. Frames anlegen + if( GetRootFrm() ) + { + pFmt->MakeFrms(); + // --> OD 2005-02-09 #i42319# - follow-up of #i35635# + // move object to visible layer + // --> OD 2007-07-10 #i79391# + if ( pContact->GetAnchorFrm() ) + { + pContact->MoveObjToVisibleLayer( &rDrawObj ); + } + // <-- + } + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo( new SwUndoInsLayFmt(pFmt, 0, 0) ); + } + + SetModified(); + return pFmt; +} + +/************************************************************************* +|* +|* SwDoc::GetAllFlyFmts +|* +|* Ersterstellung MA 14. Jul. 93 +|* Letzte Aenderung MD 23. Feb. 95 +|* +|*************************************************************************/ + +/*sal_Bool TstFlyRange( const SwPaM* pPam, sal_uInt32 nFlyPos ) +{ + sal_Bool bOk = sal_False; + const SwPaM* pTmp = pPam; + do { + bOk = pTmp->Start()->nNode.GetIndex() < nFlyPos && + pTmp->End()->nNode.GetIndex() > nFlyPos; + } while( !bOk && pPam != ( pTmp = (const SwPaM*)pTmp->GetNext() )); + return bOk; +} +*/ +/* -----------------------------04.04.00 10:55-------------------------------- + paragraph frames - o.k. if the PaM includes the paragraph from the beginning + to the beginning of the next paragraph at least + frames at character - o.k. if the pam start at least at the same position + as the frame + ---------------------------------------------------------------------------*/ +sal_Bool TstFlyRange( const SwPaM* pPam, const SwPosition* pFlyPos, + RndStdIds nAnchorId ) +{ + sal_Bool bOk = sal_False; + const SwPaM* pTmp = pPam; + do { + const sal_uInt32 nFlyIndex = pFlyPos->nNode.GetIndex(); + const SwPosition* pPaMStart = pTmp->Start(); + const SwPosition* pPaMEnd = pTmp->End(); + const sal_uInt32 nPamStartIndex = pPaMStart->nNode.GetIndex(); + const sal_uInt32 nPamEndIndex = pPaMEnd->nNode.GetIndex(); + if (FLY_AT_PARA == nAnchorId) + bOk = (nPamStartIndex < nFlyIndex && nPamEndIndex > nFlyIndex) || + (((nPamStartIndex == nFlyIndex) && (pPaMStart->nContent.GetIndex() == 0)) && + (nPamEndIndex > nFlyIndex)); + else + { + xub_StrLen nFlyContentIndex = pFlyPos->nContent.GetIndex(); + xub_StrLen nPamEndContentIndex = pPaMEnd->nContent.GetIndex(); + bOk = (nPamStartIndex < nFlyIndex && + (( nPamEndIndex > nFlyIndex )|| + ((nPamEndIndex == nFlyIndex) && + (nPamEndContentIndex > nFlyContentIndex))) ) + || + (((nPamStartIndex == nFlyIndex) && + (pPaMStart->nContent.GetIndex() <= nFlyContentIndex)) && + ((nPamEndIndex > nFlyIndex) || + (nPamEndContentIndex > nFlyContentIndex ))); + } + + } while( !bOk && pPam != ( pTmp = (const SwPaM*)pTmp->GetNext() )); + return bOk; +} + + +void SwDoc::GetAllFlyFmts( SwPosFlyFrms& rPosFlyFmts, + const SwPaM* pCmpRange, sal_Bool bDrawAlso ) const +{ + SwPosFlyFrm *pFPos = 0; + SwFrmFmt *pFly; + + // erstmal alle Absatzgebundenen einsammeln + for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + pFly = (*GetSpzFrmFmts())[ n ]; + bool bDrawFmt = bDrawAlso ? RES_DRAWFRMFMT == pFly->Which() : false; + bool bFlyFmt = RES_FLYFRMFMT == pFly->Which(); + if( bFlyFmt || bDrawFmt ) + { + const SwFmtAnchor& rAnchor = pFly->GetAnchor(); + SwPosition const*const pAPos = rAnchor.GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == rAnchor.GetAnchorId()) || + (FLY_AT_FLY == rAnchor.GetAnchorId()) || + (FLY_AT_CHAR == rAnchor.GetAnchorId()))) + { + if( pCmpRange && + !TstFlyRange( pCmpRange, pAPos, rAnchor.GetAnchorId() )) + continue; // kein gueltiger FlyFrame + pFPos = new SwPosFlyFrm( pAPos->nNode, pFly, rPosFlyFmts.Count() ); + rPosFlyFmts.Insert( pFPos ); + } + } + } + + // kein Layout oder nur ein Teil, dann wars das + // Seitenbezogen Flys nur, wenn vollstaendig "gewuenscht" wird ! + if( !GetRootFrm() || pCmpRange ) + return; + + pFPos = 0; + SwPageFrm *pPage = (SwPageFrm*)GetRootFrm()->GetLower(); + while( pPage ) + { + if( pPage->GetSortedObjs() ) + { + SwSortedObjs &rObjs = *pPage->GetSortedObjs(); + for( sal_uInt16 i = 0; i < rObjs.Count(); ++i) + { + SwAnchoredObject* pAnchoredObj = rObjs[i]; + if ( pAnchoredObj->ISA(SwFlyFrm) ) + pFly = &(pAnchoredObj->GetFrmFmt()); + else if ( bDrawAlso ) + pFly = &(pAnchoredObj->GetFrmFmt()); + else + continue; + + const SwFmtAnchor& rAnchor = pFly->GetAnchor(); + if ((FLY_AT_PARA != rAnchor.GetAnchorId()) && + (FLY_AT_FLY != rAnchor.GetAnchorId()) && + (FLY_AT_CHAR != rAnchor.GetAnchorId())) + { + const SwCntntFrm * pCntntFrm = pPage->FindFirstBodyCntnt(); + if ( !pCntntFrm ) + { + //Oops! Eine leere Seite. Damit der Rahmen nicht ganz + //verlorengeht (RTF) suchen wir schnell den letzen + //Cntnt der vor der Seite steht. + SwPageFrm *pPrv = (SwPageFrm*)pPage->GetPrev(); + while ( !pCntntFrm && pPrv ) + { + pCntntFrm = pPrv->FindFirstBodyCntnt(); + pPrv = (SwPageFrm*)pPrv->GetPrev(); + } + } + if ( pCntntFrm ) + { + SwNodeIndex aIdx( *pCntntFrm->GetNode() ); + pFPos = new SwPosFlyFrm( aIdx, pFly, rPosFlyFmts.Count() ); + } + } + if ( pFPos ) + { + rPosFlyFmts.Insert( pFPos ); + pFPos = 0; + } + } + } + pPage = (SwPageFrm*)pPage->GetNext(); + } +} + +/************************************************************************* +|* +|* SwDoc::InsertLabel() +|* +|* Ersterstellung MA 11. Feb. 94 +|* Letzte Aenderung MA 12. Nov. 97 +|* +|*************************************************************************/ + +/* #i6447# changed behaviour if lcl_CpyAttr: + + If the old item set contains the item to set (no inheritance) copy the item + into the new set. + + If the old item set contains the item by inheritance and the new set + contains the item, too: + If the two items differ copy the item from the old set to the new set. + + Otherwise the new set will not be changed. +*/ + +void lcl_CpyAttr( SfxItemSet &rNewSet, const SfxItemSet &rOldSet, sal_uInt16 nWhich ) +{ + const SfxPoolItem *pOldItem = NULL, *pNewItem = NULL; + + rOldSet.GetItemState( nWhich, sal_False, &pOldItem); + if (pOldItem != NULL) + rNewSet.Put( *pOldItem ); + else + { + pOldItem = rOldSet.GetItem( nWhich, sal_True); + if (pOldItem != NULL) + { + pNewItem = rNewSet.GetItem( nWhich, sal_True); + if (pNewItem != NULL) + { + if (*pOldItem != *pNewItem) + rNewSet.Put( *pOldItem ); + } + else { + ASSERT(0, "What am I doing here?"); + } + } + else { + ASSERT(0, "What am I doing here?"); + } + } + +} + + +static SwFlyFrmFmt * +lcl_InsertLabel(SwDoc & rDoc, SwTxtFmtColls *const pTxtFmtCollTbl, + SwUndoInsertLabel *const pUndo, + SwLabelType const eType, String const& rTxt, String const& rSeparator, + const String& rNumberingSeparator, + const sal_Bool bBefore, const sal_uInt16 nId, const sal_uLong nNdIdx, + const String& rCharacterStyle, + const sal_Bool bCpyBrd ) +{ + ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + + sal_Bool bTable = sal_False; //Um etwas Code zu sparen. + + //Erstmal das Feld bauen, weil ueber den Namen die TxtColl besorgt werden + //muss + OSL_ENSURE( nId == USHRT_MAX || nId < rDoc.GetFldTypes()->Count(), + "FldType index out of bounds." ); + SwFieldType *pType = (nId != USHRT_MAX) ? (*rDoc.GetFldTypes())[nId] : NULL; + OSL_ENSURE(!pType || pType->Which() == RES_SETEXPFLD, "wrong Id for Label"); + + SwTxtFmtColl * pColl = NULL; + if( pType ) + { + for( sal_uInt16 i = pTxtFmtCollTbl->Count(); i; ) + { + if( (*pTxtFmtCollTbl)[ --i ]->GetName() == pType->GetName() ) + { + pColl = (*pTxtFmtCollTbl)[i]; + break; + } + } + DBG_ASSERT( pColl, "no text collection found" ); + } + + if( !pColl ) + { + pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_LABEL ); + } + + SwTxtNode *pNew = NULL; + SwFlyFrmFmt* pNewFmt = NULL; + + switch ( eType ) + { + case LTYPE_TABLE: + bTable = sal_True; + /* Kein Break hier */ + case LTYPE_FLY: + //Am Anfang/Ende der Fly-Section den entsprechenden Node mit Feld + //einfuegen (Frame wird automatisch erzeugt). + { + SwStartNode *pSttNd = rDoc.GetNodes()[nNdIdx]->GetStartNode(); + ASSERT( pSttNd, "Kein StartNode in InsertLabel." ); + sal_uLong nNode; + if( bBefore ) + { + nNode = pSttNd->GetIndex(); + if( !bTable ) + ++nNode; + } + else + { + nNode = pSttNd->EndOfSectionIndex(); + if( bTable ) + ++nNode; + } + + if( pUndo ) + pUndo->SetNodePos( nNode ); + + //Node fuer Beschriftungsabsatz erzeugen. + SwNodeIndex aIdx( rDoc.GetNodes(), nNode ); + pNew = rDoc.GetNodes().MakeTxtNode( aIdx, pColl ); + } + break; + + case LTYPE_OBJECT: + { + //Rahmen zerstoeren, neuen Rahmen einfuegen, entsprechenden + // Node mit Feld in den neuen Rahmen, den alten Rahmen mit + // dem Object (Grafik/Ole) absatzgebunden in den neuen Rahmen, + // Frames erzeugen. + + //Erstmal das Format zum Fly besorgen und das Layout entkoppeln. + SwFrmFmt *pOldFmt = rDoc.GetNodes()[nNdIdx]->GetFlyFmt(); + ASSERT( pOldFmt, "Format des Fly nicht gefunden." ); + // --> OD #i115719# + // <title> and <description> attributes are lost when calling <DelFrms()>. + // Thus, keep them and restore them after the calling <MakeFrms()> + const bool bIsSwFlyFrmFmtInstance( dynamic_cast<SwFlyFrmFmt*>(pOldFmt) != 0 ); + const String sTitle( bIsSwFlyFrmFmtInstance + ? static_cast<SwFlyFrmFmt*>(pOldFmt)->GetObjTitle() + : String() ); + const String sDescription( bIsSwFlyFrmFmtInstance + ? static_cast<SwFlyFrmFmt*>(pOldFmt)->GetObjDescription() + : String() ); + // <-- + pOldFmt->DelFrms(); + + pNewFmt = rDoc.MakeFlyFrmFmt( rDoc.GetUniqueFrameName(), + rDoc.GetFrmFmtFromPool(RES_POOLFRM_FRAME) ); + + /* #i6447#: Only the selected items are copied from the old + format. */ + SfxItemSet* pNewSet = pNewFmt->GetAttrSet().Clone( sal_True ); + + + //Diejenigen Attribute uebertragen die auch gesetzt sind, + //andere sollen weiterhin aus den Vorlagen gueltig werden. + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_PRINT ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_OPAQUE ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_PROTECT ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_SURROUND ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_VERT_ORIENT ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_HORI_ORIENT ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_LR_SPACE ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_UL_SPACE ); + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_BACKGROUND ); + if( bCpyBrd ) + { + // JP 07.07.99: Bug 67029 - if at Grafik no BoxItem but + // in the new Format is any, then set the + // default item in the new Set. Because + // the Size of the Grafik have never been + // changed! + const SfxPoolItem *pItem; + if( SFX_ITEM_SET == pOldFmt->GetAttrSet(). + GetItemState( RES_BOX, sal_True, &pItem )) + pNewSet->Put( *pItem ); + else if( SFX_ITEM_SET == pNewFmt->GetAttrSet(). + GetItemState( RES_BOX, sal_True )) + pNewSet->Put( *GetDfltAttr( RES_BOX ) ); + + if( SFX_ITEM_SET == pOldFmt->GetAttrSet(). + GetItemState( RES_SHADOW, sal_True, &pItem )) + pNewSet->Put( *pItem ); + else if( SFX_ITEM_SET == pNewFmt->GetAttrSet(). + GetItemState( RES_SHADOW, sal_True )) + pNewSet->Put( *GetDfltAttr( RES_SHADOW ) ); + } + else + { + //Die Attribute hart setzen, weil sie sonst aus der + // Vorlage kommen koenten und dann passt die + // Grossenberechnung nicht mehr. + pNewSet->Put( SvxBoxItem(RES_BOX) ); + pNewSet->Put( SvxShadowItem(RES_SHADOW) ); + + } + + //Anker immer uebertragen, ist sowieso ein hartes Attribut. + pNewSet->Put( pOldFmt->GetAnchor() ); + + //In der Hoehe soll der neue Varabel sein! + SwFmtFrmSize aFrmSize( pOldFmt->GetFrmSize() ); + aFrmSize.SetHeightSizeType( ATT_MIN_SIZE ); + pNewSet->Put( aFrmSize ); + + SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( + SwNodeIndex( rDoc.GetNodes().GetEndOfAutotext() ), + SwFlyStartNode, pColl ); + pNewSet->Put( SwFmtCntnt( pSttNd )); + + pNewFmt->SetFmtAttr( *pNewSet ); + + //Bei InCntnt's wird es spannend: Das TxtAttribut muss + //vernichtet werden. Leider reisst dies neben den Frms auch + //noch das Format mit in sein Grab. Um dass zu unterbinden + //loesen wir vorher die Verbindung zwischen Attribut und Format. + + const SwFmtAnchor& rAnchor = pNewFmt->GetAnchor(); + if ( FLY_AS_CHAR == rAnchor.GetAnchorId() ) + { + const SwPosition *pPos = rAnchor.GetCntntAnchor(); + SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt(nIdx, RES_TXTATR_FLYCNT); + + ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + ASSERT( pHnt && pHnt->GetFlyCnt().GetFrmFmt() == pOldFmt, + "Wrong TxtFlyCnt-Hint." ); + + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt( + pNewFmt ); + } + + + //Der Alte soll keinen Umlauf haben, und er soll oben/mittig + //ausgerichtet sein. + //Ausserdem soll die Breite 100% betragen und bei Aenderungen + //Die Hoehe mit anpassen. + pNewSet->ClearItem(); + + pNewSet->Put( SwFmtSurround( SURROUND_NONE ) ); + pNewSet->Put( SvxOpaqueItem( RES_OPAQUE, sal_True ) ); + pNewSet->Put( SwFmtVertOrient( text::VertOrientation::TOP ) ); + pNewSet->Put( SwFmtHoriOrient( text::HoriOrientation::CENTER ) ); + + aFrmSize = pOldFmt->GetFrmSize(); + aFrmSize.SetWidthPercent( 100 ); + aFrmSize.SetHeightPercent( 255 ); + pNewSet->Put( aFrmSize ); + + //Die Attribute setzen wir hart, weil sie sonst aus der Vorlage + //kommen koenten und dann passt die Grossenberechnung nicht mehr. + if( bCpyBrd ) + { + pNewSet->Put( SvxBoxItem(RES_BOX) ); + pNewSet->Put( SvxShadowItem(RES_SHADOW) ); + } + pNewSet->Put( SvxLRSpaceItem(RES_LR_SPACE) ); + pNewSet->Put( SvxULSpaceItem(RES_UL_SPACE) ); + + //Der Alte ist absatzgebunden, und zwar am Absatz im neuen. + SwFmtAnchor aAnch( FLY_AT_PARA ); + SwNodeIndex aAnchIdx( *pNewFmt->GetCntnt().GetCntntIdx(), 1 ); + pNew = aAnchIdx.GetNode().GetTxtNode(); + SwPosition aPos( aAnchIdx ); + aAnch.SetAnchor( &aPos ); + pNewSet->Put( aAnch ); + + if( pUndo ) + pUndo->SetFlys( *pOldFmt, *pNewSet, *pNewFmt ); + else + pOldFmt->SetFmtAttr( *pNewSet ); + + delete pNewSet; + + //Nun nur noch die Flys erzeugen lassen. Das ueberlassen + //wir vorhanden Methoden (insb. fuer InCntFlys etwas aufwendig). + pNewFmt->MakeFrms(); + // --> OD #i115719# + if ( bIsSwFlyFrmFmtInstance ) + { + static_cast<SwFlyFrmFmt*>(pOldFmt)->SetObjTitle( sTitle ); + static_cast<SwFlyFrmFmt*>(pOldFmt)->SetObjDescription( sDescription ); + } + // <-- + } + break; + + default: + OSL_ENSURE(false, "unknown LabelType?"); + } + ASSERT( pNew, "No Label inserted" ); + if( pNew ) + { + //#i61007# order of captions + sal_Bool bOrderNumberingFirst = SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst(); + //String aufbereiten + String aTxt; + if( bOrderNumberingFirst ) + { + aTxt = rNumberingSeparator; + } + if( pType) + { + aTxt += pType->GetName(); + if( !bOrderNumberingFirst ) + aTxt += ' '; + } + xub_StrLen nIdx = aTxt.Len(); + if( rTxt.Len() > 0 ) + { + aTxt += rSeparator; + } + xub_StrLen nSepIdx = aTxt.Len(); + aTxt += rTxt; + + //String einfuegen + SwIndex aIdx( pNew, 0 ); + pNew->InsertText( aTxt, aIdx ); + + // + //Feld einfuegen + if(pType) + { + SwSetExpField aFld( (SwSetExpFieldType*)pType, aEmptyStr, SVX_NUM_ARABIC); + if( bOrderNumberingFirst ) + nIdx = 0; + SwFmtFld aFmt( aFld ); + pNew->InsertItem( aFmt, nIdx, nIdx ); + if(rCharacterStyle.Len()) + { + SwCharFmt* pCharFmt = rDoc.FindCharFmtByName(rCharacterStyle); + if( !pCharFmt ) + { + const sal_uInt16 nMyId = SwStyleNameMapper::GetPoolIdFromUIName(rCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT); + pCharFmt = rDoc.GetCharFmtFromPool( nMyId ); + } + if (pCharFmt) + { + SwFmtCharFmt aCharFmt( pCharFmt ); + pNew->InsertItem( aCharFmt, 0, + nSepIdx + 1, nsSetAttrMode::SETATTR_DONTEXPAND ); + } + } + } + + if ( bTable ) + { + if ( bBefore ) + { + if ( !pNew->GetSwAttrSet().GetKeep().GetValue() ) + pNew->SetAttr( SvxFmtKeepItem( sal_True, RES_KEEP ) ); + } + else + { + SwTableNode *const pNd = + rDoc.GetNodes()[nNdIdx]->GetStartNode()->GetTableNode(); + SwTable &rTbl = pNd->GetTable(); + if ( !rTbl.GetFrmFmt()->GetKeep().GetValue() ) + rTbl.GetFrmFmt()->SetFmtAttr( SvxFmtKeepItem( sal_True, RES_KEEP ) ); + if ( pUndo ) + pUndo->SetUndoKeep(); + } + } + rDoc.SetModified(); + } + + return pNewFmt; +} + +SwFlyFrmFmt * +SwDoc::InsertLabel( + SwLabelType const eType, String const& rTxt, String const& rSeparator, + String const& rNumberingSeparator, + sal_Bool const bBefore, sal_uInt16 const nId, sal_uLong const nNdIdx, + String const& rCharacterStyle, + sal_Bool const bCpyBrd ) +{ + SwUndoInsertLabel * pUndo(0); + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoInsertLabel( + eType, rTxt, rSeparator, rNumberingSeparator, + bBefore, nId, rCharacterStyle, bCpyBrd ); + } + + SwFlyFrmFmt *const pNewFmt = lcl_InsertLabel(*this, pTxtFmtCollTbl, pUndo, + eType, rTxt, rSeparator, rNumberingSeparator, bBefore, + nId, nNdIdx, rCharacterStyle, bCpyBrd); + + if (pUndo) + { + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + else + { + GetIDocumentUndoRedo().DelAllUndoObj(); + } + + return pNewFmt; +} + + +/************************************************************************* +|* +|* SwDoc::InsertDrawLabel() +|* +|* Ersterstellung MIB 7. Dez. 98 +|* Letzte Aenderung MIB 7. Dez. 98 +|* +|*************************************************************************/ + +static SwFlyFrmFmt * +lcl_InsertDrawLabel( SwDoc & rDoc, SwTxtFmtColls *const pTxtFmtCollTbl, + SwUndoInsertLabel *const pUndo, SwDrawFrmFmt *const pOldFmt, + String const& rTxt, + const String& rSeparator, + const String& rNumberSeparator, + const sal_uInt16 nId, + const String& rCharacterStyle, + SdrObject& rSdrObj ) +{ + ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo()); + ::sw::DrawUndoGuard const drawUndoGuard(rDoc.GetIDocumentUndoRedo()); + + // Erstmal das Feld bauen, weil ueber den Namen die TxtColl besorgt + // werden muss + OSL_ENSURE( nId == USHRT_MAX || nId < rDoc.GetFldTypes()->Count(), + "FldType index out of bounds" ); + SwFieldType *pType = nId != USHRT_MAX ? (*rDoc.GetFldTypes())[nId] : 0; + OSL_ENSURE( !pType || pType->Which() == RES_SETEXPFLD, "Wrong label id" ); + + SwTxtFmtColl *pColl = NULL; + if( pType ) + { + for( sal_uInt16 i = pTxtFmtCollTbl->Count(); i; ) + { + if( (*pTxtFmtCollTbl)[ --i ]->GetName() == pType->GetName() ) + { + pColl = (*pTxtFmtCollTbl)[i]; + break; + } + } + DBG_ASSERT( pColl, "no text collection found" ); + } + + if( !pColl ) + { + pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_LABEL ); + } + + SwTxtNode* pNew = NULL; + SwFlyFrmFmt* pNewFmt = NULL; + + // Rahmen zerstoeren, neuen Rahmen einfuegen, entsprechenden + // Node mit Feld in den neuen Rahmen, den alten Rahmen mit + // dem Object (Grafik/Ole) absatzgebunden in den neuen Rahmen, + // Frames erzeugen. + + // OD 27.11.2003 #112045# - Keep layer ID of drawing object before removing + // its frames. + // Note: The layer ID is passed to the undo and have to be the correct value. + // Removing the frames of the drawing object changes its layer. + const SdrLayerID nLayerId = rSdrObj.GetLayer(); + + pOldFmt->DelFrms(); + + //Bei InCntnt's wird es spannend: Das TxtAttribut muss + //vernichtet werden. Leider reisst dies neben den Frms auch + //noch das Format mit in sein Grab. Um dass zu unterbinden + //loesen wir vorher die Verbindung zwischen Attribut und Format. + SfxItemSet* pNewSet = pOldFmt->GetAttrSet().Clone( sal_False ); + + // Ggf. Groesse und Position des Rahmens schuetzen + if ( rSdrObj.IsMoveProtect() || rSdrObj.IsResizeProtect() ) + { + SvxProtectItem aProtect(RES_PROTECT); + aProtect.SetCntntProtect( sal_False ); + aProtect.SetPosProtect( rSdrObj.IsMoveProtect() ); + aProtect.SetSizeProtect( rSdrObj.IsResizeProtect() ); + pNewSet->Put( aProtect ); + } + + // Umlauf uebernehmen + lcl_CpyAttr( *pNewSet, pOldFmt->GetAttrSet(), RES_SURROUND ); + + // Den Rahmen ggf. in den Hintergrund schicken. + // OD 02.07.2003 #108784# - consider 'invisible' hell layer. + if ( rDoc.GetHellId() != nLayerId && + rDoc.GetInvisibleHellId() != nLayerId ) + { + SvxOpaqueItem aOpaque( RES_OPAQUE ); + aOpaque.SetValue( sal_True ); + pNewSet->Put( aOpaque ); + } + + // Position uebernehmen + // OD 2004-04-15 #i26791# - use directly the positioning attributes of + // the drawing object. + pNewSet->Put( pOldFmt->GetHoriOrient() ); + pNewSet->Put( pOldFmt->GetVertOrient() ); + + pNewSet->Put( pOldFmt->GetAnchor() ); + + //In der Hoehe soll der neue Varabel sein! + Size aSz( rSdrObj.GetCurrentBoundRect().GetSize() ); + SwFmtFrmSize aFrmSize( ATT_MIN_SIZE, aSz.Width(), aSz.Height() ); + pNewSet->Put( aFrmSize ); + + // Abstaende auf den neuen Rahmen uebertragen. Eine Umrandung + // gibt es beu Zeichen-Objekten nicht, also muss sie geloescht + // werden. + // MA: Falsch sie wird nicht gesetzt, denn die aus der Vorlage + // soll ruhig wirksam werden + pNewSet->Put( pOldFmt->GetLRSpace() ); + pNewSet->Put( pOldFmt->GetULSpace() ); + + SwStartNode* pSttNd = + rDoc.GetNodes().MakeTextSection( + SwNodeIndex( rDoc.GetNodes().GetEndOfAutotext() ), + SwFlyStartNode, pColl ); + + pNewFmt = rDoc.MakeFlyFrmFmt( rDoc.GetUniqueFrameName(), + rDoc.GetFrmFmtFromPool( RES_POOLFRM_FRAME ) ); + + // JP 28.10.99: Bug 69487 - set border and shadow to default if the + // template contains any. + if( SFX_ITEM_SET == pNewFmt->GetAttrSet().GetItemState( RES_BOX, sal_True )) + pNewSet->Put( *GetDfltAttr( RES_BOX ) ); + + if( SFX_ITEM_SET == pNewFmt->GetAttrSet().GetItemState(RES_SHADOW,sal_True)) + pNewSet->Put( *GetDfltAttr( RES_SHADOW ) ); + + pNewFmt->SetFmtAttr( SwFmtCntnt( pSttNd )); + pNewFmt->SetFmtAttr( *pNewSet ); + + const SwFmtAnchor& rAnchor = pNewFmt->GetAnchor(); + if ( FLY_AS_CHAR == rAnchor.GetAnchorId() ) + { + const SwPosition *pPos = rAnchor.GetCntntAnchor(); + SwTxtNode *pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + ASSERT( pTxtNode->HasHints(), "Missing FlyInCnt-Hint." ); + const xub_StrLen nIdx = pPos->nContent.GetIndex(); + SwTxtAttr * const pHnt = + pTxtNode->GetTxtAttrForCharAt( nIdx, RES_TXTATR_FLYCNT ); + +#ifdef DBG_UTIL + ASSERT( pHnt && pHnt->Which() == RES_TXTATR_FLYCNT, + "Missing FlyInCnt-Hint." ); + ASSERT( pHnt && ((SwFmtFlyCnt&)pHnt->GetFlyCnt()). + GetFrmFmt() == (SwFrmFmt*)pOldFmt, + "Wrong TxtFlyCnt-Hint." ); +#endif + const_cast<SwFmtFlyCnt&>(pHnt->GetFlyCnt()).SetFlyFmt( pNewFmt ); + } + + + //Der Alte soll keinen Umlauf haben, und er soll oben/mittig + //ausgerichtet sein. + pNewSet->ClearItem(); + + pNewSet->Put( SwFmtSurround( SURROUND_NONE ) ); + if (nLayerId == rDoc.GetHellId()) + { + rSdrObj.SetLayer( rDoc.GetHeavenId() ); + } + // OD 02.07.2003 #108784# - consider drawing objects in 'invisible' hell layer + else if (nLayerId == rDoc.GetInvisibleHellId()) + { + rSdrObj.SetLayer( rDoc.GetInvisibleHeavenId() ); + } + pNewSet->Put( SvxLRSpaceItem( RES_LR_SPACE ) ); + pNewSet->Put( SvxULSpaceItem( RES_UL_SPACE ) ); + + // OD 2004-04-15 #i26791# - set position of the drawing object, which is labeled. + pNewSet->Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ) ); + pNewSet->Put( SwFmtHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::FRAME ) ); + + //Der Alte ist absatzgebunden, und zwar am Absatz im neuen. + SwFmtAnchor aAnch( FLY_AT_PARA ); + SwNodeIndex aAnchIdx( *pNewFmt->GetCntnt().GetCntntIdx(), 1 ); + pNew = aAnchIdx.GetNode().GetTxtNode(); + SwPosition aPos( aAnchIdx ); + aAnch.SetAnchor( &aPos ); + pNewSet->Put( aAnch ); + + if( pUndo ) + { + pUndo->SetFlys( *pOldFmt, *pNewSet, *pNewFmt ); + // OD 2004-04-15 #i26791# - position no longer needed + pUndo->SetDrawObj( nLayerId ); + } + else + pOldFmt->SetFmtAttr( *pNewSet ); + + delete pNewSet; + + //Nun nur noch die Flys erzeugen lassen. Das ueberlassen + //wir vorhanden Methoden (insb. fuer InCntFlys etwas aufwendig). + pNewFmt->MakeFrms(); + + ASSERT( pNew, "No Label inserted" ); + + if( pNew ) + { + //#i61007# order of captions + sal_Bool bOrderNumberingFirst = SW_MOD()->GetModuleConfig()->IsCaptionOrderNumberingFirst(); + + // prepare string + String aTxt; + if( bOrderNumberingFirst ) + { + aTxt = rNumberSeparator; + } + if ( pType ) + { + aTxt += pType->GetName(); + if( !bOrderNumberingFirst ) + aTxt += ' '; + } + xub_StrLen nIdx = aTxt.Len(); + aTxt += rSeparator; + xub_StrLen nSepIdx = aTxt.Len(); + aTxt += rTxt; + + // insert text + SwIndex aIdx( pNew, 0 ); + pNew->InsertText( aTxt, aIdx ); + + // insert field + if ( pType ) + { + SwSetExpField aFld( (SwSetExpFieldType*)pType, aEmptyStr, SVX_NUM_ARABIC ); + if( bOrderNumberingFirst ) + nIdx = 0; + SwFmtFld aFmt( aFld ); + pNew->InsertItem( aFmt, nIdx, nIdx ); + if ( rCharacterStyle.Len() ) + { + SwCharFmt * pCharFmt = rDoc.FindCharFmtByName(rCharacterStyle); + if ( !pCharFmt ) + { + const sal_uInt16 nMyId = SwStyleNameMapper::GetPoolIdFromUIName( rCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); + pCharFmt = rDoc.GetCharFmtFromPool( nMyId ); + } + if ( pCharFmt ) + { + SwFmtCharFmt aCharFmt( pCharFmt ); + pNew->InsertItem( aCharFmt, 0, nSepIdx + 1, + nsSetAttrMode::SETATTR_DONTEXPAND ); + } + } + } + } + + return pNewFmt; +} + +SwFlyFrmFmt* SwDoc::InsertDrawLabel( + String const& rTxt, + String const& rSeparator, + String const& rNumberSeparator, + sal_uInt16 const nId, + String const& rCharacterStyle, + SdrObject& rSdrObj ) +{ + SwDrawContact *const pContact = + static_cast<SwDrawContact*>(GetUserCall( &rSdrObj )); + OSL_ENSURE( RES_DRAWFRMFMT == pContact->GetFmt()->Which(), + "InsertDrawLabel(): not a DrawFrmFmt" ); + if (!pContact) + return 0; + + SwDrawFrmFmt* pOldFmt = (SwDrawFrmFmt *)pContact->GetFmt(); + if (!pOldFmt) + return 0; + + SwUndoInsertLabel * pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + pUndo = new SwUndoInsertLabel( + LTYPE_DRAW, rTxt, rSeparator, rNumberSeparator, sal_False, + nId, rCharacterStyle, sal_False ); + } + + SwFlyFrmFmt *const pNewFmt = lcl_InsertDrawLabel( + *this, pTxtFmtCollTbl, pUndo, pOldFmt, + rTxt, rSeparator, rNumberSeparator, nId, rCharacterStyle, rSdrObj); + + if (pUndo) + { + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + else + { + GetIDocumentUndoRedo().DelAllUndoObj(); + } + + return pNewFmt; +} + + +/************************************************************************* +|* +|* IDocumentTimerAccess-methods +|* +|*************************************************************************/ + +void SwDoc::StartIdling() +{ + mbStartIdleTimer = sal_True; + if( !mIdleBlockCount ) + aIdleTimer.Start(); +} + +void SwDoc::StopIdling() +{ + mbStartIdleTimer = sal_False; + aIdleTimer.Stop(); +} + +void SwDoc::BlockIdling() +{ + aIdleTimer.Stop(); + ++mIdleBlockCount; +} + +void SwDoc::UnblockIdling() +{ + --mIdleBlockCount; + if( !mIdleBlockCount && mbStartIdleTimer && !aIdleTimer.IsActive() ) + aIdleTimer.Start(); +} + + +/************************************************************************* +|* +|* SwDoc::DoIdleJobs() +|* +|* Ersterstellung OK 30.03.94 +|* Letzte Aenderung MA 09. Jun. 95 +|* +|*************************************************************************/ + +IMPL_LINK( SwDoc, DoIdleJobs, Timer *, pTimer ) +{ +#ifdef TIMELOG + static ::rtl::Logfile* pModLogFile = 0; + if( !pModLogFile ) + pModLogFile = new ::rtl::Logfile( "First DoIdleJobs" ); +#endif + + if( GetRootFrm() && GetRootFrm()->GetCurrShell() && + !SfxProgress::GetActiveProgress( pDocShell ) ) + { + ViewShell *pSh, *pStartSh; + pSh = pStartSh = GetRootFrm()->GetCurrShell(); + do { + if( pSh->ActionPend() ) + { + if( pTimer ) + pTimer->Start(); + return 0; + } + pSh = (ViewShell*)pSh->GetNext(); + } while( pSh != pStartSh ); + + if (GetRootFrm()->IsNeedGrammarCheck()) + { + sal_Bool bIsOnlineSpell = pSh->GetViewOptions()->IsOnlineSpell(); + + sal_Bool bIsAutoGrammar = sal_False; + SvtLinguConfig().GetProperty( ::rtl::OUString::createFromAscii( + UPN_IS_GRAMMAR_AUTO ) ) >>= bIsAutoGrammar; + + if (bIsOnlineSpell && bIsAutoGrammar) + StartGrammarChecking( *this ); + } + + sal_uInt16 nFldUpdFlag; + if( GetRootFrm()->IsIdleFormat() ) + GetRootFrm()->GetCurrShell()->LayoutIdle(); + else if( ( AUTOUPD_FIELD_ONLY == + ( nFldUpdFlag = static_cast<sal_uInt16>(getFieldUpdateFlags(true)) ) + || AUTOUPD_FIELD_AND_CHARTS == nFldUpdFlag ) && + GetUpdtFlds().IsFieldsDirty() && + !GetUpdtFlds().IsInUpdateFlds() && + !IsExpFldsLocked() + // das umschalten der Feldname fuehrt zu keinem Update der + // Felder, also der "Hintergrund-Update" immer erfolgen + /* && !pStartSh->GetViewOptions()->IsFldName()*/ ) + { + // chaos::Action-Klammerung! + GetUpdtFlds().SetInUpdateFlds( sal_True ); + + GetRootFrm()->StartAllAction(); + + // no jump on update of fields #i85168# + const sal_Bool bOldLockView = pStartSh->IsViewLocked(); + pStartSh->LockView( sal_True ); + + GetSysFldType( RES_CHAPTERFLD )->Modify( 0, 0 ); // KapitelFld + UpdateExpFlds( 0, sal_False ); // Expression-Felder Updaten + UpdateTblFlds(NULL); // Tabellen + UpdateRefFlds(NULL); // Referenzen + + GetRootFrm()->EndAllAction(); + + pStartSh->LockView( bOldLockView ); + + GetUpdtFlds().SetInUpdateFlds( sal_False ); + GetUpdtFlds().SetFieldsDirty( sal_False ); + } + } +#ifdef TIMELOG + if( pModLogFile && 1 != (long)pModLogFile ) + delete pModLogFile, ((long&)pModLogFile) = 1; +#endif + if( pTimer ) + pTimer->Start(); + return 0; +} + +IMPL_STATIC_LINK( SwDoc, BackgroundDone, SvxBrushItem*, EMPTYARG ) +{ + ViewShell *pSh, *pStartSh; + pSh = pStartSh = pThis->GetRootFrm()->GetCurrShell(); + if( pStartSh ) + do { + if( pSh->GetWin() ) + { + //Fuer Repaint mir virtuellen Device sorgen. + pSh->LockPaint(); + pSh->UnlockPaint( sal_True ); + } + pSh = (ViewShell*)pSh->GetNext(); + } while( pSh != pStartSh ); + return 0; +} + +static String lcl_GetUniqueFlyName( const SwDoc* pDoc, sal_uInt16 nDefStrId ) +{ + ResId aId( nDefStrId, *pSwResMgr ); + String aName( aId ); + xub_StrLen nNmLen = aName.Len(); + + const SwSpzFrmFmts& rFmts = *pDoc->GetSpzFrmFmts(); + + sal_uInt16 nNum, nTmp, nFlagSize = ( rFmts.Count() / 8 ) +2; + sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; + sal_uInt16 n; + + memset( pSetFlags, 0, nFlagSize ); + + for( n = 0; n < rFmts.Count(); ++n ) + { + const SwFrmFmt* pFlyFmt = rFmts[ n ]; + if( RES_FLYFRMFMT == pFlyFmt->Which() && + pFlyFmt->GetName().Match( aName ) == nNmLen ) + { + // Nummer bestimmen und das Flag setzen + nNum = static_cast< sal_uInt16 >( pFlyFmt->GetName().Copy( nNmLen ).ToInt32() ); + if( nNum-- && nNum < rFmts.Count() ) + pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); + } + } + + // alle Nummern entsprechend geflag, also bestimme die richtige Nummer + nNum = rFmts.Count(); + for( n = 0; n < nFlagSize; ++n ) + if( 0xff != ( nTmp = pSetFlags[ n ] )) + { + // also die Nummer bestimmen + nNum = n * 8; + while( nTmp & 1 ) + ++nNum, nTmp >>= 1; + break; + } + + delete [] pSetFlags; + return aName += String::CreateFromInt32( ++nNum ); +} + +String SwDoc::GetUniqueGrfName() const +{ + return lcl_GetUniqueFlyName( this, STR_GRAPHIC_DEFNAME ); +} + +String SwDoc::GetUniqueOLEName() const +{ + return lcl_GetUniqueFlyName( this, STR_OBJECT_DEFNAME ); +} + +String SwDoc::GetUniqueFrameName() const +{ + return lcl_GetUniqueFlyName( this, STR_FRAME_DEFNAME ); +} + +const SwFlyFrmFmt* SwDoc::FindFlyByName( const String& rName, sal_Int8 nNdTyp ) const +{ + const SwSpzFrmFmts& rFmts = *GetSpzFrmFmts(); + for( sal_uInt16 n = rFmts.Count(); n; ) + { + const SwFrmFmt* pFlyFmt = rFmts[ --n ]; + const SwNodeIndex* pIdx; + if( RES_FLYFRMFMT == pFlyFmt->Which() && pFlyFmt->GetName() == rName && + 0 != ( pIdx = pFlyFmt->GetCntnt().GetCntntIdx() ) && + pIdx->GetNode().GetNodes().IsDocNodes() ) + { + if( nNdTyp ) + { + // dann noch auf den richtigen Node-Typ abfragen + const SwNode* pNd = GetNodes()[ pIdx->GetIndex()+1 ]; + if( nNdTyp == ND_TEXTNODE + ? !pNd->IsNoTxtNode() + : nNdTyp == pNd->GetNodeType() ) + return (SwFlyFrmFmt*)pFlyFmt; + } + else + return (SwFlyFrmFmt*)pFlyFmt; + } + } + return 0; +} + +void SwDoc::SetFlyName( SwFlyFrmFmt& rFmt, const String& rName ) +{ + String sName( rName ); + if( !rName.Len() || FindFlyByName( rName ) ) + { + sal_uInt16 nTyp = STR_FRAME_DEFNAME; + const SwNodeIndex* pIdx = rFmt.GetCntnt().GetCntntIdx(); + if( pIdx && pIdx->GetNode().GetNodes().IsDocNodes() ) + switch( GetNodes()[ pIdx->GetIndex() + 1 ]->GetNodeType() ) + { + case ND_GRFNODE: nTyp = STR_GRAPHIC_DEFNAME; break; + case ND_OLENODE: nTyp = STR_OBJECT_DEFNAME; break; + } + sName = lcl_GetUniqueFlyName( this, nTyp ); + } + rFmt.SetName( sName, sal_True ); + SetModified(); +} + +void SwDoc::SetAllUniqueFlyNames() +{ + sal_uInt16 n, nFlyNum = 0, nGrfNum = 0, nOLENum = 0; + + ResId nFrmId( STR_FRAME_DEFNAME, *pSwResMgr ), + nGrfId( STR_GRAPHIC_DEFNAME, *pSwResMgr ), + nOLEId( STR_OBJECT_DEFNAME, *pSwResMgr ); + String sFlyNm( nFrmId ); + String sGrfNm( nGrfId ); + String sOLENm( nOLEId ); + + if( 255 < ( n = GetSpzFrmFmts()->Count() )) + n = 255; + SwSpzFrmFmts aArr( (sal_Int8)n, 10 ); + SwFrmFmtPtr pFlyFmt; + sal_Bool bLoadedFlag = sal_True; // noch etwas fuers Layout + + for( n = GetSpzFrmFmts()->Count(); n; ) + { + if( RES_FLYFRMFMT == (pFlyFmt = (*GetSpzFrmFmts())[ --n ])->Which() ) + { + sal_uInt16 *pNum = 0; + xub_StrLen nLen; + const String& rNm = pFlyFmt->GetName(); + if( rNm.Len() ) + { + if( rNm.Match( sGrfNm ) == ( nLen = sGrfNm.Len() )) + pNum = &nGrfNum; + else if( rNm.Match( sFlyNm ) == ( nLen = sFlyNm.Len() )) + pNum = &nFlyNum; + else if( rNm.Match( sOLENm ) == ( nLen = sOLENm.Len() )) + pNum = &nOLENum; + + if ( pNum && *pNum < ( nLen = static_cast< xub_StrLen >( rNm.Copy( nLen ).ToInt32() ) ) ) + *pNum = nLen; + } + else + // das wollen wir nachher setzen + aArr.Insert( pFlyFmt, aArr.Count() ); + + } + if( bLoadedFlag ) + { + const SwFmtAnchor& rAnchor = pFlyFmt->GetAnchor(); + if (((FLY_AT_PAGE == rAnchor.GetAnchorId()) && + rAnchor.GetCntntAnchor()) || + // oder werden DrawObjecte rel. zu irgendetwas ausgerichtet? + ( RES_DRAWFRMFMT == pFlyFmt->Which() && ( + SFX_ITEM_SET == pFlyFmt->GetItemState( + RES_VERT_ORIENT )|| + SFX_ITEM_SET == pFlyFmt->GetItemState( + RES_HORI_ORIENT ))) ) + { + bLoadedFlag = sal_False; + } + } + } + + const SwNodeIndex* pIdx; + + for( n = aArr.Count(); n; ) + if( 0 != ( pIdx = ( pFlyFmt = aArr[ --n ])->GetCntnt().GetCntntIdx() ) + && pIdx->GetNode().GetNodes().IsDocNodes() ) + { + sal_uInt16 nNum; + String sNm; + switch( GetNodes()[ pIdx->GetIndex() + 1 ]->GetNodeType() ) + { + case ND_GRFNODE: + sNm = sGrfNm; + nNum = ++nGrfNum; + break; + case ND_OLENODE: + sNm = sOLENm; + nNum = ++nOLENum; + break; + default: + sNm = sFlyNm; + nNum = ++nFlyNum; + break; + } + pFlyFmt->SetName( sNm += String::CreateFromInt32( nNum )); + } + aArr.Remove( 0, aArr.Count() ); + + if( GetFtnIdxs().Count() ) + { + SwTxtFtn::SetUniqueSeqRefNo( *this ); + // --> FME 2005-08-02 #i52775# Chapter footnotes did not + // get updated correctly. Calling UpdateAllFtn() instead of + // UpdateFtn() solves this problem, but I do not dare to + // call UpdateAllFtn() in all cases: Safety first. + if ( FTNNUM_CHAPTER == GetFtnInfo().eNum ) + { + GetFtnIdxs().UpdateAllFtn(); + } + // <-- + else + { + SwNodeIndex aTmp( GetNodes() ); + GetFtnIdxs().UpdateFtn( aTmp ); + } + } + + // neues Document und keine seitengebundenen Rahmen/DrawObjecte gefunden, + // die an einem Node verankert sind. + if( bLoadedFlag ) + SetLoaded( sal_True ); +} + +sal_Bool SwDoc::IsInHeaderFooter( const SwNodeIndex& rIdx ) const +{ + // gibt es ein Layout, dann ueber das laufen!! + // (Das kann dann auch Fly in Fly in Kopfzeile !) + // MIB 9.2.98: Wird auch vom sw3io benutzt, um festzustellen, ob sich + // ein Redline-Objekt in einer Kopf- oder Fusszeile befindet. Da + // Redlines auch an Start- und Endnodes haengen, muss der Index nicht + // unbedingt der eines Content-Nodes sein. + SwNode* pNd = &rIdx.GetNode(); + if( pNd->IsCntntNode() && pLayout ) + { + const SwFrm *pFrm = pNd->GetCntntNode()->GetFrm(); + if( pFrm ) + { + const SwFrm *pUp = pFrm->GetUpper(); + while ( pUp && !pUp->IsHeaderFrm() && !pUp->IsFooterFrm() ) + { + if ( pUp->IsFlyFrm() ) + pUp = ((SwFlyFrm*)pUp)->GetAnchorFrm(); + pUp = pUp->GetUpper(); + } + if ( pUp ) + return sal_True; + + return sal_False; + } + } + + + const SwNode* pFlyNd = pNd->FindFlyStartNode(); + while( pFlyNd ) + { + // dann ueber den Anker nach oben "hangeln" + sal_uInt16 n; + for( n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + const SwFrmFmt* pFmt = (*GetSpzFrmFmts())[ n ]; + const SwNodeIndex* pIdx = pFmt->GetCntnt().GetCntntIdx(); + if( pIdx && pFlyNd == &pIdx->GetNode() ) + { + const SwFmtAnchor& rAnchor = pFmt->GetAnchor(); + if ((FLY_AT_PAGE == rAnchor.GetAnchorId()) || + !rAnchor.GetCntntAnchor() ) + { + return sal_False; + } + + pNd = &rAnchor.GetCntntAnchor()->nNode.GetNode(); + pFlyNd = pNd->FindFlyStartNode(); + break; + } + } + if( n >= GetSpzFrmFmts()->Count() ) + { + ASSERT( mbInReading, "Fly-Section aber kein Format gefunden" ); + return sal_False; + } + } + + return 0 != pNd->FindHeaderStartNode() || + 0 != pNd->FindFooterStartNode(); +} + +short SwDoc::GetTextDirection( const SwPosition& rPos, + const Point* pPt ) const +{ + short nRet = -1; + + SwCntntNode *pNd = rPos.nNode.GetNode().GetCntntNode(); + + // --> OD 2005-02-21 #i42921# - use new method <SwCntntNode::GetTextDirection(..)> + if ( pNd ) + { + nRet = pNd->GetTextDirection( rPos, pPt ); + } + if ( nRet == -1 ) + // <-- + { + const SvxFrameDirectionItem* pItem = 0; + if( pNd ) + { + // in a flyframe? Then look at that for the correct attribute + const SwFrmFmt* pFlyFmt = pNd->GetFlyFmt(); + while( pFlyFmt ) + { + pItem = &pFlyFmt->GetFrmDir(); + if( FRMDIR_ENVIRONMENT == pItem->GetValue() ) + { + pItem = 0; + const SwFmtAnchor* pAnchor = &pFlyFmt->GetAnchor(); + if ((FLY_AT_PAGE != pAnchor->GetAnchorId()) && + pAnchor->GetCntntAnchor()) + { + pFlyFmt = pAnchor->GetCntntAnchor()->nNode. + GetNode().GetFlyFmt(); + } + else + pFlyFmt = 0; + } + else + pFlyFmt = 0; + } + + if( !pItem ) + { + const SwPageDesc* pPgDsc = pNd->FindPageDesc( sal_False ); + if( pPgDsc ) + pItem = &pPgDsc->GetMaster().GetFrmDir(); + } + } + if( !pItem ) + pItem = (SvxFrameDirectionItem*)&GetAttrPool().GetDefaultItem( + RES_FRAMEDIR ); + nRet = pItem->GetValue(); + } + return nRet; +} + +sal_Bool SwDoc::IsInVerticalText( const SwPosition& rPos, const Point* pPt ) const +{ + const short nDir = GetTextDirection( rPos, pPt ); + return FRMDIR_VERT_TOP_RIGHT == nDir || FRMDIR_VERT_TOP_LEFT == nDir; +} + +const SwRootFrm* SwDoc::GetRootFrm() const { return pLayout; } +SwRootFrm* SwDoc::GetRootFrm() { return pLayout; } +void SwDoc::SetRootFrm( SwRootFrm* pNew ) { pLayout = pNew; } +SwLayouter* SwDoc::GetLayouter() { return pLayouter; } +const SwLayouter* SwDoc::GetLayouter() const { return pLayouter; } +void SwDoc::SetLayouter( SwLayouter* pNew ) { pLayouter = pNew; } diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx new file mode 100644 index 000000000000..cdf031aeb923 --- /dev/null +++ b/sw/source/core/doc/docnew.cxx @@ -0,0 +1,1275 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#define ROLBCK_HISTORY_ONLY // Der Kampf gegen die CLOOK's +#include <doc.hxx> +#include <dcontact.hxx> +#include <com/sun/star/document/PrinterIndependentLayout.hpp> +#include <com/sun/star/document/UpdateDocMode.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/linguistic2/XProofreadingIterator.hpp> +#include <com/sun/star/text/XFlatParagraphIteratorProvider.hpp> + +#include <unotools/processfactory.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> +#include <rtl/logfile.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/viewfrm.hxx> + +#include <svl/macitem.hxx> +#include <svx/svxids.hrc> +#include <svx/svdogrp.hxx> +#include <sfx2/linkmgr.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <svl/zforlist.hxx> +#include <unotools/compatibility.hxx> +#include <unotools/lingucfg.hxx> +#include <svx/svdpage.hxx> +#include <paratr.hxx> +#include <fchrfmt.hxx> +#include <fmtcntnt.hxx> +#include <fmtanchr.hxx> +#include <fmtfsize.hxx> +#include <fmtfordr.hxx> +#include <fmtpdsc.hxx> +#include <pvprtdat.hxx> +#include <rootfrm.hxx> //Damit der RootDtor gerufen wird. +#include <layouter.hxx> +#include <pagedesc.hxx> //Damit die PageDescs zerstoert werden koennen. +#include <ndtxt.hxx> +#include <printdata.hxx> +#include <docfld.hxx> +#include <ftninfo.hxx> +#include <ftnidx.hxx> +#include <docstat.hxx> +#include <charfmt.hxx> +#include <frmfmt.hxx> +#include <rolbck.hxx> // Undo-Attr, SwHistory +#include <poolfmt.hxx> // fuer die Pool-Vorlage +#include <dbmgr.hxx> +#include <docsh.hxx> +#include <acorrect.hxx> // fuer die autom. Aufnahme von Ausnahmen +#include <visiturl.hxx> // fuer die URL-Change Benachrichtigung +#include <docary.hxx> +#include <lineinfo.hxx> +#include <drawdoc.hxx> +#include <linkenum.hxx> +#include <fldupde.hxx> +#include <extinput.hxx> +#include <viewsh.hxx> +#include <doctxm.hxx> +#include <shellres.hxx> +#include <breakit.hxx> +#include <laycache.hxx> +#include <mvsave.hxx> +#include <istyleaccess.hxx> +#include <swstylemanager.hxx> +#include <IGrammarContact.hxx> +#include <tblsel.hxx> +#include <MarkManager.hxx> +#include <UndoManager.hxx> +#include <unochart.hxx> + +#include <cmdid.h> // fuer den dflt - Printer in SetJob + + +// --> OD 2006-04-19 #b6375613# +#include <com/sun/star/document/XDocumentInfoSupplier.hpp> +#include <com/sun/star/beans/XPropertyContainer.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +// <-- + +// --> OD 2007-03-16 #i73788# +#include <pausethreadstarting.hxx> +// <-- +#include <numrule.hxx> +// --> OD 2008-03-13 #refactorlists# +#include <list.hxx> +#include <listfunc.hxx> +// <-- + +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +#include <sfx2/Metadatable.hxx> +#include <fmtmeta.hxx> // MetaFieldManager + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::document; + +const sal_Char __FAR_DATA sFrmFmtStr[] = "Frameformat"; +const sal_Char __FAR_DATA sEmptyPageStr[] = "Empty Page"; +const sal_Char __FAR_DATA sColumnCntStr[] = "Columncontainer"; +const sal_Char __FAR_DATA sCharFmtStr[] = "Zeichenformat"; +const sal_Char __FAR_DATA sTxtCollStr[] = "Textformatvorlage"; +const sal_Char __FAR_DATA sGrfCollStr[] = "Graphikformatvorlage"; + +SV_IMPL_PTRARR( SwNumRuleTbl, SwNumRulePtr) +SV_IMPL_PTRARR( SwTxtFmtColls, SwTxtFmtCollPtr) +SV_IMPL_PTRARR( SwGrfFmtColls, SwGrfFmtCollPtr) + +/* + * global functions... + */ + + uno::Reference< linguistic2::XProofreadingIterator > SwDoc::GetGCIterator() const +{ + if (!m_xGCIterator.is() && SvtLinguConfig().HasGrammarChecker()) + { + uno::Reference< lang::XMultiServiceFactory > xMgr( utl::getProcessServiceFactory() ); + if (xMgr.is()) + { + try + { + rtl::OUString aServiceName( rtl::OUString::createFromAscii("com.sun.star.linguistic2.ProofreadingIterator") ); + m_xGCIterator = uno::Reference< linguistic2::XProofreadingIterator > + ( xMgr->createInstance( aServiceName ), uno::UNO_QUERY_THROW ); + } + catch (uno::Exception &) + { + DBG_ERROR( "No GCIterator" ); + } + } + } + + return m_xGCIterator; +} + +void StartGrammarChecking( SwDoc &rDoc ) +{ + // check for a visible view + bool bVisible = false; + const SwDocShell *pDocShell = rDoc.GetDocShell(); + SfxViewFrame *pFrame = SfxViewFrame::GetFirst( pDocShell, sal_False ); + while (pFrame && !bVisible) + { + if (pFrame->IsVisible()) + bVisible = true; + pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell, sal_False ); + } + + //!! only documents with visible views need to be checked + //!! (E.g. don't check temporary documents created for printing, see printing of notes and selections. + //!! Those get created on the fly and get hard deleted a bit later as well, and no one should have + //!! a uno reference to them) + if (bVisible) + { + uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( rDoc.GetGCIterator() ); + if ( xGCIterator.is() ) + { + uno::Reference< lang::XComponent > xDoc( rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY ); + uno::Reference< text::XFlatParagraphIteratorProvider > xFPIP( xDoc, uno::UNO_QUERY ); + + // start automatic background checking if not active already + if ( xFPIP.is() && !xGCIterator->isProofreading( xDoc ) ) + xGCIterator->startProofreading( xDoc, xFPIP ); + } + } +} + +/* + * interne Funktionen + */ + + + +sal_Bool lcl_DelFmtIndizes( const SwFrmFmtPtr& rpFmt, void* ) +{ + SwFmtCntnt &rFmtCntnt = (SwFmtCntnt&)rpFmt->GetCntnt(); + if ( rFmtCntnt.GetCntntIdx() ) + rFmtCntnt.SetNewCntntIdx( 0 ); + SwFmtAnchor &rFmtAnchor = (SwFmtAnchor&)rpFmt->GetAnchor(); + if ( rFmtAnchor.GetCntntAnchor() ) + rFmtAnchor.SetAnchor( 0 ); + return sal_True; +} + +/* + * exportierte Methoden + */ + +SwDoc::SwDoc() + : m_pNodes( new SwNodes(this) ) + , + mpAttrPool(new SwAttrPool(this)), + pMarkManager(new ::sw::mark::MarkManager(*this)), + m_pMetaFieldManager(new ::sw::MetaFieldManager()), + m_pUndoManager(new ::sw::UndoManager( + ::std::auto_ptr<SwNodes>(new SwNodes(this)), *this, *this, *this)), + pDfltFrmFmt( new SwFrmFmt( GetAttrPool(), sFrmFmtStr, 0 ) ), + pEmptyPageFmt( new SwFrmFmt( GetAttrPool(), sEmptyPageStr, pDfltFrmFmt ) ), + pColumnContFmt( new SwFrmFmt( GetAttrPool(), sColumnCntStr, pDfltFrmFmt ) ), + pDfltCharFmt( new SwCharFmt( GetAttrPool(), sCharFmtStr, 0 ) ), + pDfltTxtFmtColl( new SwTxtFmtColl( GetAttrPool(), sTxtCollStr ) ), + pDfltGrfFmtColl( new SwGrfFmtColl( GetAttrPool(), sGrfCollStr ) ), + pFrmFmtTbl( new SwFrmFmts() ), + pCharFmtTbl( new SwCharFmts() ), + pSpzFrmFmtTbl( new SwSpzFrmFmts() ), + pSectionFmtTbl( new SwSectionFmts() ), + pTblFrmFmtTbl( new SwFrmFmts() ), + pTxtFmtCollTbl( new SwTxtFmtColls() ), + pGrfFmtCollTbl( new SwGrfFmtColls() ), + pTOXTypes( new SwTOXTypes() ), + pDefTOXBases( new SwDefTOXBase_Impl() ), + pLayout( 0 ), // Rootframe des spezifischen Layouts. + pDrawModel( 0 ), + pUpdtFlds( new SwDocUpdtFld() ), + pFldTypes( new SwFldTypes() ), + pVirDev( 0 ), + pPrt( 0 ), + pPrtData( 0 ), + pGlossaryDoc( 0 ), + pOutlineRule( 0 ), + pFtnInfo( new SwFtnInfo ), + pEndNoteInfo( new SwEndNoteInfo ), + pLineNumberInfo( new SwLineNumberInfo ), + pFtnIdxs( new SwFtnIdxs ), + pDocStat( new SwDocStat ), + pDocShell( 0 ), + pLinkMgr( new sfx2::LinkManager( 0 ) ), + pACEWord( 0 ), + pURLStateChgd( 0 ), + pNumberFormatter( 0 ), + pNumRuleTbl( new SwNumRuleTbl ), + // --> OD 2008-03-26 #refactorlists# + maLists(), + maListStyleLists(), + // <-- + pRedlineTbl( new SwRedlineTbl ), + pAutoFmtRedlnComment( 0 ), + pUnoCrsrTbl( new SwUnoCrsrTbl( 0, 16 ) ), + pPgPViewPrtData( 0 ), + pExtInputRing( 0 ), + pLayouter( 0 ), + // --> OD 2008-03-07 #refactorlists# + pStyleAccess( 0 ), + // <-- + pLayoutCache( 0 ), + pUnoCallBack(new SwModify(0)), + mpGrammarContact( 0 ), + aChartDataProviderImplRef(), + pChartControllerHelper( 0 ), + // --> OD 2007-10-31 #i83479# + mpListItemsList( new tImplSortedNodeNumList() ), + // <-- + m_pXmlIdRegistry(), + nAutoFmtRedlnCommentNo( 0 ), + nLinkUpdMode( GLOBALSETTING ), + eFldUpdMode( AUTOUPD_GLOBALSETTING ), + eRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE)), + eChrCmprType( CHARCOMPRESS_NONE ), + mReferenceCount(0), + mIdleBlockCount(0), + nLockExpFld( 0 ), + mbReadlineChecked(false), + // --> OD 2005-02-11 #i38810# + mbLinksUpdated( sal_False ), + mbClipBoard( false ), + mbColumnSelection( false ), + // i#78591# + mbProtectForm(false), + n32DummyCompatabilityOptions1(0), + n32DummyCompatabilityOptions2(0), + mbStartIdleTimer(sal_False) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLog, "SW", "JP93722", "SwDoc::SwDoc" ); + + mbGlossDoc = + mbModified = + mbDtor = + mbPageNums = + mbLoaded = + mbUpdateExpFld = + mbNewDoc = + mbCopyIsMove = + mbBrowseMode = + mbInReading = + mbInXMLImport = + mbUpdateTOX = + mbInLoadAsynchron = + mbHTMLMode = + mbInCallModified = + mbIsGlobalDoc = + mbGlblDocSaveLinks = + mbIsLabelDoc = + mbIsAutoFmtRedline = + mbOLEPrtNotifyPending = + mbAllOLENotify = + mbIsRedlineMove = + mbInsOnlyTxtGlssry = + mbContains_MSVBasic = + mbKernAsianPunctuation = +#ifdef DBG_UTIL + mbXMLExport = +#endif + // --> OD 2006-03-21 #b6375613# + mbApplyWorkaroundForB6375613 = + // <-- + false; + + mbNewFldLst = + mbVisibleLinks = + mbPurgeOLE = + true; + + // + // COMPATIBILITY FLAGS START + // + + // Note: Any non-hidden compatibility flag should obtain its default + // by asking SvtCompatibilityOptions, see below. + // + const SvtCompatibilityOptions aOptions; + mbParaSpaceMax = aOptions.IsAddSpacing(); + mbParaSpaceMaxAtPages = aOptions.IsAddSpacingAtPages(); + mbTabCompat = !aOptions.IsUseOurTabStops(); + mbUseVirtualDevice = !aOptions.IsUsePrtDevice(); + mbAddExternalLeading = !aOptions.IsNoExtLeading(); + mbOldLineSpacing = aOptions.IsUseLineSpacing(); + mbAddParaSpacingToTableCells = aOptions.IsAddTableSpacing(); + mbUseFormerObjectPos = aOptions.IsUseObjectPositioning(); + mbUseFormerTextWrapping = aOptions.IsUseOurTextWrapping(); + mbConsiderWrapOnObjPos = aOptions.IsConsiderWrappingStyle(); + mbMathBaselineAlignment = false; // default for *old* documents is 'off' + mbAddFlyOffsets = false; // hidden + mbOldNumbering = false; // hidden + mbUseHiResolutionVirtualDevice = true; // hidden + mbIgnoreFirstLineIndentInNumbering = false; // hidden + mbDoNotJustifyLinesWithManualBreak = !aOptions.IsExpandWordSpace(); + mbDoNotResetParaAttrsForNumFont = false; // hidden + mbOutlineLevelYieldsOutlineRule = false; // hidden + mbTableRowKeep = false; // hidden + mbIgnoreTabsAndBlanksForLineCalculation = false; // hidden + mbDoNotCaptureDrawObjsOnPage = false; // hidden + mbClipAsCharacterAnchoredWriterFlyFrames= false; // hidden + mbUnixForceZeroExtLeading = false; // hidden + mbOldPrinterMetrics = false; // hidden + mbTabRelativeToIndent = true; // hidden + // --> OD 2008-06-05 #i89181# + mbTabAtLeftIndentForParagraphsInList = false; // hidden + // <-- + + // + // COMPATIBILITY FLAGS END + // + + pMacroTable = new SvxMacroTableDtor; + + mpGrammarContact = ::createGrammarContact(); + + /* + * Defaultformate und DefaultFormatsammlungen (FmtColl) + * werden an der Position 0 in das jeweilige Array eingetragen. + * Die Formate der FmtColls sind von den Defaultformaten + * abgeleitet und stehen auch in der Liste. + */ + /* Formate */ + pFrmFmtTbl->Insert(pDfltFrmFmt, 0 ); + pCharFmtTbl->Insert(pDfltCharFmt, 0 ); + + /* FmtColls */ + // TXT + pTxtFmtCollTbl->Insert(pDfltTxtFmtColl, 0 ); + // GRF + pGrfFmtCollTbl->Insert(pDfltGrfFmtColl, 0 ); + + // PageDesc, EmptyPageFmt und ColumnFmt anlegen + if ( !aPageDescs.Count() ) + GetPageDescFromPool( RES_POOLPAGE_STANDARD ); + + //Leere Seite Einstellen. + pEmptyPageFmt->SetFmtAttr( SwFmtFrmSize( ATT_FIX_SIZE ) ); + //BodyFmt fuer Spalten Einstellen. + pColumnContFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) ); + + _InitFieldTypes(); + + // lege (fuer die Filter) eine Default-OutlineNumRule an + // --> OD 2008-02-11 #newlistlevelattrs# + pOutlineRule = new SwNumRule( String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ), + // --> OD 2008-06-06 #i89178# + numfunc::GetDefaultPositionAndSpaceMode(), + // <-- + OUTLINE_RULE ); + // <-- + // #115901# + AddNumRule(pOutlineRule); + // --> OD 2005-10-21 - counting of phantoms depends on <IsOldNumbering()> + pOutlineRule->SetCountPhantoms( !get(IDocumentSettingAccess::OLD_NUMBERING) ); + // <-- + + new SwTxtNode( + SwNodeIndex(GetUndoManager().GetUndoNodes().GetEndOfContent()), + pDfltTxtFmtColl ); + new SwTxtNode( SwNodeIndex( GetNodes().GetEndOfContent() ), + GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); + + // den eigenen IdleTimer setzen + aIdleTimer.SetTimeout( 600 ); + aIdleTimer.SetTimeoutHdl( LINK(this, SwDoc, DoIdleJobs) ); + + aOLEModifiedTimer.SetTimeout( 1000 ); + aOLEModifiedTimer.SetTimeoutHdl( LINK( this, SwDoc, DoUpdateModifiedOLE )); + + // DBMgr anlegen + pNewDBMgr = new SwNewDBMgr; + + // create TOXTypes + InitTOXTypes(); + + // --> OD 2008-03-07 #refactorlists# + // pass empty item set containing the paragraph's list attributes + // as ignorable items to the stype manager. + { + SfxItemSet aIgnorableParagraphItems( GetAttrPool(), + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + 0 ); + pStyleAccess = createStyleManager( &aIgnorableParagraphItems ); + } + // <-- + + ResetModified(); +} + +/* + * Besonderheiten: an der Position 0 des Arrays der Formate und + * der GDI-Objekte befindet sich ein Member der Klasse SwDoc. + * Dieser darf also keinesfalls durch delete geloescht + * werden!!!!!!!!!! + */ + + +SwDoc::~SwDoc() +{ + // nothing here should create Undo actions! + GetIDocumentUndoRedo().DoUndo(false); + + if (pDocShell) + { + pDocShell->SetUndoManager(0); + } + + // --> OD 2007-03-16 #i73788# + SwPauseThreadStarting aPauseThreadStarting; + // <-- + + // --> OD 2007-11-01 #i83479# + delete mpListItemsList; + mpListItemsList = 0; + // <-- + + // clean up chart related structures... + // Note: the chart data provider gets already diposed in ~SwDocShell + // since all UNO API related functionality requires an existing SwDocShell + // this assures that dipose gets called if there is need for it. + aChartDataProviderImplRef.reset(); + delete pChartControllerHelper; + + delete mpGrammarContact; + mpGrammarContact = 0; + + //!! needs to be done to destroy a possible SwFmtDrop format that may + //!! be connected to a char format which may not otherwise be removed + //!! and thus would leave a unremoved SwFmt object. (TL) + //!! (this is case is not possible via UI but via API...) + SwFmtDrop aDrop; + SetDefault(aDrop); + //!! same for SwFmtCharFmt + SwFmtCharFmt aCharFmt(NULL); + SetDefault(aCharFmt); + + StopIdling(); // stop idle timer + + delete pUnoCallBack, pUnoCallBack = 0; + delete pURLStateChgd; + + delete pLayouter; + // --> OD 2005-09-05 #125370# + pLayouter = 0L; + // <-- + + // Undo-Benachrichtigung vom Draw abschalten + if( pDrawModel ) + { + DrawNotifyUndoHdl(); + ClrContourCache(); + } + + delete pPgPViewPrtData; + + mbDtor = sal_True; + + DELETEZ( pLayout ); + + delete pRedlineTbl; + delete pUnoCrsrTbl; + delete pAutoFmtRedlnComment; + + if( pUpdtFlds ) + delete pUpdtFlds; + + if( pACEWord ) + delete pACEWord; + + // die BaseLinks freigeben. + { + for( sal_uInt16 n = pLinkMgr->GetServers().Count(); n; ) + pLinkMgr->GetServers()[ --n ]->Closed(); + + if( pLinkMgr->GetLinks().Count() ) + pLinkMgr->Remove( 0, pLinkMgr->GetLinks().Count() ); + } + + // die KapitelNummern / Nummern muessen vor den Vorlage geloescht werden + // ansonsten wird noch staendig geupdatet !!! + m_pNodes->pOutlineNds->Remove(sal_uInt16(0), m_pNodes->pOutlineNds->Count()); + SwNodes & rUndoNodes( GetUndoManager().GetUndoNodes() ); + rUndoNodes.pOutlineNds->Remove(sal_uInt16(0), rUndoNodes.pOutlineNds->Count()); + + pFtnIdxs->Remove( sal_uInt16(0), pFtnIdxs->Count() ); + + // indices could be registered in attributes + m_pUndoManager->DelAllUndoObj(); + + // in den BookMarks sind Indizies auf den Content. Diese muessen vorm + // loesche der Nodes geloescht werden. + pMarkManager->clearAllMarks(); + DELETEZ( pMacroTable ); + + if( pExtInputRing ) + { + Ring* pTmp = pExtInputRing; + pExtInputRing = 0; + while( pTmp->GetNext() != pTmp ) + delete pTmp->GetNext(); + delete pTmp; + } + +//JP: alt - loeschen ohne Flag ist teuer; Modify wird verschickt! +// aTOXTypes.DeleteAndDestroy( 0, aTOXTypes.Count() ); + { + for( sal_uInt16 n = pTOXTypes->Count(); n; ) + { + (*pTOXTypes)[ --n ]->SetInDocDTOR(); + delete (*pTOXTypes)[ n ]; + } + pTOXTypes->Remove( 0, pTOXTypes->Count() ); + } + delete pDefTOXBases; + + //Im einen oder anderen FrmFormat koennen noch Indizes angemeldet sein, + //Diese muessen spaetestens jetzt zerstoert werden. + pFrmFmtTbl->ForEach( &lcl_DelFmtIndizes, this ); + pSpzFrmFmtTbl->ForEach( &lcl_DelFmtIndizes, this ); + ((SwFrmFmts&)*pSectionFmtTbl).ForEach( &lcl_DelFmtIndizes, this ); + + //Die Formate, die hier hinter stehen sind von den DefaultFormaten + //abhaengig. Erst nach dem Loeschen der FmtIndizes weil der Inhalt von + //Kopf-/Fussbereichen geloescht wird. Wenn dort noch Indizes von Flys + //angemeldet sind gibts was an die Ohren. + aPageDescs.DeleteAndDestroy( 0, aPageDescs.Count() ); + + // Inhaltssections loeschen + // nicht erst durch den SwNodes-DTOR, damit Formate + // keine Abhaengigen mehr haben. + m_pNodes->DelNodes( SwNodeIndex(*m_pNodes), m_pNodes->Count() ); + rUndoNodes.DelNodes( SwNodeIndex( rUndoNodes ), rUndoNodes.Count() ); + + // Formate loeschen, spaeter mal permanent machen. + + // Delete fuer Collections + // damit die Abhaengigen wech sind + SwTxtFmtColl *pFtnColl = pFtnInfo->GetFtnTxtColl(); + if ( pFtnColl ) pFtnColl->Remove(pFtnInfo); + pFtnColl = pEndNoteInfo->GetFtnTxtColl(); + if ( pFtnColl ) pFtnColl->Remove(pEndNoteInfo); + + ASSERT( pDfltTxtFmtColl == (*pTxtFmtCollTbl)[0], + "Default-Text-Collection muss immer am Anfang stehen" ); + + // JP 27.01.98: opt.: ausgehend davon, das Standard als 2. im Array + // steht, sollte das als letztes geloescht werden, damit + // die ganze Umhaengerei der Formate vermieden wird! + if( 2 < pTxtFmtCollTbl->Count() ) + pTxtFmtCollTbl->DeleteAndDestroy( 2, pTxtFmtCollTbl->Count()-2 ); + pTxtFmtCollTbl->DeleteAndDestroy( 1, pTxtFmtCollTbl->Count()-1 ); + delete pTxtFmtCollTbl; + + ASSERT( pDfltGrfFmtColl == (*pGrfFmtCollTbl)[0], + "Default-Grf-Collection muss immer am Anfang stehen" ); + + pGrfFmtCollTbl->DeleteAndDestroy( 1, pGrfFmtCollTbl->Count()-1 ); +// ergibt sich automatisch - kein _DEL Array! +// pGrfFmtCollTbl->Remove( 0, n ); + delete pGrfFmtCollTbl; + + /* + * Defaultformate und DefaultFormatsammlungen (FmtColl) + * sind an der Position 0 der jeweiligen Arrays eingetragen. + * Damit sie nicht vom DTOR der Array's zum 2.mal geloescht werden, + * nehme sie aus dem Array. + */ + pFrmFmtTbl->Remove( 0 ); + pCharFmtTbl->Remove( 0 ); + + // Delete fuer pPrt + DELETEZ( pPrt ); + DELETEZ( pNewDBMgr ); + + // Alle Flys muessen vor dem Drawing Model zerstoert werden, + // da Flys noch DrawContacts enthalten koennen, wenn wegen + // eines Lesefehlers kein Layout aufgebaut wurde. + pSpzFrmFmtTbl->DeleteAndDestroy( 0, pSpzFrmFmtTbl->Count() ); + + //Erst jetzt das Model zerstoeren, die Zeichenobjekte - die ja auch + //im Undo herumlungern - wollen noch ihre Attribute beim Model entfernen. + //Ausserdem koennen vorher noch DrawContacts existieren. + ReleaseDrawModel(); + //JP 28.01.99: DrawModel vorm LinkManager zerstoeren, da am DrawModel + // dieser immer gesetzt ist. + DELETEZ( pLinkMgr ); + + //Tables vor dem loeschen der Defaults leeren, sonst GPF wegen Def-Abhaengigen. + //Die Arrays sollten (wegen includes) bei Gelegenheit auch zu Pointern werden. + delete pFrmFmtTbl; + delete pSpzFrmFmtTbl; + + delete pStyleAccess; + + delete pCharFmtTbl; + delete pSectionFmtTbl; + delete pTblFrmFmtTbl; + delete pDfltTxtFmtColl; + delete pDfltGrfFmtColl; + delete pNumRuleTbl; + + // --> OD 2008-03-26 #refactorlists# + { + for ( std::hash_map< String, SwList*, StringHash >::iterator + aListIter = maLists.begin(); + aListIter != maLists.end(); + ++aListIter ) + { + delete (*aListIter).second; + } + maLists.clear(); + } + maListStyleLists.clear(); + // <-- + + delete pPrtData; + delete pNumberFormatter; + delete pFtnInfo; + delete pEndNoteInfo; + delete pLineNumberInfo; + delete pFtnIdxs; + delete pFldTypes; + delete pTOXTypes; + delete pDocStat; + delete pEmptyPageFmt; + delete pColumnContFmt; + delete pDfltCharFmt; + delete pDfltFrmFmt; + delete pLayoutCache; + delete pVirDev; + + SfxItemPool::Free(mpAttrPool); +} + +//--------------------------------------------------- + +VirtualDevice& SwDoc::CreateVirtualDevice_() const +{ + VirtualDevice* pNewVir = new VirtualDevice( 1 ); + + // <-- + pNewVir->SetReferenceDevice( VirtualDevice::REFDEV_MODE_MSO1 ); + + // --> FME 2006-10-09 #i60945# External leading compatibility for unix systems. + if ( get(IDocumentSettingAccess::UNIX_FORCE_ZERO_EXT_LEADING ) ) + pNewVir->Compat_ZeroExtleadBug(); + // <-- + + MapMode aMapMode( pNewVir->GetMapMode() ); + aMapMode.SetMapUnit( MAP_TWIP ); + pNewVir->SetMapMode( aMapMode ); + + const_cast<SwDoc*>(this)->setVirtualDevice( pNewVir, true, true ); + return *pVirDev; +} + +//--------------------------------------------------- + +SfxPrinter& SwDoc::CreatePrinter_() const +{ + ASSERT( ! pPrt, "Do not call CreatePrinter_(), call getPrinter() instead" ) + +#if OSL_DEBUG_LEVEL > 1 + ASSERT( false, "Printer will be created!" ) +#endif + + // wir erzeugen einen default SfxPrinter. + // Das ItemSet wird vom Sfx geloescht! + SfxItemSet *pSet = new SfxItemSet( ((SwDoc*)this)->GetAttrPool(), + FN_PARAM_ADDPRINTER, FN_PARAM_ADDPRINTER, + SID_HTML_MODE, SID_HTML_MODE, + SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN, + SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC, + 0 ); + + SfxPrinter* pNewPrt = new SfxPrinter( pSet ); + const_cast<SwDoc*>(this)->setPrinter( pNewPrt, true, true ); + return *pPrt; +} +//--------------------------------------------------- + +void SwDoc::SetDocShell( SwDocShell* pDSh ) +{ + if( pDocShell != pDSh ) + { + if (pDocShell) + { + pDocShell->SetUndoManager(0); + } + pDocShell = pDSh; + if (pDocShell) + { + pDocShell->SetUndoManager(& GetUndoManager()); + } + + pLinkMgr->SetPersist( pDocShell ); + //JP 27.08.98: Bug 55570 - DocShell Pointer auch am DrawModel setzen + if( pDrawModel ) + { + ((SwDrawDocument*)pDrawModel)->SetObjectShell( pDocShell ); + pDrawModel->SetPersist( pDocShell ); + ASSERT( pDrawModel->GetPersist() == GetPersist(), + "draw model's persist is out of sync" ); + } + } +} + + +// Convenience-Methode, um uebermaessige Includes von docsh.hxx +// zu vermeiden + + + +uno::Reference < embed::XStorage > SwDoc::GetDocStorage() +{ + if( pDocShell ) + return pDocShell->GetStorage(); + if( pLinkMgr->GetPersist() ) + return pLinkMgr->GetPersist()->GetStorage(); + return NULL; +} + + + +SfxObjectShell* SwDoc::GetPersist() const +{ + return pDocShell ? pDocShell : pLinkMgr->GetPersist(); +} + + +void SwDoc::ClearDoc() +{ + GetIDocumentUndoRedo().DelAllUndoObj(); + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + // Undo-Benachrichtigung vom Draw abschalten + if( pDrawModel ) + { + DrawNotifyUndoHdl(); + ClrContourCache(); + } + + // stehen noch FlyFrames rum, loesche auch diese + sal_uInt16 n; + while ( 0 != (n = GetSpzFrmFmts()->Count()) ) + DelLayoutFmt((*pSpzFrmFmtTbl)[n-1]); + ASSERT( !pDrawModel || !pDrawModel->GetPage(0)->GetObjCount(), + "not all DrawObjects removed from the page" ); + + pRedlineTbl->DeleteAndDestroy( 0, pRedlineTbl->Count() ); + + if( pACEWord ) + delete pACEWord; + + // in den BookMarks sind Indizies auf den Content. Diese muessen vorm + // loesche der Nodes geloescht werden. + pMarkManager->clearAllMarks(); + InitTOXTypes(); + + // create a dummy pagedesc for the layout + sal_uInt16 nDummyPgDsc = MakePageDesc( String::CreateFromAscii( "?DUMMY?" )); + SwPageDesc* pDummyPgDsc = aPageDescs[ nDummyPgDsc ]; + + SwNodeIndex aSttIdx( *GetNodes().GetEndOfContent().StartOfSectionNode(), 1 ); + // den ersten immer wieder neu anlegen (ohne Attribute/Vorlagen/...) + SwTxtNode* pFirstNd = GetNodes().MakeTxtNode( aSttIdx, pDfltTxtFmtColl ); + + if( pLayout ) + { + // set the layout to the dummy pagedesc + pFirstNd->SetAttr( SwFmtPageDesc( pDummyPgDsc )); + + SwPosition aPos( *pFirstNd, SwIndex( pFirstNd )); + SwPaM const tmpPaM(aSttIdx, SwNodeIndex(GetNodes().GetEndOfContent())); + ::PaMCorrAbs(tmpPaM, aPos); + } + + GetNodes().Delete( aSttIdx, + GetNodes().GetEndOfContent().GetIndex() - aSttIdx.GetIndex() ); + + // --> OD 2006-02-28 #i62440# + // destruction of numbering rules and creation of new outline rule + // *after* the document nodes are deleted. + pOutlineRule = NULL; + pNumRuleTbl->DeleteAndDestroy( 0, pNumRuleTbl->Count() ); + // creation of new outline numbering rule + // --> OD 2008-02-11 #newlistlevelattrs# + pOutlineRule = new SwNumRule( String::CreateFromAscii( SwNumRule::GetOutlineRuleName() ), + // --> OD 2008-06-06 #i89178# + numfunc::GetDefaultPositionAndSpaceMode(), + // <-- + OUTLINE_RULE ); + // <-- + AddNumRule(pOutlineRule); + // --> OD 2005-10-21 - counting of phantoms depends on <IsOldNumbering()> + pOutlineRule->SetCountPhantoms( !get(IDocumentSettingAccess::OLD_NUMBERING) ); + // <-- + // <-- + + //remove the dummy pagedec from the array and delete all the old ones + aPageDescs.Remove( nDummyPgDsc ); + aPageDescs.DeleteAndDestroy( 0, aPageDescs.Count() ); + + // Delete fuer Collections + // damit die Abhaengigen wech sind + SwTxtFmtColl* pFtnColl = pFtnInfo->GetFtnTxtColl(); + if( pFtnColl ) pFtnColl->Remove( pFtnInfo ); + pFtnColl = pEndNoteInfo->GetFtnTxtColl(); + if( pFtnColl ) pFtnColl->Remove( pEndNoteInfo ); + + // JP 27.01.98: opt.: ausgehend davon, das Standard als 2. im Array + // steht, sollte das als letztes geloescht werden, damit + // die ganze Umhaengerei der Formate vermieden wird! + if( 2 < pTxtFmtCollTbl->Count() ) + pTxtFmtCollTbl->DeleteAndDestroy( 2, pTxtFmtCollTbl->Count()-2 ); + pTxtFmtCollTbl->DeleteAndDestroy( 1, pTxtFmtCollTbl->Count()-1 ); + pGrfFmtCollTbl->DeleteAndDestroy( 1, pGrfFmtCollTbl->Count()-1 ); + pCharFmtTbl->DeleteAndDestroy( 1, pCharFmtTbl->Count()-1 ); + + if( pLayout ) + { + // search the FrameFormat of the root frm. This is not allowed to delete + pFrmFmtTbl->Remove( pFrmFmtTbl->GetPos( pLayout->GetFmt() ) ); + pFrmFmtTbl->DeleteAndDestroy( 1, pFrmFmtTbl->Count()-1 ); + pFrmFmtTbl->Insert( pLayout->GetFmt(), pFrmFmtTbl->Count() ); + } + else + pFrmFmtTbl->DeleteAndDestroy( 1, pFrmFmtTbl->Count()-1 ); + + xForbiddenCharsTable.unbind(); + + pFldTypes->DeleteAndDestroy( INIT_FLDTYPES, + pFldTypes->Count() - INIT_FLDTYPES ); + + delete pNumberFormatter, pNumberFormatter = 0; + + GetPageDescFromPool( RES_POOLPAGE_STANDARD ); + pFirstNd->ChgFmtColl( GetTxtCollFromPool( RES_POOLCOLL_STANDARD )); + nDummyPgDsc = aPageDescs.Count(); + aPageDescs.Insert( pDummyPgDsc, nDummyPgDsc ); + // set the layout back to the new standard pagedesc + pFirstNd->ResetAllAttr(); + // delete now the dummy pagedesc + DelPageDesc( nDummyPgDsc ); +} + +void SwDoc::SetPreViewPrtData( const SwPagePreViewPrtData* pNew ) +{ + if( pNew ) + { + if( pPgPViewPrtData ) + *pPgPViewPrtData = *pNew; + else + pPgPViewPrtData = new SwPagePreViewPrtData( *pNew ); + } + else if( pPgPViewPrtData ) + DELETEZ( pPgPViewPrtData ); + SetModified(); +} +/* -----------------------------06.01.00 14:03-------------------------------- + + ---------------------------------------------------------------------------*/ +SwModify* SwDoc::GetUnoCallBack() const +{ + return pUnoCallBack; +} + +/*-----------------28.5.2001 10:06------------------ + * SwDoc: + * Reading and writing of the layout cache. + *--------------------------------------------------*/ + +void SwDoc::ReadLayoutCache( SvStream& rStream ) +{ + if( !pLayoutCache ) + pLayoutCache = new SwLayoutCache(); + if( !pLayoutCache->IsLocked() ) + { + pLayoutCache->GetLockCount() |= 0x8000; + pLayoutCache->Read( rStream ); + pLayoutCache->GetLockCount() &= 0x7fff; + } +} + +void SwDoc::WriteLayoutCache( SvStream& rStream ) +{ + pLayoutCache->Write( rStream, *this ); +} + +IGrammarContact* getGrammarContact( const SwTxtNode& rTxtNode ) +{ + const SwDoc* pDoc = rTxtNode.GetDoc(); + if( !pDoc || pDoc->IsInDtor() ) + return 0; + return pDoc->getGrammarContact(); +} + +// --> FME 2005-02-25 #i42634# Moved common code of SwReader::Read() and +// SwDocShell::UpdateLinks() to new SwDoc::UpdateLinks(): +void SwDoc::UpdateLinks( sal_Bool bUI ) +{ + SfxObjectCreateMode eMode; + sal_uInt16 nLinkMode = getLinkUpdateMode( true ); + sal_uInt16 nUpdateDocMode = GetDocShell()->GetUpdateDocMode(); + if( GetDocShell() && + (nLinkMode != NEVER || document::UpdateDocMode::FULL_UPDATE == nUpdateDocMode) && + GetLinkManager().GetLinks().Count() && + SFX_CREATE_MODE_INTERNAL != + ( eMode = GetDocShell()->GetCreateMode()) && + SFX_CREATE_MODE_ORGANIZER != eMode && + SFX_CREATE_MODE_PREVIEW != eMode && + !GetDocShell()->IsPreview() ) + { + ViewShell* pVSh = 0; + sal_Bool bAskUpdate = nLinkMode == MANUAL; + sal_Bool bUpdate = sal_True; + switch(nUpdateDocMode) + { + case document::UpdateDocMode::NO_UPDATE: bUpdate = sal_False;break; + case document::UpdateDocMode::QUIET_UPDATE:bAskUpdate = sal_False; break; + case document::UpdateDocMode::FULL_UPDATE: bAskUpdate = sal_True; break; + } + if( bUpdate && (bUI || !bAskUpdate) ) + { + SfxMedium* pMedium = GetDocShell()->GetMedium(); + SfxFrame* pFrm = pMedium ? pMedium->GetLoadTargetFrame() : 0; + Window* pDlgParent = pFrm ? &pFrm->GetWindow() : 0; + if( GetRootFrm() && !GetEditShell( &pVSh ) && !pVSh ) + { + ViewShell aVSh( *this, 0, 0 ); + + SET_CURR_SHELL( &aVSh ); + GetLinkManager().UpdateAllLinks( bAskUpdate , sal_True, sal_False, pDlgParent ); + } + else + GetLinkManager().UpdateAllLinks( bAskUpdate, sal_True, sal_False, pDlgParent ); + } + } + +} +// <-- +// --> OD 2006-04-19 #b6375613# +void SwDoc::SetApplyWorkaroundForB6375613( bool p_bApplyWorkaroundForB6375613 ) +{ + if ( mbApplyWorkaroundForB6375613 != p_bApplyWorkaroundForB6375613 ) + { + mbApplyWorkaroundForB6375613 = p_bApplyWorkaroundForB6375613; + + uno::Reference< document::XDocumentInfoSupplier > xDoc( + GetDocShell()->GetBaseModel(), + uno::UNO_QUERY); + if ( xDoc.is() ) + { + uno::Reference< beans::XPropertyContainer > xDocInfo( + xDoc->getDocumentInfo(), + uno::UNO_QUERY ); + if ( xDocInfo.is() ) + { + try + { + if ( mbApplyWorkaroundForB6375613 ) + { + xDocInfo->addProperty( + rtl::OUString::createFromAscii("WorkaroundForB6375613Applied"), + beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::REMOVABLE, + uno::makeAny( false ) ); + } + else + { + xDocInfo->removeProperty( rtl::OUString::createFromAscii("WorkaroundForB6375613Applied") ); + } + } + catch( uno::Exception& ) + { + } + } + } + } +} +// <-- + +::sfx2::IXmlIdRegistry& +SwDoc::GetXmlIdRegistry() +{ + // UGLY: this relies on SetClipBoard being called before GetXmlIdRegistry! + if (!m_pXmlIdRegistry.get()) + { + m_pXmlIdRegistry.reset( ::sfx2::createXmlIdRegistry( IsClipBoard() ) ); + } + return *m_pXmlIdRegistry; +} + +::sw::MetaFieldManager & +SwDoc::GetMetaFieldManager() +{ + return *m_pMetaFieldManager; +} + +::sw::UndoManager & +SwDoc::GetUndoManager() +{ + return *m_pUndoManager; +} + +::sw::UndoManager const& +SwDoc::GetUndoManager() const +{ + return *m_pUndoManager; +} + +IDocumentUndoRedo & +SwDoc::GetIDocumentUndoRedo() +{ + return *m_pUndoManager; +} + +IDocumentUndoRedo const& +SwDoc::GetIDocumentUndoRedo() const +{ + return *m_pUndoManager; +} + +void SwDoc::InitTOXTypes() +{ + ShellResource* pShellRes = ViewShell::GetShellRes(); + SwTOXType * pNew = new SwTOXType(TOX_CONTENT, pShellRes->aTOXContentName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_INDEX, pShellRes->aTOXIndexName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_USER, pShellRes->aTOXUserName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_ILLUSTRATIONS, pShellRes->aTOXIllustrationsName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_OBJECTS, pShellRes->aTOXObjectsName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_TABLES, pShellRes->aTOXTablesName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + pNew = new SwTOXType(TOX_AUTHORITIES, pShellRes->aTOXAuthoritiesName ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); +} + +/*-- 08.05.2009 10:07:57--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SfxObjectShell* SwDoc::CreateCopy(bool bCallInitNew ) const +{ + SwDoc* pRet = new SwDoc; + //copy settings + sal_uInt16 __FAR_DATA aRangeOfDefaults[] = { + RES_FRMATR_BEGIN, RES_FRMATR_END-1, + RES_CHRATR_BEGIN, RES_CHRATR_END-1, + RES_PARATR_BEGIN, RES_PARATR_END-1, + // --> OD 2008-02-25 #refactorlists## + RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1, + // <-- + RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, + 0 + }; + + SfxItemSet aNewDefaults( pRet->GetAttrPool(), aRangeOfDefaults ); + + sal_uInt16 nWhich; + sal_uInt16 nRange = 0; + while( aRangeOfDefaults[nRange] != 0) + { + for( nWhich = aRangeOfDefaults[nRange]; nWhich < aRangeOfDefaults[nRange + 1]; ++nWhich ) + { + const SfxPoolItem& rSourceAttr = mpAttrPool->GetDefaultItem( nWhich ); + if( rSourceAttr != pRet->mpAttrPool->GetDefaultItem( nWhich ) ) + aNewDefaults.Put( rSourceAttr ); + } + nRange += 2; + } + if( aNewDefaults.Count() ) + pRet->SetDefault( aNewDefaults ); + + pRet->n32DummyCompatabilityOptions1 = n32DummyCompatabilityOptions1; + pRet->n32DummyCompatabilityOptions2 = n32DummyCompatabilityOptions2; + pRet->mbParaSpaceMax = mbParaSpaceMax ; + pRet->mbParaSpaceMaxAtPages = mbParaSpaceMaxAtPages ; + pRet->mbTabCompat = mbTabCompat ; + pRet->mbUseVirtualDevice = mbUseVirtualDevice ; + pRet->mbAddExternalLeading = mbAddExternalLeading ; + pRet->mbOldLineSpacing = mbOldLineSpacing ; + pRet->mbAddParaSpacingToTableCells = mbAddParaSpacingToTableCells ; + pRet->mbUseFormerObjectPos = mbUseFormerObjectPos ; + pRet->mbUseFormerTextWrapping = mbUseFormerTextWrapping ; + pRet->mbConsiderWrapOnObjPos = mbConsiderWrapOnObjPos ; + pRet->mbAddFlyOffsets = mbAddFlyOffsets ; + pRet->mbOldNumbering = mbOldNumbering ; + pRet->mbUseHiResolutionVirtualDevice = mbUseHiResolutionVirtualDevice ; + pRet->mbIgnoreFirstLineIndentInNumbering = mbIgnoreFirstLineIndentInNumbering ; + pRet->mbDoNotJustifyLinesWithManualBreak = mbDoNotJustifyLinesWithManualBreak ; + pRet->mbDoNotResetParaAttrsForNumFont = mbDoNotResetParaAttrsForNumFont ; + pRet->mbOutlineLevelYieldsOutlineRule = mbOutlineLevelYieldsOutlineRule ; + pRet->mbTableRowKeep = mbTableRowKeep ; + pRet->mbIgnoreTabsAndBlanksForLineCalculation = mbIgnoreTabsAndBlanksForLineCalculation ; + pRet->mbDoNotCaptureDrawObjsOnPage = mbDoNotCaptureDrawObjsOnPage ; + pRet->mbClipAsCharacterAnchoredWriterFlyFrames= mbClipAsCharacterAnchoredWriterFlyFrames; + pRet->mbUnixForceZeroExtLeading = mbUnixForceZeroExtLeading ; + pRet->mbOldPrinterMetrics = mbOldPrinterMetrics ; + pRet->mbTabRelativeToIndent = mbTabRelativeToIndent ; + pRet->mbTabAtLeftIndentForParagraphsInList = mbTabAtLeftIndentForParagraphsInList ; + + // + // COMPATIBILITY FLAGS END + // + pRet->ReplaceStyles( * const_cast< SwDoc*>( this )); + + // we have to use pointer here, since the callee has to decide whether SfxObjectShellLock or SfxObjectShellRef should be used + // sometimes the object will be returned with refcount set to 0 ( if no DoInitNew is done ) + SfxObjectShell* pRetShell = new SwDocShell( pRet, SFX_CREATE_MODE_STANDARD ); + if( bCallInitNew ) + { + // it could happen that DoInitNew creates model, that increases the refcount of the object + pRetShell->DoInitNew(); + } + + //copy content + pRet->Paste( *this ); + + // remove the temporary shell if it is there as it was done before + pRet->SetTmpDocShell( (SfxObjectShell*)NULL ); + + return pRetShell; +} +/*-- 08.05.2009 10:52:40--------------------------------------------------- + copy document content - code from SwFEShell::Paste( SwDoc* , sal_Bool ) + -----------------------------------------------------------------------*/ +void SwDoc::Paste( const SwDoc& rSource ) +{ +// this has to be empty const sal_uInt16 nStartPageNumber = GetPhyPageNum(); + // until the end of the NodesArray + SwNodeIndex aSourceIdx( rSource.GetNodes().GetEndOfExtras(), 2 ); + SwPaM aCpyPam( aSourceIdx ); //DocStart + SwNodeIndex aTargetIdx( GetNodes().GetEndOfExtras(), 2 ); + SwPaM aInsertPam( aTargetIdx ); //replaces PCURCRSR from SwFEShell::Paste() + + + aCpyPam.SetMark(); + aCpyPam.Move( fnMoveForward, fnGoDoc ); + + this->GetIDocumentUndoRedo().StartUndo( UNDO_INSGLOSSARY, NULL ); + this->LockExpFlds(); + + { + SwPosition& rInsPos = *aInsertPam.GetPoint(); + //find out if the clipboard document starts with a table + bool bStartWithTable = 0 != aCpyPam.Start()->nNode.GetNode().FindTableNode(); + SwPosition aInsertPosition( rInsPos ); + + { + SwNodeIndex aIndexBefore(rInsPos.nNode); + + aIndexBefore--; + + rSource.CopyRange( aCpyPam, rInsPos, true ); + + { + aIndexBefore++; + SwPaM aPaM(SwPosition(aIndexBefore), + SwPosition(rInsPos.nNode)); + + MakeUniqueNumRules(aPaM); + } + } + + //TODO: Is this necessary here? SaveTblBoxCntnt( &rInsPos ); + if(/*bIncludingPageFrames && */bStartWithTable) + { + //remove the paragraph in front of the table + SwPaM aPara(aInsertPosition); + this->DelFullPara(aPara); + } + //additionally copy page bound frames + if( /*bIncludingPageFrames && */rSource.GetSpzFrmFmts()->Count() ) + { + for ( sal_uInt16 i = 0; i < rSource.GetSpzFrmFmts()->Count(); ++i ) + { + sal_Bool bInsWithFmt = sal_True; + const SwFrmFmt& rCpyFmt = *(*rSource.GetSpzFrmFmts())[i]; + if( bInsWithFmt ) + { + SwFmtAnchor aAnchor( rCpyFmt.GetAnchor() ); + if (FLY_AT_PAGE == aAnchor.GetAnchorId()) + { + aAnchor.SetPageNum( aAnchor.GetPageNum() /*+ nStartPageNumber - */); + } + else + continue; + this->CopyLayoutFmt( rCpyFmt, aAnchor, true, true ); + } + } + } + } + + this->GetIDocumentUndoRedo().EndUndo( UNDO_INSGLOSSARY, NULL ); + + UnlockExpFlds(); + UpdateFlds(NULL, false); +} diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx new file mode 100644 index 000000000000..5a559c022c7b --- /dev/null +++ b/sw/source/core/doc/docnum.cxx @@ -0,0 +1,2972 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/resid.hxx> +#include <editeng/lrspitem.hxx> +#include <ftninfo.hxx> +#include <ftnidx.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <doctxm.hxx> // pTOXBaseRing +#include <poolfmt.hxx> +#include <UndoCore.hxx> +#include <UndoRedline.hxx> +#include <UndoNumbering.hxx> +#include <swundo.hxx> +#include <SwUndoFmt.hxx> +#include <rolbck.hxx> +#include <paratr.hxx> +#include <docary.hxx> +#include <mvsave.hxx> +#include <txtfrm.hxx> +#include <pamtyp.hxx> +#include <redline.hxx> +#include <comcore.hrc> +#include <editeng/adjitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <frmatr.hxx> +#include <SwStyleNameMapper.hxx> +#include <SwNodeNum.hxx> +// --> OD 2008-03-13 #refactorlists# +#include <list.hxx> +#include <listfunc.hxx> +// <-- + +#include <map> + +inline sal_uInt8 GetUpperLvlChg( sal_uInt8 nCurLvl, sal_uInt8 nLevel, sal_uInt16 nMask ) +{ + if( 1 < nLevel ) + { + if( nCurLvl + 1 >= nLevel ) + nCurLvl -= nLevel - 1; + else + nCurLvl = 0; + } + return static_cast<sal_uInt8>((nMask - 1) & ~(( 1 << nCurLvl ) - 1)); +} + +void SwDoc::SetOutlineNumRule( const SwNumRule& rRule ) +{ + if( pOutlineRule ) + (*pOutlineRule) = rRule; + else + { + pOutlineRule = new SwNumRule( rRule ); + + AddNumRule(pOutlineRule); // #i36749# + } + + pOutlineRule->SetRuleType( OUTLINE_RULE ); + // --> OD 2008-07-08 #i91400# + pOutlineRule->SetName( String::CreateFromAscii( + SwNumRule::GetOutlineRuleName() ), + *this); + // <-- + // --> OD 2006-09-21 #i69522# + // assure that the outline numbering rule is an automatic rule + pOutlineRule->SetAutoRule( sal_True ); + // <-- + + // teste ob die evt. gesetzen CharFormate in diesem Document + // definiert sind + pOutlineRule->CheckCharFmts( this ); + + // --> OD 2008-05-13 #refactorlists# + // notify text nodes, which are registered at the outline style, about the + // changed outline style + SwNumRule::tTxtNodeList aTxtNodeList; + pOutlineRule->GetTxtNodeList( aTxtNodeList ); + for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); + aIter != aTxtNodeList.end(); ++aIter ) + { + SwTxtNode* pTxtNd = *aIter; + pTxtNd->NumRuleChgd(); + // --> OD 2009-01-20 #i94152# + // assure that list level corresponds to outline level + if ( pTxtNd->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle() && + pTxtNd->GetAttrListLevel() != pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() ) + { + pTxtNd->SetAttrListLevel( pTxtNd->GetTxtColl()->GetAssignedOutlineStyleLevel() ); + } + // <-- + } + // <-- + + PropagateOutlineRule(); + pOutlineRule->SetInvalidRule(sal_True); + UpdateNumRule(); + + // gibt es Fussnoten && gilt Kapitelweises Nummerieren, dann updaten + if( GetFtnIdxs().Count() && FTNNUM_CHAPTER == GetFtnInfo().eNum ) + GetFtnIdxs().UpdateAllFtn(); + + UpdateExpFlds(NULL, true); + + SetModified(); +} + +void SwDoc::PropagateOutlineRule() +{ + for (sal_uInt16 n = 0; n < pTxtFmtCollTbl->Count(); n++) + { + SwTxtFmtColl *pColl = (*pTxtFmtCollTbl)[n]; + + // if (NO_NUMBERING != pColl->GetOutlineLevel())//#outline level,zhaojianwei + if(pColl->IsAssignedToListLevelOfOutlineStyle())//<-end,zhaojianwei + { + SwClientIter aIter(*pColl); + + // --> OD 2006-11-20 #i71764# + // Check only the list style, which is set at the paragraph style + const SwNumRuleItem & rCollRuleItem = pColl->GetNumRule( sal_False ); + // <-- + + // --> OD 2006-11-20 #i71764# + // Check on document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE no longer needed. + if ( rCollRuleItem.GetValue().Len() == 0 ) + // <-- + { + SwNumRule * pMyOutlineRule = GetOutlineNumRule(); + + if (pMyOutlineRule) + { + SwNumRuleItem aNumItem( pMyOutlineRule->GetName() ); + + pColl->SetFmtAttr(aNumItem); + } + } + } + } +} + + // Hoch-/Runterstufen +sal_Bool SwDoc::OutlineUpDown( const SwPaM& rPam, short nOffset ) +{ + if( !GetNodes().GetOutLineNds().Count() || !nOffset ) + return sal_False; + + // den Bereich feststellen + const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); + const SwNodePtr pSttNd = (SwNodePtr)&rPam.Start()->nNode.GetNode(); + const SwNodePtr pEndNd = (SwNodePtr)&rPam.End()->nNode.GetNode(); + sal_uInt16 nSttPos, nEndPos; + + if( !rOutlNds.Seek_Entry( pSttNd, &nSttPos ) && + !nSttPos-- ) + // wir stehen in keiner "Outline-Section" + return sal_False; + + if( rOutlNds.Seek_Entry( pEndNd, &nEndPos ) ) + ++nEndPos; + + // jetzt haben wir unseren Bereich im OutlineNodes-Array + // dann prufe ersmal, ob nicht unterebenen aufgehoben werden + // (Stufung ueber die Grenzen) + sal_uInt16 n; + + // so, dann koennen wir: + // 1. Vorlagen-Array anlegen + SwTxtFmtColl* aCollArr[ MAXLEVEL ]; + memset( aCollArr, 0, sizeof( SwTxtFmtColl* ) * MAXLEVEL ); + + for( n = 0; n < pTxtFmtCollTbl->Count(); ++n ) + { + //sal_uInt8 nLevel = (*pTxtFmtCollTbl)[ n ]->GetOutlineLevel();//#outline level,zhaojianwei + //if( nLevel < MAXLEVEL ) + // aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ]; + if((*pTxtFmtCollTbl)[ n ]->IsAssignedToListLevelOfOutlineStyle()) + { + const int nLevel = (*pTxtFmtCollTbl)[ n ]->GetAssignedOutlineStyleLevel(); + aCollArr[ nLevel ] = (*pTxtFmtCollTbl)[ n ]; + }//<-end,zhaojianwei + } + + /* --> #111107# */ + /* Find the last occupied level (backward). */ + for (n = MAXLEVEL - 1; n > 0; n--) + { + if (aCollArr[n] != 0) + break; + } + + /* If an occupied level is found, choose next level (which IS + unoccupied) until a valid level is found. If no occupied level + was found n is 0 and aCollArr[0] is 0. In this case no demoting + is possible. */ + if (aCollArr[n] != 0) + { + while (n < MAXLEVEL - 1) + { + n++; + + SwTxtFmtColl *aTmpColl = + GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n)); + + //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei + if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() && + aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei + { + aCollArr[n] = aTmpColl; + break; + } + } + } + + /* Find the first occupied level (forward). */ + for (n = 0; n < MAXLEVEL - 1; n++) + { + if (aCollArr[n] != 0) + break; + } + + /* If an occupied level is found, choose previous level (which IS + unoccupied) until a valid level is found. If no occupied level + was found n is MAXLEVEL - 1 and aCollArr[MAXLEVEL - 1] is 0. In + this case no demoting is possible. */ + if (aCollArr[n] != 0) + { + while (n > 0) + { + n--; + + SwTxtFmtColl *aTmpColl = + GetTxtCollFromPool(static_cast<sal_uInt16>(RES_POOLCOLL_HEADLINE1 + n)); + + //if (aTmpColl->GetOutlineLevel() == n)//#outline level,zhaojianwei + if( aTmpColl->IsAssignedToListLevelOfOutlineStyle() && + aTmpColl->GetAssignedOutlineStyleLevel() == n )//<-end,zhaojianwei + { + aCollArr[n] = aTmpColl; + break; + } + } + } + /* <-- #111107# */ + + /* --> #i13747# + + Build a move table that states from which level an outline will + + be moved to which other level. */ + + /* the move table + + aMoveArr[n] = m: replace aCollArr[n] with aCollArr[m] + */ + int aMoveArr[MAXLEVEL]; + int nStep; // step size for searching in aCollArr: -1 or 1 + int nNum; // amount of steps for stepping in aCollArr + + if (nOffset < 0) + { + nStep = -1; + nNum = -nOffset; + } + else + { + nStep = 1; + nNum = nOffset; + } + + /* traverse aCollArr */ + for (n = 0; n < MAXLEVEL; n++) + { + /* If outline level n has an assigned paragraph style step + nNum steps forwards (nStep == 1) or backwards (nStep == + -1). One step is to go to the next non-null entry in + aCollArr in the selected direction. If nNum steps were + possible write the index of the entry found to aCollArr[n], + i.e. outline level n will be replaced by outline level + aCollArr[n]. + + If outline level n has no assigned paragraph style + aMoveArr[n] is set to -1. + */ + if (aCollArr[n] != NULL) + { + sal_uInt16 m = n; + int nCount = nNum; + + while (nCount > 0 && m + nStep >= 0 && m + nStep < MAXLEVEL) + { + m = static_cast<sal_uInt16>(m + nStep); + + if (aCollArr[m] != NULL) + nCount--; + } + + if (nCount == 0) + aMoveArr[n] = m; + else + aMoveArr[n] = -1; + + } + else + aMoveArr[n] = -1; + } + + /* If moving of the outline levels is applicable, i.e. for all + outline levels occuring in the document there has to be a valid + target outline level implied by aMoveArr. */ + bool bMoveApplicable = true; + for (n = nSttPos; n < nEndPos; n++) + { + SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); + SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); +// int nLevel = pColl->GetOutlineLevel();//#outline level,zhaojianwei +// if (aMoveArr[nLevel] == -1) +// bMoveApplicable = false; + if( pColl->IsAssignedToListLevelOfOutlineStyle() ) + { + const int nLevel = pColl->GetAssignedOutlineStyleLevel(); + if (aMoveArr[nLevel] == -1) + bMoveApplicable = false; + }//<-end,zhaojianwei + // --> OD 2008-12-16 #i70748# + // Check on outline level attribute of text node, if text node is + // not an outline via a to outline style assigned paragraph style. + else + { + const int nNewOutlineLevel = pTxtNd->GetAttrOutlineLevel() + nOffset; + if ( nNewOutlineLevel < 1 || nNewOutlineLevel > MAXLEVEL ) + { + bMoveApplicable = false; + } + } + // <-- + } + + if (! bMoveApplicable ) + return sal_False; + + /* <-- #i13747 # */ + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().StartUndo(UNDO_OUTLINE_LR, NULL); + SwUndo *const pUndoOLR( new SwUndoOutlineLeftRight( rPam, nOffset ) ); + GetIDocumentUndoRedo().AppendUndo(pUndoOLR); + } + + // 2. allen Nodes die neue Vorlage zuweisen + + n = nSttPos; + while( n < nEndPos) + { + SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); + SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); + + if( pColl->IsAssignedToListLevelOfOutlineStyle() ) + { + // ASSERT(pColl->GetOutlineLevel() < MAXLEVEL, //#outline level,removed by zhaojianwei + // "non outline node in outline nodes?"); + //int nLevel = pColl->GetOutlineLevel(); + const int nLevel = pColl->GetAssignedOutlineStyleLevel();//#outline level,add by zhaojianwei + + ASSERT(aMoveArr[nLevel] >= 0, + "move table: current TxtColl not found when building table!"); + + + if (nLevel < MAXLEVEL && aMoveArr[nLevel] >= 0) + { + pColl = aCollArr[ aMoveArr[nLevel] ]; + + if (pColl != NULL) + pColl = (SwTxtFmtColl*)pTxtNd->ChgFmtColl( pColl ); + } + + } + else if( pTxtNd->GetAttrOutlineLevel() > 0) //#outline level,add by zhaojianwei + { + int nLevel = pTxtNd->GetAttrOutlineLevel() + nOffset; + if( 0 <= nLevel && nLevel <= MAXLEVEL) + pTxtNd->SetAttrOutlineLevel( nLevel ); + + }//<-end,zhaojianwei + + n++; + // Undo ??? + } + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().EndUndo(UNDO_OUTLINE_LR, NULL); + } + + ChkCondColls(); + SetModified(); + + return sal_True; +} + + + + // Hoch-/Runter - Verschieben ! +sal_Bool SwDoc::MoveOutlinePara( const SwPaM& rPam, short nOffset ) +{ + // kein Verschiebung in den Sonderbereichen + const SwPosition& rStt = *rPam.Start(), + & rEnd = &rStt == rPam.GetPoint() ? *rPam.GetMark() + : *rPam.GetPoint(); + if( !GetNodes().GetOutLineNds().Count() || !nOffset || + (rStt.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex()) || + (rEnd.nNode.GetIndex() < GetNodes().GetEndOfExtras().GetIndex())) + { + return sal_False; + } + + sal_uInt16 nAktPos = 0; + SwNodeIndex aSttRg( rStt.nNode ), aEndRg( rEnd.nNode ); + + //sal_uInt8 nOutLineLevel = NO_NUMBERING; //#outline level,zhaojianwei + int nOutLineLevel = MAXLEVEL; //<-end,zhaojianwei + SwNode* pSrch = &aSttRg.GetNode(); + //if( pSrch->IsTxtNode() ) //#outline level,zhaojianwei + // nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetOutlineLevel()); + if( pSrch->IsTxtNode()) + nOutLineLevel = static_cast<sal_uInt8>(((SwTxtNode*)pSrch)->GetAttrOutlineLevel()-1);//<-end,zhaojianwei + SwNode* pEndSrch = &aEndRg.GetNode(); + if( !GetNodes().GetOutLineNds().Seek_Entry( pSrch, &nAktPos ) ) + { + if( !nAktPos ) + return sal_False; // Promoting or demoting before the first outline => no. + if( --nAktPos ) + aSttRg = *GetNodes().GetOutLineNds()[ nAktPos ]; + else if( 0 > nOffset ) + return sal_False; // Promoting at the top of document?! + else + aSttRg = *GetNodes().GetEndOfContent().StartOfSectionNode(); + } + sal_uInt16 nTmpPos = 0; + // If the given range ends at an outlined text node we have to decide if it has to be a part of + // the moving range or not. Normally it will be a sub outline of our chapter + // and has to be moved, too. But if the chapter ends with a table(or a section end), + // the next text node will be choosen and this could be the next outline of the same level. + // The criteria has to be the outline level: sub level => incorporate, same/higher level => no. + if( GetNodes().GetOutLineNds().Seek_Entry( pEndSrch, &nTmpPos ) ) + { + if( !pEndSrch->IsTxtNode() || pEndSrch == pSrch || + //nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetOutlineLevel() )//#outline level,zhaojianwei + nOutLineLevel < ((SwTxtNode*)pEndSrch)->GetAttrOutlineLevel()-1 )//<-end,zhaojianwei + ++nTmpPos; // For sub outlines only! + } + + aEndRg = nTmpPos < GetNodes().GetOutLineNds().Count() + ? *GetNodes().GetOutLineNds()[ nTmpPos ] + : GetNodes().GetEndOfContent(); + if( nOffset >= 0 ) + nAktPos = nTmpPos; + if( aEndRg == aSttRg ) + { + ASSERT( false, "Moving outlines: Surprising selection" ); + aEndRg++; + } + + const SwNode* pNd; + // The following code corrects the range to handle sections (start/end nodes) + // The range will be extended if the least node before the range is a start node + // which ends inside the range => The complete section will be moved. + // The range will be shrinked if the last position is a start node. + // The range will be shrinked if the last node is an end node which starts before the range. + aSttRg--; + while( aSttRg.GetNode().IsStartNode() ) + { + pNd = aSttRg.GetNode().EndOfSectionNode(); + if( pNd->GetIndex() >= aEndRg.GetIndex() ) + break; + aSttRg--; + } + aSttRg++; + + aEndRg--; + while( aEndRg.GetNode().IsStartNode() ) + aEndRg--; + while( aEndRg.GetNode().IsEndNode() ) + { + pNd = aEndRg.GetNode().StartOfSectionNode(); + if( pNd->GetIndex() >= aSttRg.GetIndex() ) + break; + aEndRg--; + } + aEndRg++; + + // calculation of the new position + if( nOffset < 0 && nAktPos < sal_uInt16(-nOffset) ) + pNd = GetNodes().GetEndOfContent().StartOfSectionNode(); + else if( nAktPos + nOffset >= GetNodes().GetOutLineNds().Count() ) + pNd = &GetNodes().GetEndOfContent(); + else + pNd = GetNodes().GetOutLineNds()[ nAktPos + nOffset ]; + + sal_uLong nNewPos = pNd->GetIndex(); + + // And now a correction of the insert position if necessary... + SwNodeIndex aInsertPos( *pNd, -1 ); + while( aInsertPos.GetNode().IsStartNode() ) + { + // Just before the insert position starts a section: + // when I'm moving forward I do not want to enter the section, + // when I'm moving backward I want to stay in the section if I'm already a part of, + // I want to stay outside if I was outside before. + if( nOffset < 0 ) + { + pNd = aInsertPos.GetNode().EndOfSectionNode(); + if( pNd->GetIndex() >= aEndRg.GetIndex() ) + break; + } + aInsertPos--; + --nNewPos; + } + if( nOffset >= 0 ) + { + // When just before the insert position a section ends, it is okay when I'm moving backward + // because I want to stay outside the section. + // When moving forward I've to check if I started inside or outside the section + // because I don't want to enter of leave such a section + while( aInsertPos.GetNode().IsEndNode() ) + { + pNd = aInsertPos.GetNode().StartOfSectionNode(); + if( pNd->GetIndex() >= aSttRg.GetIndex() ) + break; + aInsertPos--; + --nNewPos; + } + } + // We do not want to move into tables (at the moment) + aInsertPos++; + pNd = &aInsertPos.GetNode(); + if( pNd->IsTableNode() ) + pNd = pNd->StartOfSectionNode(); + if( pNd->FindTableNode() ) + return sal_False; + + ASSERT( aSttRg.GetIndex() > nNewPos || nNewPos >= aEndRg.GetIndex(), + "Position liegt im MoveBereich" ); + + // wurde ein Position in den Sonderbereichen errechnet, dann + // setze die Position auf den Dokumentanfang. + // Sollten da Bereiche oder Tabellen stehen, so werden sie nach + // hinten verschoben. + nNewPos = Max( nNewPos, GetNodes().GetEndOfExtras().GetIndex() + 2 ); + + long nOffs = nNewPos - ( 0 < nOffset ? aEndRg.GetIndex() : aSttRg.GetIndex()); + SwPaM aPam( aSttRg, aEndRg, 0, -1 ); + return MoveParagraph( aPam, nOffs, sal_True ); +} + + +sal_uInt16 lcl_FindOutlineName( const SwNodes& rNds, const String& rName, + sal_Bool bExact ) +{ + sal_uInt16 nSavePos = USHRT_MAX; + const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); + for( sal_uInt16 n = 0; n < rOutlNds.Count(); ++n ) + { + SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); + String sTxt( pTxtNd->GetExpandTxt() ); + if( sTxt.Equals( rName ) ) + { + // "exact" gefunden, setze Pos auf den Node + nSavePos = n; + break; + } + else if( !bExact && USHRT_MAX == nSavePos && + COMPARE_EQUAL == sTxt.CompareTo( rName, rName.Len()) ) + { + // dann vielleicht nur den den 1.Teil vom Text gefunden + nSavePos = n; + } + } + + return nSavePos; +} + + + +sal_uInt16 lcl_FindOutlineNum( const SwNodes& rNds, String& rName ) +{ + // Gueltig Nummern sind (immer nur Offsets!!!): + // ([Nummer]+\.)+ (als regulaerer Ausdruck!) + // (Nummer gefolgt von Punkt, zum 5 Wiederholungen) + // also: "1.1.", "1.", "1.1.1." + xub_StrLen nPos = 0; + String sNum = rName.GetToken( 0, '.', nPos ); + if( STRING_NOTFOUND == nPos ) + return USHRT_MAX; // ungueltige Nummer!!! + + sal_uInt16 nLevelVal[ MAXLEVEL ]; // Nummern aller Levels + memset( nLevelVal, 0, MAXLEVEL * sizeof( nLevelVal[0] )); + sal_uInt8 nLevel = 0; + String sName( rName ); + + while( STRING_NOTFOUND != nPos ) + { + sal_uInt16 nVal = 0; + sal_Unicode c; + for( sal_uInt16 n = 0; n < sNum.Len(); ++n ) + if( '0' <= ( c = sNum.GetChar( n )) && c <= '9' ) + { + nVal *= 10; nVal += c - '0'; + } + else if( nLevel ) + break; // "fast" gueltige Nummer + else + return USHRT_MAX; // ungueltige Nummer!!! + + if( MAXLEVEL > nLevel ) + nLevelVal[ nLevel++ ] = nVal; + + sName.Erase( 0, nPos ); + nPos = 0; + sNum = sName.GetToken( 0, '.', nPos ); + // #i4533# without this check all parts delimited by a dot are treated as outline numbers + if(!ByteString(sNum, gsl_getSystemTextEncoding()).IsNumericAscii()) + nPos = STRING_NOTFOUND; + } + rName = sName; // das ist der nachfolgende Text. + + // alle Levels gelesen, dann suche mal im Document nach dieser + // Gliederung: + const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); + // OS: ohne OutlineNodes lohnt die Suche nicht + // und man spart sich einen Absturz #42958# + if(!rOutlNds.Count()) + return USHRT_MAX; + SwTxtNode* pNd; + nPos = 0; + //search in the existing outline nodes for the required outline num array + for( ; nPos < rOutlNds.Count(); ++nPos ) + { + pNd = rOutlNds[ nPos ]->GetTxtNode(); + //sal_uInt8 nLvl = pNd->GetTxtColl()->GetOutlineLevel(); //#outline level,zhaojianwei + const int nLvl = pNd->GetAttrOutlineLevel()-1; //<-end,zhaojianwei + if( nLvl == nLevel - 1) + { + // check for the outline num + // --> OD 2005-11-02 #i51089 - TUNING# + // --> OD 2006-09-22 #i68289# + // Assure, that text node has the correct numbering level. Otherwise, + // its number vector will not fit to the searched level. +// if ( pNd->GetNum() ) + if ( pNd->GetNum() && + pNd->GetActualListLevel() == ( nLevel - 1 ) ) + // <-- + { + const SwNodeNum & rNdNum = *(pNd->GetNum()); + SwNumberTree::tNumberVector aLevelVal = rNdNum.GetNumberVector(); + //now compare with the one searched for + bool bEqual = true; + for( sal_uInt8 n = 0; (n < nLevel) && bEqual; ++n ) + { + bEqual = aLevelVal[n] == nLevelVal[n]; + } + if(bEqual) + { + break; + } + } + else + { + // --> OD 2006-01-12 #126588# + // A text node, which has an outline paragraph style applied and + // has as hard attribute 'no numbering' set, has an outline level, + // but no numbering tree node. Thus, consider this situation in + // the assertion condition. + ASSERT( !pNd->GetNumRule(), + "<lcl_FindOutlineNum(..)> - text node with outline level and numbering rule, but without numbering tree node. This is a serious defect -> inform OD" ); + } + } + } + if( nPos >= rOutlNds.Count() ) + nPos = USHRT_MAX; + return nPos; +} + + // zu diesem Gliederungspunkt + + + // JP 13.06.96: + // im Namen kann eine Nummer oder/und der Text stehen. + // zuerst wird ueber die Nummer versucht den richtigen Eintrag zu finden. + // Gibt es diesen, dann wird ueber den Text verglichen, od es der + // gewuenschte ist. Ist das nicht der Fall, wird noch mal nur ueber den + // Text gesucht. Wird dieser gefunden ist es der Eintrag. Ansonsten der, + // der ueber die Nummer gefunden wurde. + // Ist keine Nummer angegeben, dann nur den Text suchen. + +sal_Bool SwDoc::GotoOutline( SwPosition& rPos, const String& rName ) const +{ + if( rName.Len() ) + { + const SwOutlineNodes& rOutlNds = GetNodes().GetOutLineNds(); + + // 1. Schritt: ueber die Nummer: + String sName( rName ); + sal_uInt16 nFndPos = ::lcl_FindOutlineNum( GetNodes(), sName ); + if( USHRT_MAX != nFndPos ) + { + SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); + String sExpandedText = pNd->GetExpandTxt(); + //#i4533# leading numbers followed by a dot have been remove while + //searching for the outline position + //to compensate this they must be removed from the paragraphs text content, too + sal_uInt16 nPos = 0; + String sTempNum; + while(sExpandedText.Len() && (sTempNum = sExpandedText.GetToken(0, '.', nPos)).Len() && + STRING_NOTFOUND != nPos && + ByteString(sTempNum, gsl_getSystemTextEncoding()).IsNumericAscii()) + { + sExpandedText.Erase(0, nPos); + nPos = 0; + } + + if( !sExpandedText.Equals( sName ) ) + { + sal_uInt16 nTmp = ::lcl_FindOutlineName( GetNodes(), sName, sal_True ); + if( USHRT_MAX != nTmp ) // ueber den Namen gefunden + { + nFndPos = nTmp; + pNd = rOutlNds[ nFndPos ]->GetTxtNode(); + } + } + rPos.nNode = *pNd; + rPos.nContent.Assign( pNd, 0 ); + return sal_True; + } + + nFndPos = ::lcl_FindOutlineName( GetNodes(), rName, sal_False ); + if( USHRT_MAX != nFndPos ) + { + SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); + rPos.nNode = *pNd; + rPos.nContent.Assign( pNd, 0 ); + return sal_True; + } + + // --> OD 2006-09-22 #i68289# + // additional search on hyperlink URL without its outline numbering part + if ( !sName.Equals( rName ) ) + { + nFndPos = ::lcl_FindOutlineName( GetNodes(), sName, sal_False ); + if( USHRT_MAX != nFndPos ) + { + SwTxtNode* pNd = rOutlNds[ nFndPos ]->GetTxtNode(); + rPos.nNode = *pNd; + rPos.nContent.Assign( pNd, 0 ); + return sal_True; + } + } + // <-- + } + return sal_False; +} + +/* */ + +// --- Nummerierung ----------------------------------------- + +// --> OD 2008-02-19 #refactorlists# +//void SwNumRuleInfo::MakeList( SwDoc& rDoc, sal_Bool ) +//{ +// SwNumRule* pRule = rDoc.FindNumRulePtr(rName); + +// // no rule, no fun. +// if ( !pRule ) +// return; + +// // +// // 1. Case: Information already available at pRule: +// // +// if (pRule->GetTxtNodeList()) +// { +// // copy list to own pList pointer: +// aList = *pRule->GetTxtNodeList(); +// return; +// } + +// // +// // 2. Case: Information has to be generated from scratch: +// // + +// if (pRule->IsOutlineRule()) +// { +// const SwOutlineNodes & rOutlineNodes = rDoc.GetNodes().GetOutLineNds(); + +// for (sal_uInt16 i = 0; i < rOutlineNodes.Count(); ++i) +// { +// SwTxtNode & aNode = *((SwTxtNode *) rOutlineNodes[i]); + +// if (pRule == aNode.GetNumRule()) +// AddNode(aNode); +// } +// } +// { +// SwModify* pMod; +// const SfxPoolItem* pItem; +// sal_uInt16 i, nMaxItems = rDoc.GetAttrPool().GetItemCount +// ( RES_PARATR_NUMRULE); +// for( i = 0; i < nMaxItems; ++i ) +// { +// pItem = rDoc.GetAttrPool().GetItem( RES_PARATR_NUMRULE, i ); +// if( 0 != pItem) +// { +// pMod = (SwModify*)((SwNumRuleItem*)pItem)->GetDefinedIn(); +// if (0 != pMod && +// ((SwNumRuleItem*)pItem)->GetValue().Len() && +// ((SwNumRuleItem*)pItem)->GetValue() == rName ) +// { +// if( pMod->IsA( TYPE( SwFmt )) ) +// pMod->GetInfo( *this ); +// else +// { +// SwTxtNode* pModTxtNode = (SwTxtNode*)pMod; + +// // #115901# +// if( pModTxtNode->GetNodes().IsDocNodes()) +// { +// AddNode( *pModTxtNode ); +// } +// } +// } +// } +// } +// } + +// // --> FME 2004-11-03 #i36571# The numrule and this info structure should +// // have different instances of the list: +// // --> OD 2006-09-12 #i69145# +// // method <SwNumRule::SetList(..)> copies content of list provided by the parameter +// pRule->SetTxtNodeList( aList ); +// // <-- +//} +// <-- + + +void lcl_ChgNumRule( SwDoc& rDoc, const SwNumRule& rRule ) +{ + SwNumRule* pOld = rDoc.FindNumRulePtr( rRule.GetName() ); + ASSERT( pOld, "ohne die alte NumRule geht gar nichts" ); + + sal_uInt16 nChgFmtLevel = 0, nMask = 1; + sal_uInt8 n; + + for( n = 0; n < MAXLEVEL; ++n, nMask <<= 1 ) + { + const SwNumFmt& rOldFmt = pOld->Get( n ), + & rNewFmt = rRule.Get( n ); + + if( rOldFmt != rNewFmt ) + { + nChgFmtLevel |= nMask; + } + else if( SVX_NUM_NUMBER_NONE > rNewFmt.GetNumberingType() && 1 < rNewFmt.GetIncludeUpperLevels() && + 0 != (nChgFmtLevel & GetUpperLvlChg( n, rNewFmt.GetIncludeUpperLevels(),nMask )) ) + nChgFmtLevel |= nMask; + } + + if( !nChgFmtLevel ) // es wurde nichts veraendert? + { + // --> OD 2006-04-27 #i64311# + const bool bInvalidateNumRule( pOld->IsContinusNum() != rRule.IsContinusNum() ); + // <-- + pOld->CheckCharFmts( &rDoc ); + pOld->SetContinusNum( rRule.IsContinusNum() ); + // --> OD 2008-06-17 #i87166# + // Do NOT change list style type +// pOld->SetRuleType( rRule.GetRuleType() ); + // <-- + // --> OD 2006-04-27 #i64311# + if ( bInvalidateNumRule ) + { + pOld->SetInvalidRule(sal_True); + } + // <-- + return ; + } + + // --> OD 2008-02-19 #refactorlists# +// SwNumRuleInfo* pUpd = new SwNumRuleInfo( rRule.GetName() ); +// pUpd->MakeList( rDoc ); + +// sal_uInt8 nLvl; +// for( sal_uLong nFirst = 0, nLast = pUpd->GetList().Count(); +// nFirst < nLast; ++nFirst ) +// { +// SwTxtNode* pTxtNd = pUpd->GetList().GetObject( nFirst ); +// nLvl = static_cast<sal_uInt8>(pTxtNd->GetLevel()); + +// if( nLvl < MAXLEVEL ) +// { +// if( nChgFmtLevel & ( 1 << nLvl )) +// { +// pTxtNd->NumRuleChgd(); +// } +// } +// } + SwNumRule::tTxtNodeList aTxtNodeList; + pOld->GetTxtNodeList( aTxtNodeList ); + sal_uInt8 nLvl( 0 ); + for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); + aIter != aTxtNodeList.end(); ++aIter ) + { + SwTxtNode* pTxtNd = *aIter; + nLvl = static_cast<sal_uInt8>(pTxtNd->GetActualListLevel()); + + if( nLvl < MAXLEVEL ) + { + if( nChgFmtLevel & ( 1 << nLvl )) + { + pTxtNd->NumRuleChgd(); + } + } + } + // <-- + + for( n = 0; n < MAXLEVEL; ++n ) + if( nChgFmtLevel & ( 1 << n )) + pOld->Set( n, rRule.GetNumFmt( n )); + + pOld->CheckCharFmts( &rDoc ); + pOld->SetInvalidRule(sal_True); + pOld->SetContinusNum( rRule.IsContinusNum() ); + // --> OD 2008-06-17 #i87166# + // Do NOT change list style type +// pOld->SetRuleType( rRule.GetRuleType() ); + // <-- + + // --> OD 2008-02-19 #refactorlists# +// delete pUpd; + // <-- + + rDoc.UpdateNumRule(); +} + +// OD 2008-02-08 #newlistlevelattrs# - add handling of parameter <bResetIndentAttrs> +// --> OD 2008-03-17 #refactorlists# +void SwDoc::SetNumRule( const SwPaM& rPam, + const SwNumRule& rRule, + const bool bCreateNewList, + const String sContinuedListId, + sal_Bool bSetItem, + const bool bResetIndentAttrs ) +{ + SwUndoInsNum * pUndo = NULL; + if (GetIDocumentUndoRedo().DoesUndo()) + { + // Start/End for attributes! + GetIDocumentUndoRedo().StartUndo( UNDO_INSNUM, NULL ); + pUndo = new SwUndoInsNum( rPam, rRule ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + SwNumRule * pNew = FindNumRulePtr( rRule.GetName() ); + bool bUpdateRule = false; + + if( !pNew ) + { + pNew = (*pNumRuleTbl)[ MakeNumRule( rRule.GetName(), &rRule ) ]; + } + else if (rRule != *pNew) + { + bUpdateRule = true; + } + + if (bUpdateRule) + { + if( pUndo ) + { + pUndo->SaveOldNumRule( *pNew ); + ::lcl_ChgNumRule( *this, rRule ); + pUndo->SetLRSpaceEndPos(); + } + else + { + ::lcl_ChgNumRule( *this, rRule ); + } + } + + // --> OD 2008-03-17 #refactorlists# + if ( bSetItem ) + { + if ( bCreateNewList ) + { + String sListId; + if ( !bUpdateRule ) + { + // apply list id of list, which has been created for the new list style + sListId = pNew->GetDefaultListId(); + } + else + { + // create new list and apply its list id + SwList* pNewList = createList( String(), pNew->GetName() ); + ASSERT( pNewList, + "<SwDoc::SetNumRule(..)> - could not create new list. Serious defect -> please inform OD." ); + sListId = pNewList->GetListId(); + } + InsertPoolItem( rPam, + SfxStringItem( RES_PARATR_LIST_ID, sListId ), 0 ); + } + else if ( sContinuedListId.Len() > 0 ) + { + // apply given list id + InsertPoolItem( rPam, + SfxStringItem( RES_PARATR_LIST_ID, sContinuedListId ), 0 ); + } + } + // <-- + + if ( ! rPam.HasMark()) + { + SwTxtNode * pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode(); + // --> OD 2006-10-19 #134160# + // consider case that the PaM doesn't denote a text node - e.g. it denotes a graphic node + if ( pTxtNd ) + { + SwNumRule * pRule = pTxtNd->GetNumRule(); + + if (pRule && pRule->GetName() == pNew->GetName()) + { + bSetItem = sal_False; + // --> OD 2008-06-02 #refactorlists# + if ( !pTxtNd->IsInList() ) + { + pTxtNd->AddToList(); + } + // <-- + } + // --> OD 2005-10-26 #b6340308# - only clear numbering attribute at + // text node, if at paragraph style the new numbering rule is found. + else if ( !pRule ) + { + SwTxtFmtColl* pColl = pTxtNd->GetTxtColl(); + if ( pColl ) + { + SwNumRule* pCollRule = FindNumRulePtr(pColl->GetNumRule().GetValue()); + if ( pCollRule && pCollRule->GetName() == pNew->GetName() ) + { + pTxtNd->ResetAttr( RES_PARATR_NUMRULE ); + bSetItem = sal_False; + } + } + } + // <-- + } + // <-- + } + + // --> OD 2009-08-18 #i103817# + if ( bSetItem ) + // <-- + { + InsertPoolItem( rPam, SwNumRuleItem( pNew->GetName() ), 0 ); + } + + // --> OD 2008-02-08 #newlistlevelattrs# + if ( bResetIndentAttrs && + pNew && pNew->Get( 0 ).GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT ) + { + SvUShortsSort aResetAttrsArray; + aResetAttrsArray.Insert( RES_LR_SPACE ); + // --> OD 2010-10-05 #i114929# + // On a selection setup a corresponding Point-and-Mark in order to get + // the indentation attribute reset on all paragraphs touched by the selection + if ( rPam.HasMark() && + rPam.End()->nNode.GetNode().GetTxtNode() ) + { + SwPaM aPam( rPam.Start()->nNode, + rPam.End()->nNode ); + aPam.Start()->nContent = 0; + aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len(); + ResetAttrs( aPam, sal_False, &aResetAttrsArray ); + } + else + { + ResetAttrs( rPam, sal_False, &aResetAttrsArray ); + } + // <-- + } + // <-- + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().EndUndo( UNDO_INSNUM, NULL ); + } + + SetModified(); +} + +void SwDoc::SetCounted(const SwPaM & rPam, bool bCounted) +{ + if ( bCounted ) + { + SvUShortsSort aResetAttrsArray; + aResetAttrsArray.Insert( RES_PARATR_LIST_ISCOUNTED ); + // --> OD 2010-10-05 #i114929# + // On a selection setup a corresponding Point-and-Mark in order to get + // the list-is-counted attribute reset on all paragraphs touched by the selection + if ( rPam.HasMark() && + rPam.End()->nNode.GetNode().GetTxtNode() ) + { + SwPaM aPam( rPam.Start()->nNode, + rPam.End()->nNode ); + aPam.Start()->nContent = 0; + aPam.End()->nContent = rPam.End()->nNode.GetNode().GetTxtNode()->Len(); + ResetAttrs( aPam, sal_False, &aResetAttrsArray ); + } + else + { + ResetAttrs( rPam, sal_False, &aResetAttrsArray ); + } + // <-- + } + else + { + InsertPoolItem( rPam, + SfxBoolItem( RES_PARATR_LIST_ISCOUNTED, sal_False ), 0 ); + } +} + +void SwDoc::SetNumRuleStart( const SwPosition& rPos, sal_Bool bFlag ) +{ + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + + if (pTxtNd) + { + const SwNumRule* pRule = pTxtNd->GetNumRule(); + if( pRule && !bFlag != !pTxtNd->IsListRestart()) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, bFlag) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + pTxtNd->SetListRestart(bFlag ? true : false); + + SetModified(); + } + } +} + +void SwDoc::SetNodeNumStart( const SwPosition& rPos, sal_uInt16 nStt ) +{ + SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + + if (pTxtNd) + { + // --> OD 2008-02-27 #refactorlists# +// const SwNumRule* pRule = pTxtNd->GetNumRule(); +// if( pRule && nStt != pTxtNd->GetListRestartValue() ) +// { +// if( DoesUndo() ) +// { +// ClearRedo(); +// AppendUndo( new SwUndoNumRuleStart( rPos, nStt )); +// } +// } +// pTxtNd->SetListRestartValue(nStt); + +// SetModified(); + if ( !pTxtNd->HasAttrListRestartValue() || + pTxtNd->GetAttrListRestartValue() != nStt ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoNumRuleStart(rPos, nStt) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + pTxtNd->SetAttrListRestartValue( nStt ); + + SetModified(); + } + // <-- + } +} + + // loeschen geht nur, wenn die Rule niemand benutzt! +sal_Bool SwDoc::DelNumRule( const String& rName, sal_Bool bBroadcast ) +{ + sal_uInt16 nPos = FindNumRule( rName ); + + // --> OD 2007-12-17 #151213# + if ( (*pNumRuleTbl)[ nPos ] == GetOutlineNumRule() ) + { + ASSERT( false, + "<SwDoc::DelNumRule(..)> - No deletion of outline list style. This is serious defect - please inform OD" ); + return sal_False; + } + // <-- + + if( USHRT_MAX != nPos && !IsUsed( *(*pNumRuleTbl)[ nPos ] )) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = + new SwUndoNumruleDelete(*(*pNumRuleTbl)[nPos], this); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if (bBroadcast) + BroadcastStyleOperation(rName, SFX_STYLE_FAMILY_PSEUDO, + SFX_STYLESHEET_ERASED); + + // --> OD 2008-04-02 #refactorlists# + deleteListForListStyle( rName ); + { + // delete further list, which have the deleted list style as default list style + std::vector< SwList* > aListsForDeletion; + tHashMapForLists::iterator aListIter = maLists.begin(); + while ( aListIter != maLists.end() ) + { + SwList* pList = (*aListIter).second; + if ( pList->GetDefaultListStyleName() == rName ) + { + aListsForDeletion.push_back( pList ); + } + + ++aListIter; + } + while ( aListsForDeletion.size() > 0 ) + { + SwList* pList = aListsForDeletion.back(); + aListsForDeletion.pop_back(); + deleteList( pList->GetListId() ); + } + } + // <-- + // --> FME 2004-11-02 #i34097# DeleteAndDestroy deletes rName if + // rName is directly taken from the numrule. + const String aTmpName( rName ); + // <-- + pNumRuleTbl->DeleteAndDestroy( nPos ); + maNumRuleMap.erase(aTmpName); + + SetModified(); + return sal_True; + } + return sal_False; +} + +// #106897# +void SwDoc::ChgNumRuleFmts( const SwNumRule& rRule, const String * pName ) +{ + // #106897# + SwNumRule* pRule = FindNumRulePtr( pName ? *pName : rRule.GetName() ); + if( pRule ) + { + SwUndoInsNum* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoInsNum( *pRule, rRule ); + pUndo->GetHistory(); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + } + ::lcl_ChgNumRule( *this, rRule ); + + if( pUndo ) + pUndo->SetLRSpaceEndPos(); + + SetModified(); + } +} + +sal_Bool SwDoc::RenameNumRule(const String & rOldName, const String & rNewName, + sal_Bool bBroadcast) +{ + sal_Bool bResult = sal_False; + SwNumRule * pNumRule = FindNumRulePtr(rOldName); + + if (pNumRule) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoNumruleRename(rOldName, rNewName, this); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + // --> OD 2008-02-19 #refactorlists# +// SwNumRuleInfo aInfo(rOldName); +// aInfo.MakeList(*this); + SwNumRule::tTxtNodeList aTxtNodeList; + pNumRule->GetTxtNodeList( aTxtNodeList ); + // <-- + + // --> OD 2008-07-08 #i91400# + pNumRule->SetName( rNewName, *this ); + // <-- + + SwNumRuleItem aItem(rNewName); + // --> OD 2008-02-19 #refactorlists# +// for (sal_uLong nI = 0; nI < aInfo.GetList().Count(); ++nI) +// { +// SwTxtNode * pTxtNd = aInfo.GetList().GetObject(nI); +// pTxtNd->SwCntntNode::SetAttr(aItem); +// } + for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); + aIter != aTxtNodeList.end(); ++aIter ) + { + SwTxtNode * pTxtNd = *aIter; + pTxtNd->SetAttr(aItem); + } + // <-- + + bResult = sal_True; + + if (bBroadcast) + BroadcastStyleOperation(rOldName, SFX_STYLE_FAMILY_PSEUDO, + SFX_STYLESHEET_MODIFIED); + } + + return bResult; +} + +void SwDoc::StopNumRuleAnimations( OutputDevice* pOut ) +{ + for( sal_uInt16 n = GetNumRuleTbl().Count(); n; ) + { + // --> OD 2008-02-19 #refactorlists# +// SwNumRuleInfo aUpd( GetNumRuleTbl()[ --n ]->GetName() ); +// aUpd.MakeList( *this ); + +// for( sal_uLong nFirst = 0, nLast = aUpd.GetList().Count(); +// nFirst < nLast; ++nFirst ) +// { +// SwTxtNode* pTNd = aUpd.GetList().GetObject( nFirst ); +// SwClientIter aIter( *pTNd ); +// for( SwFrm* pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) ); +// pFrm; pFrm = (SwFrm*)aIter.Next() ) +// if( ((SwTxtFrm*)pFrm)->HasAnimation() ) +// ((SwTxtFrm*)pFrm)->StopAnimation( pOut ); +// } + SwNumRule::tTxtNodeList aTxtNodeList; + GetNumRuleTbl()[ --n ]->GetTxtNodeList( aTxtNodeList ); + for ( SwNumRule::tTxtNodeList::iterator aTxtNodeIter = aTxtNodeList.begin(); + aTxtNodeIter != aTxtNodeList.end(); ++aTxtNodeIter ) + { + SwTxtNode* pTNd = *aTxtNodeIter; + SwClientIter aIter( *pTNd ); + for( SwFrm* pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) ); + pFrm; pFrm = (SwFrm*)aIter.Next() ) + if( ((SwTxtFrm*)pFrm)->HasAnimation() ) + ((SwTxtFrm*)pFrm)->StopAnimation( pOut ); + } + // <-- + } +} + +sal_Bool SwDoc::ReplaceNumRule( const SwPosition& rPos, + const String& rOldRule, const String& rNewRule ) +{ + sal_Bool bRet = sal_False; + SwNumRule *pOldRule = FindNumRulePtr( rOldRule ), + *pNewRule = FindNumRulePtr( rNewRule ); + if( pOldRule && pNewRule && pOldRule != pNewRule ) + { + // --> OD 2008-02-19 #refactorlists# + SwUndoInsNum* pUndo = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + // Start/End for attributes! + GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); + pUndo = new SwUndoInsNum( rPos, *pNewRule, rOldRule ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + // --> OD 2008-02-19 #refactorlists# + // apply new list style <pNewRule> to all text nodes, which have the + // old list style <pOldNRule> applied and belong to the same list as + // the text node of the given <SwPosition>. +// SwNumRuleInfo aUpd( rOldRule ); +// aUpd.MakeList( *this ); + +// if (aUpd.GetList().Count() > 0) // #106897# + SwNumRule::tTxtNodeList aTxtNodeList; + pOldRule->GetTxtNodeList( aTxtNodeList ); + if ( aTxtNodeList.size() > 0 ) + { +// // Position suchen und bestimme ob ein Node davor oder dahinter +// // einen Start erzwingt +// SwTxtNode* pTxtNd; +// sal_uLong nFndPos, nFirst, nLast; + +// if( TABLE_ENTRY_NOTFOUND != aUpd.GetList().SearchKey( +// rPos.nNode.GetIndex(), &nFndPos )) +// ++nFndPos; + +// for( nLast = nFndPos; nLast < aUpd.GetList().Count(); ++nLast ) +// { +// pTxtNd = aUpd.GetList().GetObject( nLast ); +// if(pTxtNd->IsRestart()) +// break; +// } +// for( nFirst = nFndPos; nFirst; ) +// { +// pTxtNd = aUpd.GetList().GetObject( --nFirst ); +// if( pTxtNd->IsRestart() ) +// break; +// } +// // dann neue Numerierung ueber diesen Bereich +// // definieren und den Start am Anfang/Ende zurueck setzen +// pTxtNd = aUpd.GetList().GetObject( nFirst ); +// if( pTxtNd->IsRestart() ) +// { +// pTxtNd->SetRestart(false); +// if( pUndo ) +// pUndo->SetSttNum( pTxtNd->GetIndex() ); +// } + + SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 ); + sal_uInt16 nChgFmtLevel = 0; + for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) + { + const SwNumFmt& rOldFmt = pOldRule->Get( n ), + & rNewFmt = pNewRule->Get( n ); + + if( rOldFmt.GetAbsLSpace() != rNewFmt.GetAbsLSpace() || + rOldFmt.GetFirstLineOffset() != rNewFmt.GetFirstLineOffset() ) + nChgFmtLevel |= ( 1 << n ); + } + + const SwTxtNode* pGivenTxtNode = rPos.nNode.GetNode().GetTxtNode(); + SwNumRuleItem aRule( rNewRule ); +// for( ; nFirst < nLast; ++nFirst ) +// { +// pTxtNd = aUpd.GetList().GetObject( nFirst ); + +// aRegH.RegisterInModify( pTxtNd, *pTxtNd ); + +// pTxtNd->SwCntntNode::SetAttr( aRule ); +// pTxtNd->NumRuleChgd(); +// } + for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); + aIter != aTxtNodeList.end(); ++aIter ) + { + SwTxtNode* pTxtNd = *aIter; + + if ( pGivenTxtNode && + pGivenTxtNode->GetListId() == pTxtNd->GetListId() ) + { + aRegH.RegisterInModify( pTxtNd, *pTxtNd ); + + pTxtNd->SetAttr( aRule ); + pTxtNd->NumRuleChgd(); + } + } + GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + SetModified(); + + bRet = sal_True; // #106897# + } + } + + return bRet; +} + +// --> OD 2008-03-18 #refactorlists# +namespace +{ + struct ListStyleData + { + SwNumRule* pReplaceNumRule; + bool bCreateNewList; + String sListId; + + ListStyleData() + : pReplaceNumRule( 0 ), + bCreateNewList( false ), + sListId() + {} + }; +} +// <-- + +void SwDoc::MakeUniqueNumRules(const SwPaM & rPaM) +{ + ASSERT( rPaM.GetDoc() == this, "need same doc" ); + + // --> OD 2008-03-18 #refactorlists# +// map<SwNumRule *, SwNumRule *> aMyNumRuleMap; + ::std::map<SwNumRule *, ListStyleData> aMyNumRuleMap; + // <-- + + sal_uLong nStt = rPaM.Start()->nNode.GetIndex(); + sal_uLong nEnd = rPaM.End()->nNode.GetIndex(); + + bool bFirst = true; + + for (sal_uLong n = nStt; n <= nEnd; n++) + { + SwTxtNode * pCNd = GetNodes()[n]->GetTxtNode(); + + if (pCNd) + { + SwNumRule * pRule = pCNd->GetNumRule(); + + if (pRule && pRule->IsAutoRule() && ! pRule->IsOutlineRule()) + { + // --> OD 2008-03-18 #refactorlists# +// SwNumRule * pReplaceNumRule = aMyNumRuleMap[pRule]; + ListStyleData aListStyleData = aMyNumRuleMap[pRule]; + +// if (! pReplaceNumRule) + if ( aListStyleData.pReplaceNumRule == 0 ) + { + if (bFirst) + { + SwPosition aPos(*pCNd); + aListStyleData.pReplaceNumRule = + const_cast<SwNumRule *> + (SearchNumRule( aPos, false, pCNd->HasNumber(), + false, 0, + aListStyleData.sListId, true )); + } + +// if (! pReplaceNumRule) + if ( aListStyleData.pReplaceNumRule == 0 ) + { +// pReplaceNumRule = new SwNumRule(*pRule); +// pReplaceNumRule->SetName(GetUniqueNumRuleName()); + aListStyleData.pReplaceNumRule = new SwNumRule(*pRule); + // --> OD 2008-07-08 #i91400# + aListStyleData.pReplaceNumRule->SetName( + GetUniqueNumRuleName(), *this ); + // <-- + aListStyleData.bCreateNewList = true; + } + +// aMyNumRuleMap[pRule] = pReplaceNumRule; + aMyNumRuleMap[pRule] = aListStyleData; + } + + SwPaM aPam(*pCNd); + + SetNumRule( aPam, *aListStyleData.pReplaceNumRule, + aListStyleData.bCreateNewList, + aListStyleData.sListId ); + if ( aListStyleData.bCreateNewList ) + { + aListStyleData.bCreateNewList = false; + aListStyleData.sListId = pCNd->GetListId(); + aMyNumRuleMap[pRule] = aListStyleData; + } + // <-- + + bFirst = false; + } + } + } +} + +sal_Bool SwDoc::NoNum( const SwPaM& rPam ) +{ + + sal_Bool bRet = SplitNode( *rPam.GetPoint(), false ); + // ist ueberhaupt Nummerierung im Spiel ? + if( bRet ) + { + // NoNum setzen und Upaten + const SwNodeIndex& rIdx = rPam.GetPoint()->nNode; + SwTxtNode* pNd = rIdx.GetNode().GetTxtNode(); + const SwNumRule* pRule = pNd->GetNumRule(); + if( pRule ) + { + pNd->SetCountedInList(false); + + SetModified(); + } + else + bRet = sal_False; // keine Nummerierung , ?? oder immer sal_True ?? + } + return bRet; +} + +void SwDoc::DelNumRules( const SwPaM& rPam ) +{ + sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(), + nEnd = rPam.GetMark()->nNode.GetIndex(); + if( nStt > nEnd ) + { + sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp; + } + + SwUndoDelNum* pUndo; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoDelNum( rPam ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + else + pUndo = 0; + + SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 ); + + SwNumRuleItem aEmptyRule( aEmptyStr ); + const SwNode* pOutlNd = 0; + for( ; nStt <= nEnd; ++nStt ) + { + SwTxtNode* pTNd = GetNodes()[ nStt ]->GetTxtNode(); + // --> OD 2008-03-13 #refactorlists# +// if( pTNd && 0 != ( pItem = pTNd->GetNoCondAttr( +// RES_PARATR_NUMRULE, sal_True ) ) && +// ( pName = &((SwNumRuleItem*)pItem)->GetValue())->Len() ) + SwNumRule* pNumRuleOfTxtNode = pTNd ? pTNd->GetNumRule() : 0; + if ( pTNd && pNumRuleOfTxtNode ) + // <-- + { + // recognize changes of attribute for undo + aRegH.RegisterInModify( pTNd, *pTNd ); + + if( pUndo ) + pUndo->AddNode( *pTNd, sal_False ); + + // directly set list style attribute is reset, otherwise empty + // list style is applied + const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet(); + if ( pAttrSet && + pAttrSet->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET ) + pTNd->ResetAttr( RES_PARATR_NUMRULE ); + else + pTNd->SetAttr( aEmptyRule ); + + // --> OD 2008-03-26 #refactorlists# + pTNd->ResetAttr( RES_PARATR_LIST_ID ); + pTNd->ResetAttr( RES_PARATR_LIST_LEVEL ); + pTNd->ResetAttr( RES_PARATR_LIST_ISRESTART ); + pTNd->ResetAttr( RES_PARATR_LIST_RESTARTVALUE ); + pTNd->ResetAttr( RES_PARATR_LIST_ISCOUNTED ); + // <-- + + if( RES_CONDTXTFMTCOLL == pTNd->GetFmtColl()->Which() ) + pTNd->ChkCondColl(); + //else if( !pOutlNd && NO_NUMBERING != //#outline level,zhaojianwei + // ((SwTxtFmtColl*)pTNd->GetFmtColl())->GetOutlineLevel() ) + else if( !pOutlNd && + ((SwTxtFmtColl*)pTNd->GetFmtColl())->IsAssignedToListLevelOfOutlineStyle() )//<-end,zhaojianwei + pOutlNd = pTNd; + } + } + + // dann noch alle Updaten + UpdateNumRule(); + + if( pOutlNd ) + GetNodes().UpdtOutlineIdx( *pOutlNd ); +} + +void SwDoc::InvalidateNumRules() +{ + for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n) + (*pNumRuleTbl)[n]->SetInvalidRule(sal_True); +} + + // zum naechsten/vorhergehenden Punkt auf gleicher Ebene + +sal_Bool lcl_IsNumOk( sal_uInt8 nSrchNum, sal_uInt8& rLower, sal_uInt8& rUpper, + sal_Bool bOverUpper, sal_uInt8 nNumber ) +{ + // --> OD 2008-04-02 #refactorlists# + ASSERT( nNumber < MAXLEVEL, + "<lcl_IsNumOk(..)> - misusage of method" ); + // <-- + + sal_Bool bRet = sal_False; + { + if( bOverUpper ? nSrchNum == nNumber : nSrchNum >= nNumber ) + bRet = sal_True; + else if( nNumber > rLower ) + rLower = nNumber; + else if( nNumber < rUpper ) + rUpper = nNumber; + } + return bRet; +} + +sal_Bool lcl_IsValidPrevNextNumNode( const SwNodeIndex& rIdx ) +{ + sal_Bool bRet = sal_False; + const SwNode& rNd = rIdx.GetNode(); + switch( rNd.GetNodeType() ) + { + case ND_ENDNODE: + bRet = SwTableBoxStartNode == rNd.StartOfSectionNode()->GetStartNodeType() || + rNd.StartOfSectionNode()->IsSectionNode(); + break; + + case ND_STARTNODE: + bRet = SwTableBoxStartNode == ((SwStartNode&)rNd).GetStartNodeType(); + break; + + case ND_SECTIONNODE: // der ist erlaubt, also weiter + bRet = sal_True; + break; + } + return bRet; +} + +sal_Bool lcl_GotoNextPrevNum( SwPosition& rPos, sal_Bool bNext, + sal_Bool bOverUpper, sal_uInt8* pUpper, sal_uInt8* pLower ) +{ + const SwTxtNode* pNd = rPos.nNode.GetNode().GetTxtNode(); + const SwNumRule* pRule; + if( !pNd || 0 == ( pRule = pNd->GetNumRule())) + return sal_False; + + sal_uInt8 nSrchNum = static_cast<sal_uInt8>(pNd->GetActualListLevel()); + + SwNodeIndex aIdx( rPos.nNode ); + if( ! pNd->IsCountedInList() ) + { + // falls gerade mal NO_NUMLEVEL an ist, so such den vorherigen Node + // mit Nummerierung + sal_Bool bError = sal_False; + do { + aIdx--; + if( aIdx.GetNode().IsTxtNode() ) + { + pNd = aIdx.GetNode().GetTxtNode(); + pRule = pNd->GetNumRule(); + + sal_uInt8 nTmpNum; + + if( pRule ) + { + nTmpNum = static_cast<sal_uInt8>(pNd->GetActualListLevel()); + if( !( ! pNd->IsCountedInList() && + (nTmpNum >= nSrchNum )) ) + break; // gefunden + } + else + bError = sal_True; + } + else + bError = !lcl_IsValidPrevNextNumNode( aIdx ); + + } while( !bError ); + if( bError ) + return sal_False; + } + + sal_uInt8 nLower = nSrchNum, nUpper = nSrchNum; + sal_Bool bRet = sal_False; + + const SwTxtNode* pLast; + if( bNext ) + aIdx++, pLast = pNd; + else + aIdx--, pLast = 0; + + while( bNext ? ( aIdx.GetIndex() < aIdx.GetNodes().Count() - 1 ) + : aIdx.GetIndex() ) + { + if( aIdx.GetNode().IsTxtNode() ) + { + pNd = aIdx.GetNode().GetTxtNode(); + pRule = pNd->GetNumRule(); + if( pRule ) + { + if( ::lcl_IsNumOk( nSrchNum, nLower, nUpper, bOverUpper, + static_cast<sal_uInt8>(pNd->GetActualListLevel()) )) + { + rPos.nNode = aIdx; + rPos.nContent.Assign( (SwTxtNode*)pNd, 0 ); + bRet = sal_True; + break; + } + else + pLast = pNd; + } + else + break; + } + else if( !lcl_IsValidPrevNextNumNode( aIdx )) + break; + + if( bNext ) + aIdx++; + else + aIdx--; + } + + if( !bRet && !bOverUpper && pLast ) // nicht ueber hoehere Nummmern, aber bis Ende + { + if( bNext ) + { + rPos.nNode = aIdx; + if( aIdx.GetNode().IsCntntNode() ) + rPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 ); + } + else + { + rPos.nNode.Assign( *pLast ); + rPos.nContent.Assign( (SwTxtNode*)pLast, 0 ); + } + bRet = sal_True; + } + + if( bRet ) + { + if( pUpper ) + *pUpper = nUpper; + if( pLower ) + *pLower = nLower; + } + return bRet; +} + +sal_Bool SwDoc::GotoNextNum( SwPosition& rPos, sal_Bool bOverUpper, + sal_uInt8* pUpper, sal_uInt8* pLower ) +{ + return ::lcl_GotoNextPrevNum( rPos, sal_True, bOverUpper, pUpper, pLower ); +} + +// -> #i23731# +// --> OD 2008-03-18 #refactorlists# - add output parameter <sListId> +const SwNumRule * SwDoc::SearchNumRule(const SwPosition & rPos, + const bool bForward, + const bool bNum, + const bool bOutline, + int nNonEmptyAllowed, + String& sListId, + const bool bInvestigateStartNode) +{ + const SwNumRule * pResult = NULL; + SwTxtNode * pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + SwNode * pStartFromNode = pTxtNd; + + if (pTxtNd) + { + SwNodeIndex aIdx(rPos.nNode); + + // --> OD 2005-10-20 #i55391# + // - the start node has also been investigated, if requested. + const SwNode * pNode = NULL; + do + { + // --> OD 2005-10-20 #i55391# + if ( !bInvestigateStartNode ) + { + if (bForward) + aIdx++; + else + aIdx--; + } + // <-- + if (aIdx.GetNode().IsTxtNode()) + { + pTxtNd = aIdx.GetNode().GetTxtNode(); + + const SwNumRule * pNumRule = pTxtNd->GetNumRule(); + if (pNumRule) + { + if ( ( pNumRule->IsOutlineRule() == ( bOutline ? sal_True : sal_False ) ) && // #115901# + ( ( bNum && pNumRule->Get(0).IsEnumeration()) || + ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560# + { + pResult = pTxtNd->GetNumRule(); + // --> OD 2008-03-18 #refactorlists# + // provide also the list id, to which the text node belongs. + sListId = pTxtNd->GetListId(); + } + + break; + } + else if (pTxtNd->Len() > 0 || NULL != pTxtNd->GetNumRule()) + { + if (nNonEmptyAllowed == 0) + break; + + nNonEmptyAllowed--; + + if (nNonEmptyAllowed < 0) + nNonEmptyAllowed = -1; + } + } + + // --> OD 2005-10-20 #i55391# + if ( bInvestigateStartNode ) + { + if (bForward) + aIdx++; + else + aIdx--; + } + // <-- + + pNode = &aIdx.GetNode(); + } + while (!(pNode == GetNodes().DocumentSectionStartNode(pStartFromNode) || + pNode == GetNodes().DocumentSectionEndNode(pStartFromNode))); + // <-- + } + + return pResult; +} +// <- #i23731# + +sal_Bool SwDoc::GotoPrevNum( SwPosition& rPos, sal_Bool bOverUpper, + sal_uInt8* pUpper, sal_uInt8* pLower ) +{ + return ::lcl_GotoNextPrevNum( rPos, sal_False, bOverUpper, pUpper, pLower ); +} + +sal_Bool SwDoc::NumUpDown( const SwPaM& rPam, sal_Bool bDown ) +{ + sal_uLong nStt = rPam.GetPoint()->nNode.GetIndex(), + nEnd = rPam.GetMark()->nNode.GetIndex(); + if( nStt > nEnd ) + { + sal_uLong nTmp = nStt; nStt = nEnd; nEnd = nTmp; + } + + // -> #115901# outline nodes are promoted or demoted differently + bool bOnlyOutline = true; + bool bOnlyNonOutline = true; + for (sal_uLong n = nStt; n <= nEnd; n++) + { + SwTxtNode * pTxtNd = GetNodes()[n]->GetTxtNode(); + + if (pTxtNd) + { + SwNumRule * pRule = pTxtNd->GetNumRule(); + + if (pRule) + { + if (pRule->IsOutlineRule()) + bOnlyNonOutline = false; + else + bOnlyOutline = false; + } + } + } + // <- #115901# + + sal_Bool bRet = sal_True; + char nDiff = bDown ? 1 : -1; + + // ->#115901# + if (bOnlyOutline) + bRet = OutlineUpDown(rPam, nDiff); + else if (bOnlyNonOutline) + { + /* --> #i24560# + + Only promote or demote if all selected paragraphs are + promotable resp. demotable. + + */ + for (sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp) + { + SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode(); + + // --> OD 2006-10-19 #134160# - make code robust: + // consider case that the node doesn't denote a text node. + if ( pTNd ) + { + SwNumRule * pRule = pTNd->GetNumRule(); + + if (pRule) + { + sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel()); + if( (-1 == nDiff && 0 >= nLevel) || + (1 == nDiff && MAXLEVEL - 1 <= nLevel)) + bRet = sal_False; + } + } + // <-- + } + + if( bRet ) + { + /* <-- #i24560# */ + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoNumUpDown(rPam, nDiff) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + String sNumRule; + + for(sal_uLong nTmp = nStt; nTmp <= nEnd; ++nTmp ) + { + SwTxtNode* pTNd = GetNodes()[ nTmp ]->GetTxtNode(); + + if( pTNd) + { + SwNumRule * pRule = pTNd->GetNumRule(); + + if (pRule) + { + sal_uInt8 nLevel = static_cast<sal_uInt8>(pTNd->GetActualListLevel()); + nLevel = nLevel + nDiff; + + pTNd->SetAttrListLevel(nLevel); + } + } + } + + ChkCondColls(); + SetModified(); + } + } + + return bRet; +} + +sal_Bool SwDoc::MoveParagraph( const SwPaM& rPam, long nOffset, sal_Bool bIsOutlMv ) +{ + const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End(); + + sal_uLong nStIdx = pStt->nNode.GetIndex(); + sal_uLong nEndIdx = pEnd->nNode.GetIndex(); + + // Here are some sophisticated checks whether the wished PaM will be moved or not. + // For moving outlines (bIsOutlMv) I've already done some checks, so here are two different + // checks... + SwNode *pTmp1; + SwNode *pTmp2; + if( bIsOutlMv ) + { + // For moving chapters (outline) the following reason will deny the move: + // if a start node is inside the moved area and its end node outside or vice versa. + // If a start node is the first moved paragraph, its end node has to be within the moved + // area, too (e.g. as last node). + // If an end node is the last node of the moved area, its start node has to be a part of + // the moved section, too. + pTmp1 = GetNodes()[ nStIdx ]; + if( pTmp1->IsStartNode() ) + { // First is a start node + pTmp2 = pTmp1->EndOfSectionNode(); + if( pTmp2->GetIndex() > nEndIdx ) + return sal_False; // Its end node is behind the moved range + } + pTmp1 = pTmp1->StartOfSectionNode()->EndOfSectionNode(); + if( pTmp1->GetIndex() <= nEndIdx ) + return sal_False; // End node inside but start node before moved range => no. + pTmp1 = GetNodes()[ nEndIdx ]; + if( pTmp1->IsEndNode() ) + { // The last one is an end node + pTmp1 = pTmp1->StartOfSectionNode(); + if( pTmp1->GetIndex() < nStIdx ) + return sal_False; // Its start node is before the moved range. + } + pTmp1 = pTmp1->StartOfSectionNode(); + if( pTmp1->GetIndex() >= nStIdx ) + return sal_False; // A start node which ends behind the moved area => no. + } + + sal_uLong nInStIdx, nInEndIdx; + long nOffs = nOffset; + if( nOffset > 0 ) + { + nInEndIdx = nEndIdx; + nEndIdx += nOffset; + ++nOffs; + } + else + { + //Impossible to move to negative index + if( sal_uLong(abs( nOffset )) > nStIdx) + return sal_False; + + nInEndIdx = nStIdx - 1; + nStIdx += nOffset; + } + nInStIdx = nInEndIdx + 1; + // Folgende Absatzbloecke sollen vertauscht werden: + // [ nStIdx, nInEndIdx ] mit [ nInStIdx, nEndIdx ] + + if( nEndIdx >= GetNodes().GetEndOfContent().GetIndex() ) + return sal_False; + + if( !bIsOutlMv ) + { // And here the restrictions for moving paragraphs other than chapters (outlines) + // The plan is to exchange [nStIdx,nInEndIdx] and [nStartIdx,nEndIdx] + // It will checked if the both "start" nodes as well as the both "end" notes belongs to + // the same start-end-section. This is more restrictive than the conditions checked above. + // E.g. a paragraph will not escape from a section or be inserted to another section. + pTmp1 = GetNodes()[ nStIdx ]->StartOfSectionNode(); + pTmp2 = GetNodes()[ nInStIdx ]->StartOfSectionNode(); + if( pTmp1 != pTmp2 ) + return sal_False; // "start" nodes in different sections + pTmp1 = GetNodes()[ nEndIdx ]; + bool bIsEndNode = pTmp1->IsEndNode(); + if( !pTmp1->IsStartNode() ) + { + pTmp1 = pTmp1->StartOfSectionNode(); + if( bIsEndNode ) // For end nodes the first start node is of course inside the range, + pTmp1 = pTmp1->StartOfSectionNode(); // I've to check the start node of the start node. + } + pTmp1 = pTmp1->EndOfSectionNode(); + pTmp2 = GetNodes()[ nInEndIdx ]; + if( !pTmp2->IsStartNode() ) + { + bIsEndNode = pTmp2->IsEndNode(); + pTmp2 = pTmp2->StartOfSectionNode(); + if( bIsEndNode ) + pTmp2 = pTmp2->StartOfSectionNode(); + } + pTmp2 = pTmp2->EndOfSectionNode(); + if( pTmp1 != pTmp2 ) + return sal_False; // The "end" notes are in different sections + } + + // auf Redlining testen - darf die Selektion ueberhaupt verschoben + // werden? + if( !IsIgnoreRedline() ) + { + sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_DELETE ); + if( USHRT_MAX != nRedlPos ) + { + SwPosition aStPos( *pStt ), aEndPos( *pEnd ); + aStPos.nContent = 0; + SwCntntNode* pCNd = pEnd->nNode.GetNode().GetCntntNode(); + aEndPos.nContent = pCNd ? pCNd->Len() : 1; + sal_Bool bCheckDel = sal_True; + + // es existiert fuer den Bereich irgendein Redline-Delete-Object + for( ; nRedlPos < GetRedlineTbl().Count(); ++nRedlPos ) + { + const SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ]; + if( !bCheckDel || nsRedlineType_t::REDLINE_DELETE == pTmp->GetType() ) + { + const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End(); + switch( ComparePosition( *pRStt, *pREnd, aStPos, aEndPos )) + { + case POS_COLLIDE_START: + case POS_BEHIND: // Pos1 liegt hinter Pos2 + nRedlPos = GetRedlineTbl().Count(); + break; + + case POS_COLLIDE_END: + case POS_BEFORE: // Pos1 liegt vor Pos2 + break; + case POS_INSIDE: // Pos1 liegt vollstaendig in Pos2 + // ist erlaubt, aber checke dann alle nachfolgenden + // auf Ueberlappungen + bCheckDel = sal_False; + break; + + case POS_OUTSIDE: // Pos2 liegt vollstaendig in Pos1 + case POS_EQUAL: // Pos1 ist genauso gross wie Pos2 + case POS_OVERLAP_BEFORE: // Pos1 ueberlappt Pos2 am Anfang + case POS_OVERLAP_BEHIND: // Pos1 ueberlappt Pos2 am Ende + return sal_False; + } + } + } + } + } + + { + // DataChanged vorm verschieben verschicken, dann bekommt + // man noch mit, welche Objecte sich im Bereich befinden. + // Danach koennen sie vor/hinter der Position befinden. + SwDataChanged aTmp( rPam, 0 ); + } + + SwNodeIndex aIdx( nOffset > 0 ? pEnd->nNode : pStt->nNode, nOffs ); + SwNodeRange aMvRg( pStt->nNode, 0, pEnd->nNode, +1 ); + + SwRedline* pOwnRedl = 0; + if( IsRedlineOn() ) + { + // wenn der Bereich komplett im eigenen Redline liegt, kann es + // verschoben werden! + sal_uInt16 nRedlPos = GetRedlinePos( pStt->nNode.GetNode(), nsRedlineType_t::REDLINE_INSERT ); + if( USHRT_MAX != nRedlPos ) + { + SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ]; + const SwPosition *pRStt = pTmp->Start(), *pREnd = pTmp->End(); + SwRedline aTmpRedl( nsRedlineType_t::REDLINE_INSERT, rPam ); + const SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode(); + // liegt komplett im Bereich, und ist auch der eigene Redline? + if( aTmpRedl.IsOwnRedline( *pTmp ) && + (pRStt->nNode < pStt->nNode || + (pRStt->nNode == pStt->nNode && !pRStt->nContent.GetIndex()) ) && + (pEnd->nNode < pREnd->nNode || + (pEnd->nNode == pREnd->nNode && + pCEndNd ? pREnd->nContent.GetIndex() == pCEndNd->Len() + : !pREnd->nContent.GetIndex() )) ) + { + pOwnRedl = pTmp; + if( nRedlPos + 1 < GetRedlineTbl().Count() ) + { + pTmp = GetRedlineTbl()[ nRedlPos+1 ]; + if( *pTmp->Start() == *pREnd ) + // dann doch nicht! + pOwnRedl = 0; + } + + if( pOwnRedl && + !( pRStt->nNode <= aIdx && aIdx <= pREnd->nNode )) + { + // nicht in sich selbst, dann auch nicht moven + pOwnRedl = 0; + } + } + } + + if( !pOwnRedl ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); + + // zuerst das Insert, dann das Loeschen + SwPosition aInsPos( aIdx ); + aInsPos.nContent.Assign( aIdx.GetNode().GetCntntNode(), 0 ); + + SwPaM aPam( pStt->nNode, aMvRg.aEnd ); + + SwPaM& rOrigPam = (SwPaM&)rPam; + rOrigPam.DeleteMark(); + rOrigPam.GetPoint()->nNode = aIdx.GetIndex() - 1; + + sal_Bool bDelLastPara = !aInsPos.nNode.GetNode().IsCntntNode(); + + /* #101076# When copying to a non-content node Copy will + insert a paragraph before that node and insert before + that inserted node. Copy creates an SwUndoInserts that + does not cover the extra paragraph. Thus we insert the + extra paragraph ourselves, _with_ correct undo + information. */ + if (bDelLastPara) + { + /* aInsPos points to the non-content node. Move it to + the previous content node. */ + SwPaM aInsPam(aInsPos); + sal_Bool bMoved = aInsPam.Move(fnMoveBackward); + ASSERT(bMoved, "No content node found!"); + + if (bMoved) + { + /* Append the new node after the content node + found. The new position to insert the moved + paragraph at is before the inserted + paragraph. */ + AppendTxtNode(*aInsPam.GetPoint()); + aInsPos = *aInsPam.GetPoint(); + } + } + + CopyRange( aPam, aInsPos, false ); + if( bDelLastPara ) + { + // dann muss der letzte leere Node wieder entfernt werden + aIdx = aInsPos.nNode; + SwCntntNode* pCNd = GetNodes().GoPrevious( &aInsPos.nNode ); + xub_StrLen nCLen = 0; if( pCNd ) nCLen = pCNd->Len(); + aInsPos.nContent.Assign( pCNd, nCLen ); + + // alle die im zu loeschenden Node stehen, mussen auf den + // naechsten umgestezt werden + SwPosition* pPos; + for( sal_uInt16 n = 0; n < GetRedlineTbl().Count(); ++n ) + { + SwRedline* pTmp = GetRedlineTbl()[ n ]; + if( ( pPos = &pTmp->GetBound(sal_True))->nNode == aIdx ) + { + pPos->nNode++; + pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0); + } + if( ( pPos = &pTmp->GetBound(sal_False))->nNode == aIdx ) + { + pPos->nNode++; + pPos->nContent.Assign( pPos->nNode.GetNode().GetCntntNode(),0); + } + } + CorrRel( aIdx, aInsPos, 0, sal_False ); + + pCNd->JoinNext(); + } + + rOrigPam.GetPoint()->nNode++; + rOrigPam.GetPoint()->nContent.Assign( rOrigPam.GetCntntNode(), 0 ); + + RedlineMode_t eOld = GetRedlineMode(); + checkRedlining(eOld); + if (GetIDocumentUndoRedo().DoesUndo()) + { + //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)); + SwUndo *const pUndo(new SwUndoRedlineDelete(aPam, UNDO_DELETE)); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + SwRedline* pNewRedline = new SwRedline( nsRedlineType_t::REDLINE_DELETE, aPam ); + + // #101654# prevent assertion from aPam's target being deleted + // (Alternatively, one could just let aPam go out of scope, but + // that requires touching a lot of code.) + aPam.GetBound(sal_True).nContent.Assign( NULL, 0 ); + aPam.GetBound(sal_False).nContent.Assign( NULL, 0 ); + + AppendRedline( pNewRedline, true ); + +//JP 06.01.98: MUSS noch optimiert werden!!! +SetRedlineMode( eOld ); + GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + SetModified(); + + return sal_True; + } + } + + if( !pOwnRedl && !IsIgnoreRedline() && GetRedlineTbl().Count() ) + { + SwPaM aTemp(aIdx); + SplitRedline(aTemp); + } + + sal_uLong nRedlSttNd(0), nRedlEndNd(0); + if( pOwnRedl ) + { + const SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End(); + nRedlSttNd = pRStt->nNode.GetIndex(); + nRedlEndNd = pREnd->nNode.GetIndex(); + } + + SwUndoMoveNum* pUndo = 0; + sal_uLong nMoved = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndo = new SwUndoMoveNum( rPam, nOffset, bIsOutlMv ); + nMoved = rPam.End()->nNode.GetIndex() - rPam.Start()->nNode.GetIndex() + 1; + } + + + MoveNodeRange( aMvRg, aIdx, DOC_MOVEREDLINES ); + + if( pUndo ) + { + // i57907: Under circumstances (sections at the end of a chapter) + // the rPam.Start() is not moved to the new position. + // But aIdx should be at the new end position and as long as the number of moved paragraphs + // is nMoved, I know, where the new position is. + pUndo->SetStartNode( aIdx.GetIndex() - nMoved ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if( pOwnRedl ) + { + SwPosition *pRStt = pOwnRedl->Start(), *pREnd = pOwnRedl->End(); + if( pRStt->nNode.GetIndex() != nRedlSttNd ) + { + pRStt->nNode = nRedlSttNd; + pRStt->nContent.Assign( pRStt->nNode.GetNode().GetCntntNode(),0); + } + if( pREnd->nNode.GetIndex() != nRedlEndNd ) + { + pREnd->nNode = nRedlEndNd; + SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode(); + xub_StrLen nL = 0; if( pCNd ) nL = pCNd->Len(); + pREnd->nContent.Assign( pCNd, nL ); + } + } + + SetModified(); + return sal_True; +} + +sal_Bool SwDoc::NumOrNoNum( const SwNodeIndex& rIdx, sal_Bool bDel ) +{ + sal_Bool bResult = sal_False; + SwTxtNode * pTxtNd = rIdx.GetNode().GetTxtNode(); + + if (pTxtNd && pTxtNd->GetNumRule() != NULL && + (pTxtNd->HasNumber() || pTxtNd->HasBullet())) + { + if ( !pTxtNd->IsCountedInList() == !bDel) + { + sal_Bool bOldNum = bDel; // == pTxtNd->IsCounted(); + sal_Bool bNewNum = bDel ? sal_False : sal_True; + pTxtNd->SetCountedInList(bNewNum ? true : false); + + SetModified(); + + bResult = sal_True; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoNumOrNoNum * pUndo = + new SwUndoNumOrNoNum(rIdx, bOldNum, bNewNum); + + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + } + else if (bDel && pTxtNd->GetNumRule(sal_False) && + pTxtNd->GetActualListLevel() >= 0 && + pTxtNd->GetActualListLevel() < MAXLEVEL) + { + SwPaM aPam(*pTxtNd); + + DelNumRules(aPam); + + bResult = sal_True; + } + } + + return bResult; +} + +SwNumRule* SwDoc::GetCurrNumRule( const SwPosition& rPos ) const +{ + SwNumRule* pRet = 0; + SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode(); + + if( pTNd ) + { + // --> OD 2008-02-20 #refactorlists# +// pTNd->SyncNumberAndNumRule(); + // <-- + pRet = pTNd->GetNumRule(); + } + + return pRet; +} + +sal_uInt16 SwDoc::FindNumRule( const String& rName ) const +{ + for( sal_uInt16 n = pNumRuleTbl->Count(); n; ) + if( (*pNumRuleTbl)[ --n ]->GetName() == rName ) + return n; + + return USHRT_MAX; +} + +SwNumRule* SwDoc::FindNumRulePtr( const String& rName ) const +{ + SwNumRule * pResult = 0; + + pResult = maNumRuleMap[rName]; + + if ( !pResult ) + { + for (sal_uInt16 n = 0; n < pNumRuleTbl->Count(); ++n) + { + if ((*pNumRuleTbl)[n]->GetName() == rName) + { + pResult = (*pNumRuleTbl)[n]; + + break; + } + } + } + + return pResult; +} + +// #i36749# +void SwDoc::AddNumRule(SwNumRule * pRule) +{ + pNumRuleTbl->Insert(pRule, pNumRuleTbl->Count()); + maNumRuleMap[pRule->GetName()] = pRule; + pRule->SetNumRuleMap(&maNumRuleMap); + + // --> OD 2008-03-26 #refactorlists# + createListForListStyle( pRule->GetName() ); + // <-- +} + +// --> OD 2008-02-11 #newlistlevelattrs# +sal_uInt16 SwDoc::MakeNumRule( const String &rName, + const SwNumRule* pCpy, + sal_Bool bBroadcast, + const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode ) +{ + SwNumRule* pNew; + if( pCpy ) + { + pNew = new SwNumRule( *pCpy ); + + // --> OD 2008-07-08 #i91400# + pNew->SetName( GetUniqueNumRuleName( &rName ), *this ); + // <-- + if( pNew->GetName() != rName ) + { + pNew->SetPoolFmtId( USHRT_MAX ); + pNew->SetPoolHelpId( USHRT_MAX ); + pNew->SetPoolHlpFileId( UCHAR_MAX ); + // --> OD 2008-04-03 #refactorlists# + pNew->SetDefaultListId( String() ); + // <-- + } + pNew->CheckCharFmts( this ); + } + else + { + // --> OD 2008-02-11 #newlistlevelattrs# + pNew = new SwNumRule( GetUniqueNumRuleName( &rName ), + eDefaultNumberFormatPositionAndSpaceMode ); + // <-- + } + + sal_uInt16 nRet = pNumRuleTbl->Count(); + + AddNumRule(pNew); // #i36749# + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo * pUndo = new SwUndoNumruleCreate(pNew, this); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + if (bBroadcast) + BroadcastStyleOperation(pNew->GetName(), SFX_STYLE_FAMILY_PSEUDO, + SFX_STYLESHEET_CREATED); + + return nRet; +} + +String SwDoc::GetUniqueNumRuleName( const String* pChkStr, sal_Bool bAutoNum ) const +{ + String aName; + if( bAutoNum ) + { + long n = Time().GetTime(); + n += Date().GetDate(); + aName = String::CreateFromInt32( n ); + if( pChkStr && !pChkStr->Len() ) + pChkStr = 0; + } + else if( pChkStr && pChkStr->Len() ) + aName = *pChkStr; + else + { + pChkStr = 0; + aName = SW_RESSTR( STR_NUMRULE_DEFNAME ); + } + + sal_uInt16 nNum(0), nTmp, nFlagSize = ( pNumRuleTbl->Count() / 8 ) +2; + sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; + memset( pSetFlags, 0, nFlagSize ); + + xub_StrLen nNmLen = aName.Len(); + if( !bAutoNum && pChkStr ) + { + while( nNmLen-- && '0' <= aName.GetChar( nNmLen ) && + '9' >= aName.GetChar( nNmLen ) ) + ; //nop + + if( ++nNmLen < aName.Len() ) + { + aName.Erase( nNmLen ); + pChkStr = 0; + } + } + + const SwNumRule* pNumRule; + sal_uInt16 n; + + for( n = 0; n < pNumRuleTbl->Count(); ++n ) + if( 0 != ( pNumRule = (*pNumRuleTbl)[ n ] ) ) + { + const String& rNm = pNumRule->GetName(); + if( rNm.Match( aName ) == nNmLen ) + { + // Nummer bestimmen und das Flag setzen + nNum = (sal_uInt16)rNm.Copy( nNmLen ).ToInt32(); + if( nNum-- && nNum < pNumRuleTbl->Count() ) + pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); + } + if( pChkStr && pChkStr->Equals( rNm ) ) + pChkStr = 0; + } + + if( !pChkStr ) + { + // alle Nummern entsprechend geflag, also bestimme die richtige Nummer + nNum = pNumRuleTbl->Count(); + for( n = 0; n < nFlagSize; ++n ) + if( 0xff != ( nTmp = pSetFlags[ n ] )) + { + // also die Nummer bestimmen + nNum = n * 8; + while( nTmp & 1 ) + ++nNum, nTmp >>= 1; + break; + } + + } + delete [] pSetFlags; + if( pChkStr && pChkStr->Len() ) + return *pChkStr; + return aName += String::CreateFromInt32( ++nNum ); +} + +void SwDoc::UpdateNumRule() +{ + const SwNumRuleTbl& rNmTbl = GetNumRuleTbl(); + for( sal_uInt16 n = 0; n < rNmTbl.Count(); ++n ) + if( rNmTbl[ n ]->IsInvalidRule() ) + rNmTbl[ n ]->Validate(); +} + +// --> OD 2008-04-02 #refactorlists# +void SwDoc::MarkListLevel( const String& sListId, + const int nListLevel, + const sal_Bool bValue ) +{ + SwList* pList = getListByName( sListId ); + + if ( pList ) + { + MarkListLevel( *pList, nListLevel, bValue ); + } +} + +void SwDoc::MarkListLevel( SwList& rList, + const int nListLevel, + const sal_Bool bValue ) +{ + // Set new marked list level and notify all affected nodes of the changed mark. + rList.MarkListLevel( nListLevel, bValue ); +} +// <- #i27615# +// <-- + +// #i23726# +sal_Bool SwDoc::IsFirstOfNumRule(SwPosition & rPos) +{ + sal_Bool bResult = sal_False; + SwTxtNode * pTxtNode = rPos.nNode.GetNode().GetTxtNode(); + + if (pTxtNode) + { + SwNumRule * pNumRule = pTxtNode->GetNumRule(); + + if (pNumRule) + bResult = pTxtNode->IsFirstOfNumRule(); + } + + return bResult; +} + +// --> OD 2007-10-26 #i83479# +// implementation for interface <IDocumentListItems> +bool SwDoc::lessThanNodeNum::operator()( const SwNodeNum* pNodeNumOne, + const SwNodeNum* pNodeNumTwo ) const +{ + return pNodeNumOne->LessThan( *pNodeNumTwo ); +} + +void SwDoc::addListItem( const SwNodeNum& rNodeNum ) +{ + if ( mpListItemsList == 0 ) + { + return; + } + + const bool bAlreadyInserted( + mpListItemsList->find( &rNodeNum ) != mpListItemsList->end() ); + ASSERT( !bAlreadyInserted, + "<SwDoc::InsertListItem(..)> - <SwNodeNum> instance already registered as numbered item!" ); + if ( !bAlreadyInserted ) + { + mpListItemsList->insert( &rNodeNum ); + } +} + +void SwDoc::removeListItem( const SwNodeNum& rNodeNum ) +{ + if ( mpListItemsList == 0 ) + { + return; + } + + const tImplSortedNodeNumList::size_type nDeleted = mpListItemsList->erase( &rNodeNum ); + if ( nDeleted > 1 ) + { + ASSERT( false, + "<SwDoc::RemoveListItem(..)> - <SwNodeNum> was registered more than once as numbered item!" ); + } +} + +String SwDoc::getListItemText( const SwNodeNum& rNodeNum, + const bool bWithNumber, + const bool bWithSpacesForLevel ) const +{ + return rNodeNum.GetTxtNode() + ? rNodeNum.GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber, + bWithNumber, bWithSpacesForLevel ) + : String(); +} + +void SwDoc::getListItems( tSortedNodeNumList& orNodeNumList ) const +{ + orNodeNumList.clear(); + orNodeNumList.reserve( mpListItemsList->size() ); + + tImplSortedNodeNumList::iterator aIter; + tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end(); + for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter ) + { + orNodeNumList.push_back( (*aIter) ); + } +} + +void SwDoc::getNumItems( tSortedNodeNumList& orNodeNumList ) const +{ + orNodeNumList.clear(); + orNodeNumList.reserve( mpListItemsList->size() ); + + tImplSortedNodeNumList::iterator aIter; + tImplSortedNodeNumList::iterator aEndIter = mpListItemsList->end(); + for ( aIter = mpListItemsList->begin(); aIter != aEndIter; ++aIter ) + { + const SwNodeNum* pNodeNum = (*aIter); + if ( pNodeNum->IsCounted() && + pNodeNum->GetTxtNode() && pNodeNum->GetTxtNode()->HasNumber() ) + { + orNodeNumList.push_back( pNodeNum ); + } + } +} +// <-- + +// --> OD 2007-11-15 #i83479# +// implementation for interface <IDocumentOutlineNodes> +sal_Int32 SwDoc::getOutlineNodesCount() const +{ + return GetNodes().GetOutLineNds().Count(); +} + +int SwDoc::getOutlineLevel( const sal_Int32 nIdx ) const +{ + return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]-> + // GetTxtNode()->GetOutlineLevel(); //#outline level,zhaojianwei + GetTxtNode()->GetAttrOutlineLevel()-1; //<-end,zhaojianwei +} + +String SwDoc::getOutlineText( const sal_Int32 nIdx, + const bool bWithNumber, + const bool bWithSpacesForLevel ) const +{ + return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]-> + GetTxtNode()->GetExpandTxt( 0, STRING_LEN, bWithNumber, + bWithNumber, bWithSpacesForLevel ); +} + +SwTxtNode* SwDoc::getOutlineNode( const sal_Int32 nIdx ) const +{ + return GetNodes().GetOutLineNds()[ static_cast<sal_uInt16>(nIdx) ]->GetTxtNode(); +} + +void SwDoc::getOutlineNodes( IDocumentOutlineNodes::tSortedOutlineNodeList& orOutlineNodeList ) const +{ + orOutlineNodeList.clear(); + orOutlineNodeList.reserve( getOutlineNodesCount() ); + + const sal_uInt16 nOutlCount( static_cast<sal_uInt16>(getOutlineNodesCount()) ); + for ( sal_uInt16 i = 0; i < nOutlCount; ++i ) + { + orOutlineNodeList.push_back( + GetNodes().GetOutLineNds()[i]->GetTxtNode() ); + } +} +// <-- + +// --> OD 2008-03-26 #refactorlists# +// implementation of interface IDocumentListsAccess +SwList* SwDoc::createList( String sListId, + const String sDefaultListStyleName ) +{ + if ( sListId.Len() == 0 ) + { + sListId = listfunc::CreateUniqueListId( *this ); + } + + if ( getListByName( sListId ) ) + { + ASSERT( false, + "<SwDoc::createList(..)> - provided list id already used. Serious defect -> please inform OD." ); + return 0; + } + + SwNumRule* pDefaultNumRuleForNewList = FindNumRulePtr( sDefaultListStyleName ); + if ( !pDefaultNumRuleForNewList ) + { + ASSERT( false, + "<SwDoc::createList(..)> - for provided default list style name no list style is found. Serious defect -> please inform OD." ); + return 0; + } + + SwList* pNewList = new SwList( sListId, *pDefaultNumRuleForNewList, GetNodes() ); + maLists[sListId] = pNewList; + + return pNewList; +} + +void SwDoc::deleteList( const String sListId ) +{ + SwList* pList = getListByName( sListId ); + if ( pList ) + { + maLists.erase( sListId ); + delete pList; + } +} + +SwList* SwDoc::getListByName( const String sListId ) const +{ + SwList* pList = 0; + + std::hash_map< String, SwList*, StringHash >::const_iterator + aListIter = maLists.find( sListId ); + if ( aListIter != maLists.end() ) + { + pList = (*aListIter).second; + } + + return pList; +} + +SwList* SwDoc::createListForListStyle( const String sListStyleName ) +{ + if ( sListStyleName.Len() == 0 ) + { + ASSERT( false, + "<SwDoc::createListForListStyle(..)> - no list style name provided. Serious defect -> please inform OD." ); + return 0; + } + + if ( getListForListStyle( sListStyleName ) ) + { + ASSERT( false, + "<SwDoc::createListForListStyle(..)> - a list for the provided list style name already exists. Serious defect -> please inform OD." ); + return 0; + } + + SwNumRule* pNumRule = FindNumRulePtr( sListStyleName ); + if ( !pNumRule ) + { + ASSERT( false, + "<SwDoc::createListForListStyle(..)> - for provided list style name no list style is found. Serious defect -> please inform OD." ); + return 0; + } + + String sListId( pNumRule->GetDefaultListId() ); // can be empty String + if ( getListByName( sListId ) ) + { + sListId = String(); + } + SwList* pNewList = createList( sListId, sListStyleName ); + maListStyleLists[sListStyleName] = pNewList; + pNumRule->SetDefaultListId( pNewList->GetListId() ); + + return pNewList; +} + +SwList* SwDoc::getListForListStyle( const String sListStyleName ) const +{ + SwList* pList = 0; + + std::hash_map< String, SwList*, StringHash >::const_iterator + aListIter = maListStyleLists.find( sListStyleName ); + if ( aListIter != maListStyleLists.end() ) + { + pList = (*aListIter).second; + } + + return pList; +} + +void SwDoc::deleteListForListStyle( const String sListStyleName ) +{ + String sListId; + { + SwList* pList = getListForListStyle( sListStyleName ); + ASSERT( pList, + "<SwDoc::deleteListForListStyle(..)> - misusage of method: no list found for given list style name" ); + if ( pList ) + { + sListId = pList->GetListId(); + } + } + if ( sListId.Len() > 0 ) + { + maListStyleLists.erase( sListStyleName ); + deleteList( sListId ); + } +} +// <-- +// --> OD 2008-07-08 #i91400# +void SwDoc::trackChangeOfListStyleName( const String sListStyleName, + const String sNewListStyleName ) +{ + SwList* pList = getListForListStyle( sListStyleName ); + ASSERT( pList, + "<SwDoc::changeOfListStyleName(..)> - misusage of method: no list found for given list style name" ); + + if ( pList != 0 ) + { + maListStyleLists.erase( sListStyleName ); + maListStyleLists[sNewListStyleName] = pList; + } +} +// <-- + +// --> OD 2008-03-13 #refactorlists# +namespace listfunc +{ + const String MakeListIdUnique( const SwDoc& rDoc, + const String aSuggestedUniqueListId ) + { + long nHitCount = 0; + String aTmpStr = aSuggestedUniqueListId; + while ( rDoc.getListByName( aTmpStr ) ) + { + ++nHitCount; + aTmpStr = aSuggestedUniqueListId; + aTmpStr += String::CreateFromInt32( nHitCount ); + } + + return aTmpStr; + } + const String CreateUniqueListId( const SwDoc& rDoc ) + { + // --> OD 2008-08-06 #i92478# + String aNewListId = String::CreateFromAscii( "list" ); + // <-- + sal_Int64 n = Time().GetTime(); + n += Date().GetDate(); + n += rand(); + // --> OD 2008-08-06 #i92478# + aNewListId += String::CreateFromInt64( n ); + // <-- + + return MakeListIdUnique( rDoc, aNewListId ); + } +} +// <-- diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx new file mode 100644 index 000000000000..d18d2166dd96 --- /dev/null +++ b/sw/source/core/doc/docredln.cxx @@ -0,0 +1,3868 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <tools/shl.hxx> +#include <svl/itemiter.hxx> +#include <sfx2/app.hxx> +#include <editeng/colritem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <swmodule.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <ndtxt.hxx> +#include <redline.hxx> +#include <swundo.hxx> +#include <UndoCore.hxx> +#include <UndoRedline.hxx> +#include <hints.hxx> +#include <pamtyp.hxx> +#include <poolfmt.hxx> +#include <viewsh.hxx> +#include <rootfrm.hxx> + +#include <comcore.hrc> + +using namespace com::sun::star; + +TYPEINIT1(SwRedlineHint, SfxHint); + +#ifndef DBG_UTIL + + #define _CHECK_REDLINE( pDoc ) + #define _DEBUG_REDLINE( pDoc ) + +#else + +#define _ERROR_PREFIX "redline table corrupted: " + + // helper function for lcl_CheckRedline + // 1. make sure that pPos->nContent points into pPos->nNode + // (or into the 'special' no-content-node-IndexReg) + // 2. check that position is valid and doesn't point behind text + void lcl_CheckPosition( const SwPosition* pPos ) + { + SwPosition aComparePos( *pPos ); + aComparePos.nContent.Assign( + aComparePos.nNode.GetNode().GetCntntNode(), 0 ); + DBG_ASSERT( pPos->nContent.GetIdxReg() == + aComparePos.nContent.GetIdxReg(), + _ERROR_PREFIX "illegal position" ); + + SwTxtNode* pTxtNode = pPos->nNode.GetNode().GetTxtNode(); + if( pTxtNode == NULL ) + { + DBG_ASSERT( pPos->nContent == 0, + _ERROR_PREFIX "non-text-node with content" ); + } + else + { + DBG_ASSERT( pPos->nContent >= 0 && + pPos->nContent <= pTxtNode->Len(), + _ERROR_PREFIX "index behind text" ); + } + } + + void lcl_CheckPam( const SwPaM* pPam ) + { + DBG_ASSERT( pPam != NULL, _ERROR_PREFIX "illegal argument" ); + lcl_CheckPosition( pPam->GetPoint() ); + lcl_CheckPosition( pPam->GetMark() ); + } + + // check validity of the redline table. Checks redline bounds, and make + // sure the redlines are sorted and non-overlapping. + void lcl_CheckRedline( const SwDoc* pDoc ) + { + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + + // verify valid redline positions + for( sal_uInt16 i = 0; i < rTbl.Count(); ++i ) + lcl_CheckPam( rTbl[ i ] ); + + for( sal_uInt16 j = 0; j < rTbl.Count(); ++j ) + { + // check for empty redlines + DBG_ASSERT( ( *(rTbl[j]->GetPoint()) != *(rTbl[j]->GetMark()) ) || + ( rTbl[j]->GetContentIdx() != NULL ), + _ERROR_PREFIX "empty redline" ); + } + + // verify proper redline sorting + for( sal_uInt16 n = 1; n < rTbl.Count(); ++n ) + { + const SwRedline* pPrev = rTbl[ n-1 ]; + const SwRedline* pCurrent = rTbl[ n ]; + + // check redline sorting + DBG_ASSERT( *pPrev->Start() <= *pCurrent->Start(), + _ERROR_PREFIX "not sorted correctly" ); + + // check for overlapping redlines + DBG_ASSERT( *pPrev->End() <= *pCurrent->Start(), + _ERROR_PREFIX "overlapping redlines" ); + } + } + + #define _CHECK_REDLINE( pDoc ) lcl_CheckRedline( pDoc ); + + void lcl_DebugRedline( const SwDoc* pDoc ) + { + static sal_uInt16 nWatch = 0; + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + sal_uInt16 nDummy = 0; + const SwRedline* pCurrent = rTbl[ n ]; + const SwRedline* pNext = n+1 < rTbl.Count() ? rTbl[ n+1 ] : 0; + if( pCurrent == pNext ) + ++nDummy; + if( n == nWatch ) + ++nDummy; // Possible debugger breakpoint + } + } + + #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc ); + +#endif + +SV_IMPL_OP_PTRARR_SORT( _SwRedlineTbl, SwRedlinePtr ) + +RedlineMode_t SwDoc::GetRedlineMode() const +{ + return eRedlineMode; +} + +void SwDoc::SetRedlineMode( RedlineMode_t eMode ) +{ + if( eRedlineMode != eMode ) + { + if( (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) != (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode) + || 0 == (nsRedlineMode_t::REDLINE_SHOW_MASK & eMode) ) + { + bool bSaveInXMLImportFlag = IsInXMLImport(); + SetInXMLImport( false ); + // und dann alles verstecken, anzeigen + void (SwRedline::*pFnc)( sal_uInt16 ) = 0; + + switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eMode ) + { + case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE : + pFnc = &SwRedline::Show; + break; + case nsRedlineMode_t::REDLINE_SHOW_INSERT: + pFnc = &SwRedline::Hide; + break; + case nsRedlineMode_t::REDLINE_SHOW_DELETE: + pFnc = &SwRedline::ShowOriginal; + break; + + default: + pFnc = &SwRedline::Hide; + eMode = (RedlineMode_t)(eMode | nsRedlineMode_t::REDLINE_SHOW_INSERT); + break; + } + + _CHECK_REDLINE( this ) + + if( pFnc ) + for( sal_uInt16 nLoop = 1; nLoop <= 2; ++nLoop ) + for( sal_uInt16 i = 0; i < pRedlineTbl->Count(); ++i ) + ((*pRedlineTbl)[ i ]->*pFnc)( nLoop ); + _CHECK_REDLINE( this ) + SetInXMLImport( bSaveInXMLImportFlag ); + } + eRedlineMode = eMode; + SetModified(); + } +} + +bool SwDoc::IsRedlineOn() const +{ + return IDocumentRedlineAccess::IsRedlineOn(eRedlineMode); +} + +bool SwDoc::IsIgnoreRedline() const +{ + return (nsRedlineMode_t::REDLINE_IGNORE & eRedlineMode); +} + +void SwDoc::SetRedlineMode_intern(RedlineMode_t eMode) +{ + eRedlineMode = eMode; +} + +const SwRedlineTbl& SwDoc::GetRedlineTbl() const +{ + return *pRedlineTbl; +} + +bool SwDoc::IsRedlineMove() const +{ + return mbIsRedlineMove; +} + +void SwDoc::SetRedlineMove(bool bFlag) +{ + mbIsRedlineMove = bFlag; +} + +const uno::Sequence <sal_Int8>& SwDoc::GetRedlinePassword() const +{ + return aRedlinePasswd; +} + +inline bool IsPrevPos( const SwPosition rPos1, const SwPosition rPos2 ) +{ + const SwCntntNode* pCNd; + return 0 == rPos2.nContent.GetIndex() && + rPos2.nNode.GetIndex() - 1 == rPos1.nNode.GetIndex() && + 0 != ( pCNd = rPos1.nNode.GetNode().GetCntntNode() ) + ? rPos1.nContent.GetIndex() == pCNd->Len() + : false; +} + +#ifdef DEBUG +bool CheckPosition( const SwPosition* pStt, const SwPosition* pEnd ) +{ + int nError = 0; + SwNode* pSttNode = &pStt->nNode.GetNode(); + SwNode* pEndNode = &pEnd->nNode.GetNode(); + SwNode* pSttTab = pSttNode->StartOfSectionNode()->FindTableNode(); + SwNode* pEndTab = pEndNode->StartOfSectionNode()->FindTableNode(); + SwNode* pSttStart = pSttNode; + while( pSttStart && (!pSttStart->IsStartNode() || pSttStart->IsSectionNode() || + pSttStart->IsTableNode() ) ) + pSttStart = pSttStart->StartOfSectionNode(); + SwNode* pEndStart = pEndNode; + while( pEndStart && (!pEndStart->IsStartNode() || pEndStart->IsSectionNode() || + pEndStart->IsTableNode() ) ) + pEndStart = pEndStart->StartOfSectionNode(); + if( pSttTab != pEndTab ) + nError = 1; + if( !pSttTab && pSttStart != pEndStart ) + nError |= 2; + if( nError ) + nError += 10; + return nError != 0; +} +#endif + +/* + +Text heisst, nicht von Redline "verseuchter" Text. + +Verhalten von Insert-Redline: + - im Text - Redline Object einfuegen + - im InsertRedline (eigenes) - ignorieren, bestehendes wird + aufgespannt + - im InsertRedline (andere) - Insert Redline aufsplitten + Redline Object einfuegen + - in DeleteRedline - Delete Redline aufsplitten oder + am Ende/Anfang verschieben + +Verhalten von Delete-Redline: + - im Text - Redline Object einfuegen + - im DeleteRedline (eigenes/andere) - ignorieren + - im InsertRedline (eigenes) - ignorieren, Zeichen aber loeschen + - im InsertRedline (andere) - Insert Redline aufsplitten + Redline Object einfuegen + - Ueberlappung von Text und - Text in eigenen Insert loeschen, + eigenem Insert im andereren Text aufspannen (bis + zum Insert! + - Ueberlappung von Text und - Redline Object einfuegen, der + anderem Insert andere Insert wird vom Delete + ueberlappt +*/ + +bool SwDoc::AppendRedline( SwRedline* pNewRedl, bool bCallDelete ) +{ +#if 0 +// #i93179# disabled: ASSERT in ~SwIndexReg #ifdef DBG_UTIL + SwRedline aCopy( *pNewRedl ); +#endif + bool bError = true; + _CHECK_REDLINE( this ) + + if( IsRedlineOn() && !IsShowOriginal( eRedlineMode ) && + pNewRedl->GetAuthorString().Len() ) + { + pNewRedl->InvalidateRange(); + + if( mbIsAutoFmtRedline ) + { + pNewRedl->SetAutoFmtFlag(); + if( pAutoFmtRedlnComment && pAutoFmtRedlnComment->Len() ) + { + pNewRedl->SetComment( *pAutoFmtRedlnComment ); + pNewRedl->SetSeqNo( nAutoFmtRedlnCommentNo ); + } + } + + SwPosition* pStt = pNewRedl->Start(), + * pEnd = pStt == pNewRedl->GetPoint() ? pNewRedl->GetMark() + : pNewRedl->GetPoint(); + { + SwTxtNode* pTxtNode = pStt->nNode.GetNode().GetTxtNode(); + if( pTxtNode == NULL ) + { + if( pStt->nContent > 0 ) + { + DBG_ASSERT( false, "Redline start: non-text-node with content" ); + pStt->nContent = 0; + } + } + else + { + if( pStt->nContent > pTxtNode->Len() ) + { + DBG_ASSERT( false, "Redline start: index behind text" ); + pStt->nContent = pTxtNode->Len(); + } + } + pTxtNode = pEnd->nNode.GetNode().GetTxtNode(); + if( pTxtNode == NULL ) + { + if( pEnd->nContent > 0 ) + { + DBG_ASSERT( false, "Redline end: non-text-node with content" ); + pEnd->nContent = 0; + } + } + else + { + if( pEnd->nContent > pTxtNode->Len() ) + { + DBG_ASSERT( false, "Redline end: index behind text" ); + pEnd->nContent = pTxtNode->Len(); + } + } + } + if( ( *pStt == *pEnd ) && + ( pNewRedl->GetContentIdx() == NULL ) ) + { // Do not insert empty redlines + delete pNewRedl; + return sal_False; + } + sal_Bool bCompress = sal_False; + sal_uInt16 n = 0; + // zur StartPos das erste Redline suchen + if( !GetRedline( *pStt, &n ) && n ) + --n; + bool bDec = false; + + for( ; pNewRedl && n < pRedlineTbl->Count(); bDec ? n : ++n ) + { + bDec = false; +#ifdef DVO_TEST + _CHECK_REDLINE( this ) +#endif + + SwRedline* pRedl = (*pRedlineTbl)[ n ]; + SwPosition* pRStt = pRedl->Start(), + * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark() + : pRedl->GetPoint(); + + // #i8518# remove empty redlines while we're at it + if( ( *pRStt == *pREnd ) && + ( pRedl->GetContentIdx() == NULL ) ) + { + pRedlineTbl->DeleteAndDestroy(n); + continue; + } + + SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ); + + switch( pNewRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + switch( pRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + if( pRedl->IsOwnRedline( *pNewRedl ) ) + { + bool bDelete = false; + + // ggfs. verschmelzen? + if( (( POS_BEHIND == eCmpPos && + IsPrevPos( *pREnd, *pStt ) ) || + ( POS_COLLIDE_START == eCmpPos ) || + ( POS_OVERLAP_BEHIND == eCmpPos ) ) && + pRedl->CanCombine( *pNewRedl ) && + ( n+1 >= pRedlineTbl->Count() || + ( *(*pRedlineTbl)[ n+1 ]->Start() >= *pEnd && + *(*pRedlineTbl)[ n+1 ]->Start() != *pREnd ) ) ) + { + pRedl->SetEnd( *pEnd, pREnd ); + if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + } + + bError = false; + bDelete = true; + } + else if( (( POS_BEFORE == eCmpPos && + IsPrevPos( *pEnd, *pRStt ) ) || + ( POS_COLLIDE_END == eCmpPos ) || + ( POS_OVERLAP_BEFORE == eCmpPos ) ) && + pRedl->CanCombine( *pNewRedl ) && + ( !n || + *(*pRedlineTbl)[ n-1 ]->End() != *pRStt )) + { + pRedl->SetStart( *pStt, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + + bError = false; + bDelete = true; + } + else if ( POS_OUTSIDE == eCmpPos ) + { + // #107164# own insert-over-insert + // redlines: just scrap the inside ones + pRedlineTbl->Remove( n ); + bDec = true; + } + // <- #107164# + else if( POS_OVERLAP_BEHIND == eCmpPos ) + { + *pStt = *pREnd; + if( ( *pStt == *pEnd ) && + ( pNewRedl->GetContentIdx() == NULL ) ) + bDelete = true; + } + else if( POS_OVERLAP_BEFORE == eCmpPos ) + { + *pEnd = *pRStt; + if( ( *pStt == *pEnd ) && + ( pNewRedl->GetContentIdx() == NULL ) ) + bDelete = true; + } + else if( POS_INSIDE == eCmpPos || POS_EQUAL == eCmpPos) + bDelete = true; + + if( bDelete ) + { + delete pNewRedl, pNewRedl = 0; + bCompress = sal_True; + } + } + else if( POS_INSIDE == eCmpPos ) + { + // aufsplitten + if( *pEnd != *pREnd ) + { + SwRedline* pCpy = new SwRedline( *pRedl ); + pCpy->SetStart( *pEnd ); + pRedlineTbl->Insert( pCpy ); + } + pRedl->SetEnd( *pStt, pREnd ); + if( ( *pStt == *pRStt ) && + ( pRedl->GetContentIdx() == NULL ) ) + { + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + else if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + } + } + else if ( POS_OUTSIDE == eCmpPos ) + { + // #102366# handle overlapping redlines in broken + // documents + + // split up the new redline, since it covers the + // existing redline. Insert the first part, and + // progress with the remainder as usual + SwRedline* pSplit = new SwRedline( *pNewRedl ); + pSplit->SetEnd( *pRStt ); + pNewRedl->SetStart( *pREnd ); + pRedlineTbl->Insert( pSplit ); + if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL ) + { + delete pNewRedl; + pNewRedl = 0; + bCompress = true; + } + } + else if ( POS_OVERLAP_BEHIND == eCmpPos ) + { + // #107164# handle overlapping redlines in broken + // documents + pNewRedl->SetStart( *pREnd ); + } + else if ( POS_OVERLAP_BEFORE == eCmpPos ) + { + // #107164# handle overlapping redlines in broken + // documents + *pEnd = *pRStt; + if( ( *pStt == *pEnd ) && + ( pNewRedl->GetContentIdx() == NULL ) ) + { + delete pNewRedl; + pNewRedl = 0; + bCompress = true; + } + } + break; + case nsRedlineType_t::REDLINE_DELETE: + if( POS_INSIDE == eCmpPos ) + { + // aufsplitten + if( *pEnd != *pREnd ) + { + SwRedline* pCpy = new SwRedline( *pRedl ); + pCpy->SetStart( *pEnd ); + pRedlineTbl->Insert( pCpy ); + } + pRedl->SetEnd( *pStt, pREnd ); + if( ( *pStt == *pRStt ) && + ( pRedl->GetContentIdx() == NULL ) ) + { + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + else if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + } + } + else if ( POS_OUTSIDE == eCmpPos ) + { + // #102366# handle overlapping redlines in broken + // documents + + // split up the new redline, since it covers the + // existing redline. Insert the first part, and + // progress with the remainder as usual + SwRedline* pSplit = new SwRedline( *pNewRedl ); + pSplit->SetEnd( *pRStt ); + pNewRedl->SetStart( *pREnd ); + pRedlineTbl->Insert( pSplit ); + if( *pStt == *pEnd && pNewRedl->GetContentIdx() == NULL ) + { + delete pNewRedl; + pNewRedl = 0; + bCompress = true; + } + } + else if ( POS_EQUAL == eCmpPos ) + { + // #112895# handle identical redlines in broken + // documents - delete old (delete) redline + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + else if ( POS_OVERLAP_BEHIND == eCmpPos ) + { // Another workaround for broken redlines (#107164#) + pNewRedl->SetStart( *pREnd ); + } + break; + case nsRedlineType_t::REDLINE_FORMAT: + switch( eCmpPos ) + { + case POS_OVERLAP_BEFORE: + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + bDec = true; + break; + + case POS_OVERLAP_BEHIND: + pRedl->SetEnd( *pStt, pREnd ); + if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL ) + { + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + break; + + case POS_EQUAL: + case POS_OUTSIDE: + // ueberlappt den akt. komplett oder hat gleiche + // Ausdehung, dann muss der alte geloescht werden + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + break; + + case POS_INSIDE: + // ueberlappt den akt. komplett, dann muss + // der neue gesplittet oder verkuertzt werden + if( *pEnd != *pREnd ) + { + if( *pEnd != *pRStt ) + { + SwRedline* pNew = new SwRedline( *pRedl ); + pNew->SetStart( *pEnd ); + pRedl->SetEnd( *pStt, pREnd ); + if( *pStt == *pRStt && pRedl->GetContentIdx() == NULL ) + pRedlineTbl->DeleteAndDestroy( n ); + AppendRedline( pNew, bCallDelete ); + n = 0; // neu Aufsetzen + bDec = true; + } + } + else + pRedl->SetEnd( *pStt, pREnd ); + break; + default: + break; + } + break; + default: + break; + } + break; + + case nsRedlineType_t::REDLINE_DELETE: + switch( pRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_DELETE: + switch( eCmpPos ) + { + case POS_OUTSIDE: + { + // ueberlappt den akt. komplett + // dann muss der neue gesplittet werden + if( *pEnd != *pREnd ) + { + SwRedline* pNew = new SwRedline( *pNewRedl ); + pNew->SetStart( *pREnd ); + pNewRedl->SetEnd( *pRStt, pEnd ); + AppendRedline( pNew, bCallDelete ); + n = 0; // neu Aufsetzen + bDec = true; + } + else + pNewRedl->SetEnd( *pRStt, pEnd ); + } + break; + + case POS_INSIDE: + case POS_EQUAL: + delete pNewRedl, pNewRedl = 0; + bCompress = sal_True; + break; + + case POS_OVERLAP_BEFORE: + case POS_OVERLAP_BEHIND: + if( pRedl->IsOwnRedline( *pNewRedl ) && +// 1 == pRedl->GetStackCount() && + pRedl->CanCombine( *pNewRedl )) + { + // dann kann das zusammengefasst werden, sprich + // der neue deckt das schon ab. + if( POS_OVERLAP_BEHIND == eCmpPos ) + pNewRedl->SetStart( *pRStt, pStt ); + else + pNewRedl->SetEnd( *pREnd, pEnd ); + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + else if( POS_OVERLAP_BEHIND == eCmpPos ) + pNewRedl->SetStart( *pREnd, pStt ); + else + pNewRedl->SetEnd( *pRStt, pEnd ); + break; + + case POS_COLLIDE_START: + case POS_COLLIDE_END: + if( pRedl->IsOwnRedline( *pNewRedl ) && +// 1 == pRedl->GetStackCount() && + pRedl->CanCombine( *pNewRedl ) ) + { + if( IsHideChanges( eRedlineMode )) + { + // dann erstmal sichtbar machen, bevor + // die zusammengefasst werden koennen! + // Damit pNew auch beim Verschieben der + // Indizies behandelt wird, erstmal + // temporaer einfuegen + pRedlineTbl->SavePtrInArr( pNewRedl ); + pRedl->Show(); + pRedlineTbl->Remove( pRedlineTbl->GetPos(pNewRedl )); + pRStt = pRedl->Start(); + pREnd = pRedl->End(); + } + + // dann kann das zusammengefasst werden, sprich + // der neue deckt das schon ab. + if( POS_COLLIDE_START == eCmpPos ) + pNewRedl->SetStart( *pRStt, pStt ); + else + pNewRedl->SetEnd( *pREnd, pEnd ); + + // delete current (below), and restart process with + // previous + sal_uInt16 nToBeDeleted = n; + bDec = true; + + // #107359# Do it again, Sam! + // If you can do it for them, you can do it for me. + if( *(pNewRedl->Start()) <= *pREnd ) + { + // Whoooah, we just extended the new 'redline' + // beyond previous redlines, so better start + // again. Of course this is not supposed to + // happen, and in an ideal world it doesn't, + // but unfortunately this code is buggy and + // totally rotten so it does happen and we + // better fix it. + n = 0; + bDec = true; + } + + pRedlineTbl->DeleteAndDestroy( nToBeDeleted ); + } + break; + default: + break; + } + break; + + case nsRedlineType_t::REDLINE_INSERT: + { + // b62341295: Do not throw away redlines + // even if they are not allowed to be combined + RedlineMode_t eOld = eRedlineMode; + if( !( eOld & nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) && + pRedl->IsOwnRedline( *pNewRedl ) ) + { + +// auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig +// zusammen fasst! Der ShowMode muss erhalten bleiben! + eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)); + switch( eCmpPos ) + { + case POS_EQUAL: + bCompress = sal_True; + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + // kein break! + + case POS_INSIDE: + if( bCallDelete ) + { + eRedlineMode = (RedlineMode_t)(eRedlineMode | nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES); + + // #98863# DeleteAndJoin does not yield the + // desired result if there is no paragraph to + // join with, i.e. at the end of the document. + // For this case, we completely delete the + // paragraphs (if, of course, we also start on + // a paragraph boundary). + if( (pStt->nContent == 0) && + pEnd->nNode.GetNode().IsEndNode() ) + { + pEnd->nNode--; + pEnd->nContent.Assign( + pEnd->nNode.GetNode().GetTxtNode(), 0); + DelFullPara( *pNewRedl ); + } + else + DeleteAndJoin( *pNewRedl ); + + bCompress = sal_True; + } + delete pNewRedl, pNewRedl = 0; + break; + + case POS_OUTSIDE: + { + pRedlineTbl->Remove( n ); + bDec = true; + // damit pNew auch beim Verschieben der Indizies + // behandelt wird, erstmal temp. einfuegen + if( bCallDelete ) + { + pRedlineTbl->SavePtrInArr( pNewRedl ); + DeleteAndJoin( *pRedl ); + sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl ); + if( USHRT_MAX != nFnd ) + pRedlineTbl->Remove( nFnd ); + else + pNewRedl = 0; + } + delete pRedl; + } + break; + + case POS_OVERLAP_BEFORE: + { + SwPaM aPam( *pRStt, *pEnd ); + + if( *pEnd == *pREnd ) + pRedlineTbl->DeleteAndDestroy( n ); + else + { + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + } + + if( bCallDelete ) + { + // damit pNew auch beim Verschieben der Indizies + // behandelt wird, erstmal temp. einfuegen + pRedlineTbl->SavePtrInArr( pNewRedl ); + DeleteAndJoin( aPam ); + sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl ); + if( USHRT_MAX != nFnd ) + pRedlineTbl->Remove( nFnd ); + else + pNewRedl = 0; + n = 0; // neu Aufsetzen + } + bDec = true; + } + break; + + case POS_OVERLAP_BEHIND: + { + SwPaM aPam( *pStt, *pREnd ); + + if( *pStt == *pRStt ) + { + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + else + pRedl->SetEnd( *pStt, pREnd ); + + if( bCallDelete ) + { + // damit pNew auch beim Verschieben der Indizies + // behandelt wird, erstmal temp. einfuegen + pRedlineTbl->SavePtrInArr( pNewRedl ); + DeleteAndJoin( aPam ); + sal_uInt16 nFnd = pRedlineTbl->GetPos(pNewRedl ); + if( USHRT_MAX != nFnd ) + pRedlineTbl->Remove( nFnd ); + else + pNewRedl = 0; + n = 0; // neu Aufsetzen + bDec = true; + } + } + break; + default: + break; + } + + eRedlineMode = eOld; + } + else + { + // it may be necessary to split the existing redline in + // two. In this case, pRedl will be changed to cover + // only part of it's former range, and pNew will cover + // the remainder. + SwRedline* pNew = 0; + + switch( eCmpPos ) + { + case POS_EQUAL: + { + pRedl->PushData( *pNewRedl ); + delete pNewRedl, pNewRedl = 0; + if( IsHideChanges( eRedlineMode )) + pRedl->Hide(); + bCompress = sal_True; + } + break; + + case POS_INSIDE: + { + if( *pRStt == *pStt ) + { + // --> mst 2010-05-17 #i97421# + // redline w/out extent loops + if (*pStt != *pEnd) + // <-- + { + pNewRedl->PushData( *pRedl, sal_False ); + pRedl->SetStart( *pEnd, pRStt ); + // re-insert + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + bDec = true; + } + } + else + { + pNewRedl->PushData( *pRedl, sal_False ); + if( *pREnd != *pEnd ) + { + pNew = new SwRedline( *pRedl ); + pNew->SetStart( *pEnd ); + } + pRedl->SetEnd( *pStt, pREnd ); + if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + } + } + } + break; + + case POS_OUTSIDE: + { + pRedl->PushData( *pNewRedl ); + if( *pEnd == *pREnd ) + pNewRedl->SetEnd( *pRStt, pEnd ); + else + { + pNew = new SwRedline( *pNewRedl ); + pNew->SetEnd( *pRStt ); + pNewRedl->SetStart( *pREnd, pStt ); + } + bCompress = sal_True; + } + break; + + case POS_OVERLAP_BEFORE: + { + if( *pEnd == *pREnd ) + { + pRedl->PushData( *pNewRedl ); + pNewRedl->SetEnd( *pRStt, pEnd ); + if( IsHideChanges( eRedlineMode )) + { + pRedlineTbl->SavePtrInArr( pNewRedl ); + pRedl->Hide(); + pRedlineTbl->Remove( + pRedlineTbl->GetPos(pNewRedl )); + } + } + else + { + pNew = new SwRedline( *pRedl ); + pNew->PushData( *pNewRedl ); + pNew->SetEnd( *pEnd ); + pNewRedl->SetEnd( *pRStt, pEnd ); + pRedl->SetStart( *pNew->End(), pRStt ) ; + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + bDec = true; + } + } + break; + + case POS_OVERLAP_BEHIND: + { + if( *pStt == *pRStt ) + { + pRedl->PushData( *pNewRedl ); + pNewRedl->SetStart( *pREnd, pStt ); + if( IsHideChanges( eRedlineMode )) + { + pRedlineTbl->SavePtrInArr( pNewRedl ); + pRedl->Hide(); + pRedlineTbl->Remove( + pRedlineTbl->GetPos(pNewRedl )); + } + } + else + { + pNew = new SwRedline( *pRedl ); + pNew->PushData( *pNewRedl ); + pNew->SetStart( *pStt ); + pNewRedl->SetStart( *pREnd, pStt ); + pRedl->SetEnd( *pNew->Start(), pREnd ); + if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + } + } + } + break; + default: + break; + } + + // insert the pNew part (if it exists) + if( pNew ) + { + // AppendRedline( pNew, bCallDelete ); + //sal_Bool bRet = + pRedlineTbl->Insert( pNew ); + + // pNew must be deleted if Insert() wasn't + // successful. But that can't happen, since pNew is + // part of the original pRedl redline. + // ASSERT( bRet, "Can't insert existing redline?" ); + + // restart (now with pRedl being split up) + n = 0; + bDec = true; + } + } + } + break; + + case nsRedlineType_t::REDLINE_FORMAT: + switch( eCmpPos ) + { + case POS_OVERLAP_BEFORE: + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + bDec = true; + break; + + case POS_OVERLAP_BEHIND: + pRedl->SetEnd( *pStt, pREnd ); + break; + + case POS_EQUAL: + case POS_OUTSIDE: + // ueberlappt den akt. komplett oder hat gleiche + // Ausdehung, dann muss der alte geloescht werden + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + break; + + case POS_INSIDE: + // ueberlappt den akt. komplett, dann muss + // der neue gesplittet oder verkuertzt werden + if( *pEnd != *pREnd ) + { + if( *pEnd != *pRStt ) + { + SwRedline* pNew = new SwRedline( *pRedl ); + pNew->SetStart( *pEnd ); + pRedl->SetEnd( *pStt, pREnd ); + if( ( *pStt == *pRStt ) && + ( pRedl->GetContentIdx() == NULL ) ) + pRedlineTbl->DeleteAndDestroy( n ); + AppendRedline( pNew, bCallDelete ); + n = 0; // neu Aufsetzen + bDec = true; + } + } + else + pRedl->SetEnd( *pStt, pREnd ); + break; + default: + break; + } + break; + default: + break; + } + break; + + case nsRedlineType_t::REDLINE_FORMAT: + switch( pRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + case nsRedlineType_t::REDLINE_DELETE: + switch( eCmpPos ) + { + case POS_OVERLAP_BEFORE: + pNewRedl->SetEnd( *pRStt, pEnd ); + break; + + case POS_OVERLAP_BEHIND: + pNewRedl->SetStart( *pREnd, pStt ); + break; + + case POS_EQUAL: + case POS_INSIDE: + delete pNewRedl, pNewRedl = 0; + break; + + case POS_OUTSIDE: + // ueberlappt den akt. komplett, dann muss + // der neue gesplittet oder verkuerzt werden + if( *pEnd != *pREnd ) + { + if( *pEnd != *pRStt ) + { + SwRedline* pNew = new SwRedline( *pNewRedl ); + pNew->SetStart( *pREnd ); + pNewRedl->SetEnd( *pRStt, pEnd ); + AppendRedline( pNew, bCallDelete ); + n = 0; // neu Aufsetzen + bDec = true; + } + } + else + pNewRedl->SetEnd( *pRStt, pEnd ); + break; + default: + break; + } + break; + case nsRedlineType_t::REDLINE_FORMAT: + switch( eCmpPos ) + { + case POS_OUTSIDE: + case POS_EQUAL: + { + // ueberlappt den akt. komplett oder hat gleiche + // Ausdehnung, dann muss der alte geloescht werden + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + break; + + case POS_INSIDE: + if( pRedl->IsOwnRedline( *pNewRedl ) && + pRedl->CanCombine( *pNewRedl )) + // ein eigenes kann komplett ignoriert werden + delete pNewRedl, pNewRedl = 0; + + else if( *pREnd == *pEnd ) + // ansonsten nur den akt. verkuerzen + pRedl->SetEnd( *pStt, pREnd ); + else if( *pRStt == *pStt ) + { + // ansonsten nur den akt. verkuerzen + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl, n ); + bDec = true; + } + else + { + // liegt komplett im akt. + // dann muss der gesplittet werden + SwRedline* pNew = new SwRedline( *pRedl ); + pNew->SetStart( *pEnd ); + pRedl->SetEnd( *pStt, pREnd ); + AppendRedline( pNew, bCallDelete ); + n = 0; // neu Aufsetzen + bDec = true; + } + break; + + case POS_OVERLAP_BEFORE: + case POS_OVERLAP_BEHIND: + if( pRedl->IsOwnRedline( *pNewRedl ) && + pRedl->CanCombine( *pNewRedl )) + { + // dann kann das zusammengefasst werden, sprich + // der neue deckt das schon ab. + if( POS_OVERLAP_BEHIND == eCmpPos ) + pNewRedl->SetStart( *pRStt, pStt ); + else + pNewRedl->SetEnd( *pREnd, pEnd ); + pRedlineTbl->DeleteAndDestroy( n ); + bDec = 0; + } + else if( POS_OVERLAP_BEHIND == eCmpPos ) + pNewRedl->SetStart( *pREnd, pStt ); + else + pNewRedl->SetEnd( *pRStt, pEnd ); + break; + + case POS_COLLIDE_END: + if( pRedl->IsOwnRedline( *pNewRedl ) && + pRedl->CanCombine( *pNewRedl ) && n && + *(*pRedlineTbl)[ n-1 ]->End() < *pStt ) + { + // dann kann das zusammengefasst werden, sprich + // der neue deckt das schon ab. + pNewRedl->SetEnd( *pREnd, pEnd ); + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + break; + case POS_COLLIDE_START: + if( pRedl->IsOwnRedline( *pNewRedl ) && + pRedl->CanCombine( *pNewRedl ) && + n+1 < pRedlineTbl->Count() && + *(*pRedlineTbl)[ n+1 ]->Start() < *pEnd ) + { + // dann kann das zusammengefasst werden, sprich + // der neue deckt das schon ab. + pNewRedl->SetStart( *pRStt, pStt ); + pRedlineTbl->DeleteAndDestroy( n ); + bDec = true; + } + break; + default: + break; + } + break; + default: + break; + } + break; + + + case nsRedlineType_t::REDLINE_FMTCOLL: + // wie soll das verhalten sein???? + // erstmal so einfuegen + break; + default: + break; + } + } + + if( pNewRedl ) + { + if( ( *pStt == *pEnd ) && + ( pNewRedl->GetContentIdx() == NULL ) ) + { // Do not insert empty redlines + delete pNewRedl; + pNewRedl = 0; + } + else + pRedlineTbl->Insert( pNewRedl ); + } + + if( bCompress ) + CompressRedlines(); + } + else + { + if( bCallDelete && nsRedlineType_t::REDLINE_DELETE == pNewRedl->GetType() ) + { + RedlineMode_t eOld = eRedlineMode; +// auf NONE setzen, damit das Delete::Redo die RedlineDaten wieder richtig +// zusammen fasst! Der ShowMode muss erhalten bleiben! + eRedlineMode = (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE)); + DeleteAndJoin( *pNewRedl ); + eRedlineMode = eOld; + } + delete pNewRedl, pNewRedl = 0; + } + _CHECK_REDLINE( this ) + + return ( 0 != pNewRedl ) || !bError; +} + +void SwDoc::CompressRedlines() +{ + _CHECK_REDLINE( this ) + + void (SwRedline::*pFnc)(sal_uInt16) = 0; + switch( nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode ) + { + case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE: + pFnc = &SwRedline::Show; + break; + case nsRedlineMode_t::REDLINE_SHOW_INSERT: + pFnc = &SwRedline::Hide; + break; + } + + // versuche gleiche zusammenzufassen + for( sal_uInt16 n = 1; n < pRedlineTbl->Count(); ++n ) + { + SwRedline* pPrev = (*pRedlineTbl)[ n-1 ], + * pCur = (*pRedlineTbl)[ n ]; + const SwPosition* pPrevStt = pPrev->Start(), + * pPrevEnd = pPrevStt == pPrev->GetPoint() + ? pPrev->GetMark() : pPrev->GetPoint(); + const SwPosition* pCurStt = pCur->Start(), + * pCurEnd = pCurStt == pCur->GetPoint() + ? pCur->GetMark() : pCur->GetPoint(); + if( *pPrevEnd == *pCurStt && pPrev->CanCombine( *pCur ) && + pPrevStt->nNode.GetNode().StartOfSectionNode() == + pCurEnd->nNode.GetNode().StartOfSectionNode() && + !pCurEnd->nNode.GetNode().StartOfSectionNode()->IsTableNode() ) + { + // dann koennen die zusammen gefasst werden + pPrev->Show(); + pCur->Show(); + + pPrev->SetEnd( *pCur->End() ); + pRedlineTbl->DeleteAndDestroy( n ); + --n; + if( pFnc ) + (pPrev->*pFnc)(0); + } + } + _CHECK_REDLINE( this ) +} + +bool SwDoc::SplitRedline( const SwPaM& rRange ) +{ + sal_Bool bChg = sal_False; + sal_uInt16 n = 0; + const SwPosition* pStt = rRange.Start(), + * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark() + : rRange.GetPoint(); + GetRedline( *pStt, &n ); + for( ; n < pRedlineTbl->Count() ; ++n ) + { + SwRedline* pTmp = (*pRedlineTbl)[ n ]; + SwPosition* pTStt = pTmp->Start(), + * pTEnd = pTStt == pTmp->GetPoint() ? pTmp->GetMark() + : pTmp->GetPoint(); + if( *pTStt <= *pStt && *pStt <= *pTEnd && + *pTStt <= *pEnd && *pEnd <= *pTEnd ) + { + bChg = sal_True; + int nn = 0; + if( *pStt == *pTStt ) + nn += 1; + if( *pEnd == *pTEnd ) + nn += 2; + + SwRedline* pNew = 0; + switch( nn ) + { + case 0: + pNew = new SwRedline( *pTmp ); + pTmp->SetEnd( *pStt, pTEnd ); + pNew->SetStart( *pEnd ); + break; + + case 1: + *pTStt = *pEnd; + break; + + case 2: + *pTEnd = *pStt; + break; + + case 3: + pTmp->InvalidateRange(); + pRedlineTbl->DeleteAndDestroy( n-- ); + pTmp = 0; + break; + } + if( pTmp && !pTmp->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pTmp, n ); + } + if( pNew ) + pRedlineTbl->Insert( pNew, n ); + } + else if( *pEnd < *pTStt ) + break; + } + return bChg; +} + +bool SwDoc::DeleteRedline( const SwPaM& rRange, bool bSaveInUndo, + sal_uInt16 nDelType ) +{ + if( nsRedlineMode_t::REDLINE_IGNOREDELETE_REDLINES & eRedlineMode || + !rRange.HasMark() || *rRange.GetMark() == *rRange.GetPoint() ) + return sal_False; + + sal_Bool bChg = sal_False; + + if (bSaveInUndo && GetIDocumentUndoRedo().DoesUndo()) + { + SwUndoRedline* pUndo = new SwUndoRedline( UNDO_REDLINE, rRange ); + if( pUndo->GetRedlSaveCount() ) + { + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + else + delete pUndo; + } + + const SwPosition* pStt = rRange.Start(), + * pEnd = pStt == rRange.GetPoint() ? rRange.GetMark() + : rRange.GetPoint(); + sal_uInt16 n = 0; + GetRedline( *pStt, &n ); + for( ; n < pRedlineTbl->Count() ; ++n ) + { + SwRedline* pRedl = (*pRedlineTbl)[ n ]; + if( USHRT_MAX != nDelType && nDelType != pRedl->GetType() ) + continue; + + SwPosition* pRStt = pRedl->Start(), + * pREnd = pRStt == pRedl->GetPoint() ? pRedl->GetMark() + : pRedl->GetPoint(); + sal_Bool bDel = sal_False; + switch( ComparePosition( *pStt, *pEnd, *pRStt, *pREnd ) ) + { + case POS_EQUAL: + case POS_OUTSIDE: + bDel = sal_True; + break; + + case POS_OVERLAP_BEFORE: + if( *pEnd == *pREnd ) + bDel = sal_True; + else + { + pRedl->InvalidateRange(); + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + --n; + } + break; + + case POS_OVERLAP_BEHIND: + if( *pStt == *pRStt ) + bDel = sal_True; + else + { + pRedl->InvalidateRange(); + pRedl->SetEnd( *pStt, pREnd ); + if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + --n; + } + } + break; + + case POS_INSIDE: + { + // der muss gesplittet werden + pRedl->InvalidateRange(); + if( *pRStt == *pStt ) + { + pRedl->SetStart( *pEnd, pRStt ); + // neu einsortieren + pRedlineTbl->Remove( n ); + pRedlineTbl->Insert( pRedl ); + --n; + } + else + { + SwRedline* pCpy; + if( *pREnd != *pEnd ) + { + pCpy = new SwRedline( *pRedl ); + pCpy->SetStart( *pEnd ); + } + else + pCpy = 0; + pRedl->SetEnd( *pStt, pREnd ); + if( !pRedl->HasValidRange() ) + { + // neu einsortieren + pRedlineTbl->Remove( pRedlineTbl->GetPos( pRedl )); + pRedlineTbl->Insert( pRedl ); + --n; + } + if( pCpy ) + pRedlineTbl->Insert( pCpy ); + } + } + break; + + case POS_COLLIDE_END: + case POS_BEFORE: + n = pRedlineTbl->Count(); + break; + default: + break; + } + + if( bDel ) + { + pRedl->InvalidateRange(); + pRedlineTbl->DeleteAndDestroy( n-- ); + bChg = sal_True; + } + } + + if( bChg ) + SetModified(); + + return bChg; +} + +bool SwDoc::DeleteRedline( const SwStartNode& rNode, bool bSaveInUndo, + sal_uInt16 nDelType ) +{ + SwPaM aTemp(*rNode.EndOfSectionNode(), rNode); + return DeleteRedline(aTemp, bSaveInUndo, nDelType); +} + +sal_uInt16 SwDoc::GetRedlinePos( const SwNode& rNd, sal_uInt16 nType ) const +{ + const sal_uLong nNdIdx = rNd.GetIndex(); + for( sal_uInt16 n = 0; n < pRedlineTbl->Count() ; ++n ) + { + const SwRedline* pTmp = (*pRedlineTbl)[ n ]; + sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(), + nMk = pTmp->GetMark()->nNode.GetIndex(); + if( nPt < nMk ) { long nTmp = nMk; nMk = nPt; nPt = nTmp; } + + if( ( USHRT_MAX == nType || nType == pTmp->GetType()) && + nMk <= nNdIdx && nNdIdx <= nPt ) + return n; + + if( nMk > nNdIdx ) + break; + } + return USHRT_MAX; +} + +const SwRedline* SwDoc::GetRedline( const SwPosition& rPos, + sal_uInt16* pFndPos ) const +{ + sal_uInt16 nO = pRedlineTbl->Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + const SwRedline* pRedl = (*pRedlineTbl)[ nM ]; + const SwPosition* pStt = pRedl->Start(); + const SwPosition* pEnd = pStt == pRedl->GetPoint() + ? pRedl->GetMark() + : pRedl->GetPoint(); + if( pEnd == pStt + ? *pStt == rPos + : ( *pStt <= rPos && rPos < *pEnd ) ) + { + /* #107318# returned wrong redline ???*/ + while( nM && rPos == *(*pRedlineTbl)[ nM - 1 ]->End() && + rPos == *(*pRedlineTbl)[ nM - 1 ]->Start() ) + { + --nM; + pRedl = (*pRedlineTbl)[ nM ]; + } + + if( pFndPos ) + *pFndPos = nM; + return pRedl; + } + else if( *pEnd <= rPos ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pFndPos ) + *pFndPos = nU; + return 0; + } + else + nO = nM - 1; + } + } + if( pFndPos ) + *pFndPos = nU; + return 0; +} + +typedef sal_Bool (*Fn_AcceptReject)( SwRedlineTbl& rArr, sal_uInt16& rPos, + sal_Bool bCallDelete, + const SwPosition* pSttRng, + const SwPosition* pEndRng); + +sal_Bool lcl_AcceptRedline( SwRedlineTbl& rArr, sal_uInt16& rPos, + sal_Bool bCallDelete, + const SwPosition* pSttRng = 0, + const SwPosition* pEndRng = 0 ) +{ + sal_Bool bRet = sal_True; + SwRedline* pRedl = rArr[ rPos ]; + SwPosition *pRStt = 0, *pREnd = 0; + SwComparePosition eCmp = POS_OUTSIDE; + if( pSttRng && pEndRng ) + { + pRStt = pRedl->Start(); + pREnd = pRedl->End(); + eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd ); + } + + pRedl->InvalidateRange(); + + switch( pRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + case nsRedlineType_t::REDLINE_FORMAT: + { + sal_Bool bCheck = sal_False, bReplace = sal_False; + switch( eCmp ) + { + case POS_INSIDE: + if( *pSttRng == *pRStt ) + pRedl->SetStart( *pEndRng, pRStt ); + else + { + if( *pEndRng != *pREnd ) + { + // aufsplitten + SwRedline* pNew = new SwRedline( *pRedl ); + pNew->SetStart( *pEndRng ); + rArr.Insert( pNew ); ++rPos; + } + pRedl->SetEnd( *pSttRng, pREnd ); + bCheck = sal_True; + } + break; + + case POS_OVERLAP_BEFORE: + pRedl->SetStart( *pEndRng, pRStt ); + bReplace = sal_True; + break; + + case POS_OVERLAP_BEHIND: + pRedl->SetEnd( *pSttRng, pREnd ); + bCheck = sal_True; + break; + + case POS_OUTSIDE: + case POS_EQUAL: + rArr.DeleteAndDestroy( rPos-- ); + break; + + default: + bRet = sal_False; + } + + if( bReplace || ( bCheck && !pRedl->HasValidRange() )) + { + // neu einsortieren + rArr.Remove( rArr.GetPos( pRedl )); + rArr.Insert( pRedl ); + } + } + break; + case nsRedlineType_t::REDLINE_DELETE: + { + SwDoc& rDoc = *pRedl->GetDoc(); + const SwPosition *pDelStt = 0, *pDelEnd = 0; + sal_Bool bDelRedl = sal_False; + switch( eCmp ) + { + case POS_INSIDE: + if( bCallDelete ) + { + pDelStt = pSttRng; + pDelEnd = pEndRng; + } + break; + + case POS_OVERLAP_BEFORE: + if( bCallDelete ) + { + pDelStt = pRStt; + pDelEnd = pEndRng; + } + break; + case POS_OVERLAP_BEHIND: + if( bCallDelete ) + { + pDelStt = pREnd; + pDelEnd = pSttRng; + } + break; + + case POS_OUTSIDE: + case POS_EQUAL: + { + rArr.Remove( rPos-- ); + bDelRedl = sal_True; + if( bCallDelete ) + { + pDelStt = pRedl->Start(); + pDelEnd = pRedl->End(); + } + } + break; + default: + bRet = sal_False; + } + + if( pDelStt && pDelEnd ) + { + SwPaM aPam( *pDelStt, *pDelEnd ); + SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode(); + SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode(); + + if( bDelRedl ) + delete pRedl; + + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE))); + + if( pCSttNd && pCEndNd ) + rDoc.DeleteAndJoin( aPam ); + else + { + rDoc.DeleteRange( aPam ); + + if( pCSttNd && !pCEndNd ) + { + aPam.GetBound( sal_True ).nContent.Assign( 0, 0 ); + aPam.GetBound( sal_False ).nContent.Assign( 0, 0 ); + aPam.DeleteMark(); + rDoc.DelFullPara( aPam ); + } + } + rDoc.SetRedlineMode_intern( eOld ); + } + else if( bDelRedl ) + delete pRedl; + } + break; + + case nsRedlineType_t::REDLINE_FMTCOLL: + rArr.DeleteAndDestroy( rPos-- ); + break; + + default: + bRet = sal_False; + } + return bRet; +} + +sal_Bool lcl_RejectRedline( SwRedlineTbl& rArr, sal_uInt16& rPos, + sal_Bool bCallDelete, + const SwPosition* pSttRng = 0, + const SwPosition* pEndRng = 0 ) +{ + sal_Bool bRet = sal_True; + SwRedline* pRedl = rArr[ rPos ]; + SwPosition *pRStt = 0, *pREnd = 0; + SwComparePosition eCmp = POS_OUTSIDE; + if( pSttRng && pEndRng ) + { + pRStt = pRedl->Start(); + pREnd = pRedl->End(); + eCmp = ComparePosition( *pSttRng, *pEndRng, *pRStt, *pREnd ); + } + + pRedl->InvalidateRange(); + + switch( pRedl->GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: + { + SwDoc& rDoc = *pRedl->GetDoc(); + const SwPosition *pDelStt = 0, *pDelEnd = 0; + sal_Bool bDelRedl = sal_False; + switch( eCmp ) + { + case POS_INSIDE: + if( bCallDelete ) + { + pDelStt = pSttRng; + pDelEnd = pEndRng; + } + break; + + case POS_OVERLAP_BEFORE: + if( bCallDelete ) + { + pDelStt = pRStt; + pDelEnd = pEndRng; + } + break; + case POS_OVERLAP_BEHIND: + if( bCallDelete ) + { + pDelStt = pREnd; + pDelEnd = pSttRng; + } + break; + case POS_OUTSIDE: + case POS_EQUAL: + { + // dann den Bereich wieder loeschen + rArr.Remove( rPos-- ); + bDelRedl = sal_True; + if( bCallDelete ) + { + pDelStt = pRedl->Start(); + pDelEnd = pRedl->End(); + } + } + break; + + default: + bRet = sal_False; + } + if( pDelStt && pDelEnd ) + { + SwPaM aPam( *pDelStt, *pDelEnd ); + + SwCntntNode* pCSttNd = pDelStt->nNode.GetNode().GetCntntNode(); + SwCntntNode* pCEndNd = pDelEnd->nNode.GetNode().GetCntntNode(); + + if( bDelRedl ) + delete pRedl; + + RedlineMode_t eOld = rDoc.GetRedlineMode(); + rDoc.SetRedlineMode_intern( (RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE))); + + if( pCSttNd && pCEndNd ) + rDoc.DeleteAndJoin( aPam ); + else + { + rDoc.DeleteRange( aPam ); + + if( pCSttNd && !pCEndNd ) + { + aPam.GetBound( sal_True ).nContent.Assign( 0, 0 ); + aPam.GetBound( sal_False ).nContent.Assign( 0, 0 ); + aPam.DeleteMark(); + rDoc.DelFullPara( aPam ); + } + } + rDoc.SetRedlineMode_intern( eOld ); + } + else if( bDelRedl ) + delete pRedl; + } + break; + case nsRedlineType_t::REDLINE_DELETE: + { + SwRedline* pNew = 0; + sal_Bool bCheck = sal_False, bReplace = sal_False; + + switch( eCmp ) + { + case POS_INSIDE: + { + if( 1 < pRedl->GetStackCount() ) + { + pNew = new SwRedline( *pRedl ); + pNew->PopData(); + } + if( *pSttRng == *pRStt ) + { + pRedl->SetStart( *pEndRng, pRStt ); + bReplace = sal_True; + if( pNew ) + pNew->SetEnd( *pEndRng ); + } + else + { + if( *pEndRng != *pREnd ) + { + // aufsplitten + SwRedline* pCpy = new SwRedline( *pRedl ); + pCpy->SetStart( *pEndRng ); + rArr.Insert( pCpy ); ++rPos; + if( pNew ) + pNew->SetEnd( *pEndRng ); + } + + pRedl->SetEnd( *pSttRng, pREnd ); + bCheck = sal_True; + if( pNew ) + pNew->SetStart( *pSttRng ); + } + } + break; + + case POS_OVERLAP_BEFORE: + if( 1 < pRedl->GetStackCount() ) + { + pNew = new SwRedline( *pRedl ); + pNew->PopData(); + } + pRedl->SetStart( *pEndRng, pRStt ); + bReplace = sal_True; + if( pNew ) + pNew->SetEnd( *pEndRng ); + break; + + case POS_OVERLAP_BEHIND: + if( 1 < pRedl->GetStackCount() ) + { + pNew = new SwRedline( *pRedl ); + pNew->PopData(); + } + pRedl->SetEnd( *pSttRng, pREnd ); + bCheck = sal_True; + if( pNew ) + pNew->SetStart( *pSttRng ); + break; + + case POS_OUTSIDE: + case POS_EQUAL: + if( !pRedl->PopData() ) + // das RedlineObject loeschen reicht + rArr.DeleteAndDestroy( rPos-- ); + break; + + default: + bRet = sal_False; + } + + if( pNew ) + { + rArr.Insert( pNew ); ++rPos; + } + + if( bReplace || ( bCheck && !pRedl->HasValidRange() )) + { + // neu einsortieren + rArr.Remove( rArr.GetPos( pRedl )); + rArr.Insert( pRedl ); + } + } + break; + + case nsRedlineType_t::REDLINE_FORMAT: + case nsRedlineType_t::REDLINE_FMTCOLL: + { + if( pRedl->GetExtraData() ) + pRedl->GetExtraData()->Reject( *pRedl ); + rArr.DeleteAndDestroy( rPos-- ); + } + break; + + default: + bRet = sal_False; + } + return bRet; +} + + +const SwRedline* lcl_FindCurrRedline( const SwPosition& rSttPos, + sal_uInt16& rPos, + sal_Bool bNext = sal_True ) +{ + const SwRedline* pFnd = 0; + const SwRedlineTbl& rArr = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl(); + for( ; rPos < rArr.Count() ; ++rPos ) + { + const SwRedline* pTmp = rArr[ rPos ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + const SwPosition* pRStt = pTmp->Start(), + * pREnd = pRStt == pTmp->GetPoint() ? pTmp->GetMark() + : pTmp->GetPoint(); + if( bNext ? *pRStt <= rSttPos : *pRStt < rSttPos ) + { + if( bNext ? *pREnd > rSttPos : *pREnd >= rSttPos ) + { + pFnd = pTmp; + break; + } + } + else + break; + } + } + return pFnd; +} + +// #111827# +int lcl_AcceptRejectRedl( Fn_AcceptReject fn_AcceptReject, + SwRedlineTbl& rArr, sal_Bool bCallDelete, + const SwPaM& rPam) +{ + sal_uInt16 n = 0; + int nCount = 0; // #111827# + + const SwPosition* pStt = rPam.Start(), + * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark() + : rPam.GetPoint(); + const SwRedline* pFnd = lcl_FindCurrRedline( *pStt, n, sal_True ); + if( pFnd && // neu ein Teil davon? + ( *pFnd->Start() != *pStt || *pFnd->End() > *pEnd )) + { + // dann nur die TeilSelektion aufheben + if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd )) + nCount++; // #111827# + ++n; + } + + for( ; n < rArr.Count(); ++n ) + { + SwRedline* pTmp = rArr[ n ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + if( *pTmp->End() <= *pEnd ) + { + if( (*fn_AcceptReject)( rArr, n, bCallDelete, 0, 0 )) + nCount++; // #111827# + } + else + { + if( *pTmp->Start() < *pEnd ) + { + // dann nur in der TeilSelektion aufheben + if( (*fn_AcceptReject)( rArr, n, bCallDelete, pStt, pEnd )) + nCount++; // #111827# + } + break; + } + } + } + return nCount; // #111827# +} + +void lcl_AdjustRedlineRange( SwPaM& rPam ) +{ + // die Selektion steht nur im ContentBereich. Wenn es aber Redlines + // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die + // die Selection auf diese + SwPosition* pStt = rPam.Start(), + * pEnd = pStt == rPam.GetPoint() ? rPam.GetMark() + : rPam.GetPoint(); + SwDoc* pDoc = rPam.GetDoc(); + if( !pStt->nContent.GetIndex() && + !pDoc->GetNodes()[ pStt->nNode.GetIndex() - 1 ]->IsCntntNode() ) + { + const SwRedline* pRedl = pDoc->GetRedline( *pStt, 0 ); + if( pRedl ) + { + const SwPosition* pRStt = pRedl->Start(); + if( !pRStt->nContent.GetIndex() && pRStt->nNode.GetIndex() == + pStt->nNode.GetIndex() - 1 ) + *pStt = *pRStt; + } + } + if( pEnd->nNode.GetNode().IsCntntNode() && + !pDoc->GetNodes()[ pEnd->nNode.GetIndex() + 1 ]->IsCntntNode() && + pEnd->nContent.GetIndex() == pEnd->nNode.GetNode().GetCntntNode()->Len() ) + { + const SwRedline* pRedl = pDoc->GetRedline( *pEnd, 0 ); + if( pRedl ) + { + const SwPosition* pREnd = pRedl->End(); + if( !pREnd->nContent.GetIndex() && pREnd->nNode.GetIndex() == + pEnd->nNode.GetIndex() + 1 ) + *pEnd = *pREnd; + } + } +} + + +bool SwDoc::AcceptRedline( sal_uInt16 nPos, bool bCallDelete ) +{ + sal_Bool bRet = sal_False; + + // aufjedenfall auf sichtbar umschalten + if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) != + (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) ) + SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode)); + + SwRedline* pTmp = (*pRedlineTbl)[ nPos ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + // #111827# + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr()); + GetIDocumentUndoRedo().StartUndo(UNDO_ACCEPT_REDLINE, &aRewriter); + } + + int nLoopCnt = 2; + sal_uInt16 nSeqNo = pTmp->GetSeqNo(); + + do { + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoAcceptRedline(*pTmp) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + bRet |= lcl_AcceptRedline( *pRedlineTbl, nPos, bCallDelete ); + + if( nSeqNo ) + { + if( USHRT_MAX == nPos ) + nPos = 0; + sal_uInt16 nFndPos = 2 == nLoopCnt + ? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos ) + : pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ); + if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) && + USHRT_MAX != ( nFndPos = + pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) ) + pTmp = (*pRedlineTbl)[ nPos = nFndPos ]; + else + nLoopCnt = 0; + } + else + nLoopCnt = 0; + + } while( nLoopCnt ); + + if( bRet ) + { + CompressRedlines(); + SetModified(); + } + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().EndUndo(UNDO_END, 0); + } + } + return bRet; +} + +bool SwDoc::AcceptRedline( const SwPaM& rPam, bool bCallDelete ) +{ + // aufjedenfall auf sichtbar umschalten + if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) != + (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) ) + SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode)); + + // die Selektion steht nur im ContentBereich. Wenn es aber Redlines + // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die + // die Selection auf diese + SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() ); + lcl_AdjustRedlineRange( aPam ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().StartUndo( UNDO_ACCEPT_REDLINE, NULL ); + GetIDocumentUndoRedo().AppendUndo( new SwUndoAcceptRedline( aPam )); + } + + // #111827# + int nRet = lcl_AcceptRejectRedl( lcl_AcceptRedline, *pRedlineTbl, + bCallDelete, aPam ); + if( nRet > 0 ) + { + CompressRedlines(); + SetModified(); + } + if (GetIDocumentUndoRedo().DoesUndo()) + { + // #111827# + String aTmpStr; + + { + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet)); + aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES))); + } + + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, aTmpStr); + + GetIDocumentUndoRedo().EndUndo( UNDO_ACCEPT_REDLINE, &aRewriter ); + } + return nRet != 0; +} + +bool SwDoc::RejectRedline( sal_uInt16 nPos, bool bCallDelete ) +{ + sal_Bool bRet = sal_False; + + // aufjedenfall auf sichtbar umschalten + if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) != + (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) ) + SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode)); + + SwRedline* pTmp = (*pRedlineTbl)[ nPos ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + if (GetIDocumentUndoRedo().DoesUndo()) + { + // #111827# + SwRewriter aRewriter; + + aRewriter.AddRule(UNDO_ARG1, pTmp->GetDescr()); + GetIDocumentUndoRedo().StartUndo(UNDO_REJECT_REDLINE, &aRewriter); + } + + int nLoopCnt = 2; + sal_uInt16 nSeqNo = pTmp->GetSeqNo(); + + do { + + if (GetIDocumentUndoRedo().DoesUndo()) + { + SwUndo *const pUndo( new SwUndoRejectRedline( *pTmp ) ); + GetIDocumentUndoRedo().AppendUndo(pUndo); + } + + bRet |= lcl_RejectRedline( *pRedlineTbl, nPos, bCallDelete ); + + if( nSeqNo ) + { + if( USHRT_MAX == nPos ) + nPos = 0; + sal_uInt16 nFndPos = 2 == nLoopCnt + ? pRedlineTbl->FindNextSeqNo( nSeqNo, nPos ) + : pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ); + if( USHRT_MAX != nFndPos || ( 0 != ( --nLoopCnt ) && + USHRT_MAX != ( nFndPos = + pRedlineTbl->FindPrevSeqNo( nSeqNo, nPos ))) ) + pTmp = (*pRedlineTbl)[ nPos = nFndPos ]; + else + nLoopCnt = 0; + } + else + nLoopCnt = 0; + + } while( nLoopCnt ); + + if( bRet ) + { + CompressRedlines(); + SetModified(); + } + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().EndUndo(UNDO_END, 0); + } + } + return bRet; +} + +bool SwDoc::RejectRedline( const SwPaM& rPam, bool bCallDelete ) +{ + // aufjedenfall auf sichtbar umschalten + if( (nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE) != + (nsRedlineMode_t::REDLINE_SHOW_MASK & eRedlineMode) ) + SetRedlineMode((RedlineMode_t)(nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE | eRedlineMode)); + + // die Selektion steht nur im ContentBereich. Wenn es aber Redlines + // davor oder dahinter auf nicht ContentNodes stehen, dann erweiter die + // die Selection auf diese + SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() ); + lcl_AdjustRedlineRange( aPam ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().StartUndo( UNDO_REJECT_REDLINE, NULL ); + GetIDocumentUndoRedo().AppendUndo( new SwUndoRejectRedline(aPam) ); + } + + // #111827# + int nRet = lcl_AcceptRejectRedl( lcl_RejectRedline, *pRedlineTbl, + bCallDelete, aPam ); + if( nRet > 0 ) + { + CompressRedlines(); + SetModified(); + } + if (GetIDocumentUndoRedo().DoesUndo()) + { + // #111827# + String aTmpStr; + + { + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, String::CreateFromInt32(nRet)); + aTmpStr = aRewriter.Apply(String(SW_RES(STR_N_REDLINES))); + } + + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, aTmpStr); + + GetIDocumentUndoRedo().EndUndo( UNDO_REJECT_REDLINE, &aRewriter ); + } + + return nRet != 0; +} + +const SwRedline* SwDoc::SelNextRedline( SwPaM& rPam ) const +{ + rPam.DeleteMark(); + rPam.SetMark(); + + SwPosition& rSttPos = *rPam.GetPoint(); + SwPosition aSavePos( rSttPos ); + sal_Bool bRestart; + + // sollte die StartPos auf dem letzen gueligen ContentNode stehen, + // dann aufjedenfall das naechste Redline nehmen + sal_uInt16 n = 0; + const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_True ); + if( pFnd ) + { + const SwPosition* pEnd = pFnd->End(); + if( !pEnd->nNode.GetNode().IsCntntNode() ) + { + SwNodeIndex aTmp( pEnd->nNode ); + SwCntntNode* pCNd = GetNodes().GoPrevSection( &aTmp ); + if( !pCNd || ( aTmp == rSttPos.nNode && + pCNd->Len() == rSttPos.nContent.GetIndex() )) + pFnd = 0; + } + if( pFnd ) + rSttPos = *pFnd->End(); + } + + do { + bRestart = sal_False; + + for( ; !pFnd && n < pRedlineTbl->Count(); ++n ) + { + pFnd = (*pRedlineTbl)[ n ]; + if( pFnd->HasMark() && pFnd->IsVisible() ) + { + *rPam.GetMark() = *pFnd->Start(); + rSttPos = *pFnd->End(); + break; + } + else + pFnd = 0; + } + + if( pFnd ) + { + // alle vom gleichen Typ und Author, die hinter einander liegen + // zu einer Selektion zusammenfassen. + const SwPosition* pPrevEnd = pFnd->End(); + while( ++n < pRedlineTbl->Count() ) + { + const SwRedline* pTmp = (*pRedlineTbl)[ n ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + const SwPosition *pRStt; + if( pFnd->GetType() == pTmp->GetType() && + pFnd->GetAuthor() == pTmp->GetAuthor() && + ( *pPrevEnd == *( pRStt = pTmp->Start() ) || + IsPrevPos( *pPrevEnd, *pRStt )) ) + { + pPrevEnd = pTmp->End(); + rSttPos = *pPrevEnd; + } + else + break; + } + } + } + + if( pFnd ) + { + const SwRedline* pSaveFnd = pFnd; + + SwCntntNode* pCNd; + SwNodeIndex* pIdx = &rPam.GetMark()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetNodes().GoNextSection( pIdx )) ) + { + if( *pIdx <= rPam.GetPoint()->nNode ) + rPam.GetMark()->nContent.Assign( pCNd, 0 ); + else + pFnd = 0; + } + + if( pFnd ) + { + pIdx = &rPam.GetPoint()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) ) + { + if( *pIdx >= rPam.GetMark()->nNode ) + rPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + else + pFnd = 0; + } + } + + if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() ) + { + if( n < pRedlineTbl->Count() ) + { + bRestart = sal_True; + *rPam.GetPoint() = *pSaveFnd->End(); + } + else + { + rPam.DeleteMark(); + *rPam.GetPoint() = aSavePos; + } + pFnd = 0; + } + } + } while( bRestart ); + + return pFnd; +} + +const SwRedline* SwDoc::SelPrevRedline( SwPaM& rPam ) const +{ + rPam.DeleteMark(); + rPam.SetMark(); + + SwPosition& rSttPos = *rPam.GetPoint(); + SwPosition aSavePos( rSttPos ); + sal_Bool bRestart; + + // sollte die StartPos auf dem ersten gueligen ContentNode stehen, + // dann aufjedenfall das vorherige Redline nehmen + sal_uInt16 n = 0; + const SwRedline* pFnd = lcl_FindCurrRedline( rSttPos, n, sal_False ); + if( pFnd ) + { + const SwPosition* pStt = pFnd->Start(); + if( !pStt->nNode.GetNode().IsCntntNode() ) + { + SwNodeIndex aTmp( pStt->nNode ); + SwCntntNode* pCNd = GetNodes().GoNextSection( &aTmp ); + if( !pCNd || ( aTmp == rSttPos.nNode && + !rSttPos.nContent.GetIndex() )) + pFnd = 0; + } + if( pFnd ) + rSttPos = *pFnd->Start(); + } + + do { + bRestart = sal_False; + + while( !pFnd && 0 < n ) + { + pFnd = (*pRedlineTbl)[ --n ]; + if( pFnd->HasMark() && pFnd->IsVisible() ) + { + *rPam.GetMark() = *pFnd->End(); + rSttPos = *pFnd->Start(); + } + else + pFnd = 0; + } + + if( pFnd ) + { + // alle vom gleichen Typ und Author, die hinter einander liegen + // zu einer Selektion zusammenfassen. + const SwPosition* pNextStt = pFnd->Start(); + while( 0 < n ) + { + const SwRedline* pTmp = (*pRedlineTbl)[ --n ]; + if( pTmp->HasMark() && pTmp->IsVisible() ) + { + const SwPosition *pREnd; + if( pFnd->GetType() == pTmp->GetType() && + pFnd->GetAuthor() == pTmp->GetAuthor() && + ( *pNextStt == *( pREnd = pTmp->End() ) || + IsPrevPos( *pREnd, *pNextStt )) ) + { + pNextStt = pTmp->Start(); + rSttPos = *pNextStt; + } + else + { + ++n; + break; + } + } + } + } + + if( pFnd ) + { + const SwRedline* pSaveFnd = pFnd; + + SwCntntNode* pCNd; + SwNodeIndex* pIdx = &rPam.GetMark()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetNodes().GoPrevSection( pIdx )) ) + { + if( *pIdx >= rPam.GetPoint()->nNode ) + rPam.GetMark()->nContent.Assign( pCNd, pCNd->Len() ); + else + pFnd = 0; + } + + if( pFnd ) + { + pIdx = &rPam.GetPoint()->nNode; + if( !pIdx->GetNode().IsCntntNode() && + 0 != ( pCNd = GetNodes().GoNextSection( pIdx )) ) + { + if( *pIdx <= rPam.GetMark()->nNode ) + rPam.GetPoint()->nContent.Assign( pCNd, 0 ); + else + pFnd = 0; + } + } + + if( !pFnd || *rPam.GetMark() == *rPam.GetPoint() ) + { + if( n ) + { + bRestart = sal_True; + *rPam.GetPoint() = *pSaveFnd->Start(); + } + else + { + rPam.DeleteMark(); + *rPam.GetPoint() = aSavePos; + } + pFnd = 0; + } + } + } while( bRestart ); + + return pFnd; +} + +// Kommentar am Redline setzen +bool SwDoc::SetRedlineComment( const SwPaM& rPaM, const String& rS ) +{ + sal_Bool bRet = sal_False; + const SwPosition* pStt = rPaM.Start(), + * pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark() + : rPaM.GetPoint(); + sal_uInt16 n = 0; + if( lcl_FindCurrRedline( *pStt, n, sal_True ) ) + { + for( ; n < pRedlineTbl->Count(); ++n ) + { + bRet = sal_True; + SwRedline* pTmp = (*pRedlineTbl)[ n ]; + if( pStt != pEnd && *pTmp->Start() > *pEnd ) + break; + + pTmp->SetComment( rS ); + if( *pTmp->End() >= *pEnd ) + break; + } + } + if( bRet ) + SetModified(); + + return bRet; +} + +// legt gebenenfalls einen neuen Author an +sal_uInt16 SwDoc::GetRedlineAuthor() +{ + return SW_MOD()->GetRedlineAuthor(); +} + + // fuer die Reader usw. - neuen Author in die Tabelle eintragen +sal_uInt16 SwDoc::InsertRedlineAuthor( const String& rNew ) +{ + return SW_MOD()->InsertRedlineAuthor(rNew); +} + +void SwDoc::UpdateRedlineAttr() +{ + const SwRedlineTbl& rTbl = GetRedlineTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + SwRedline* pRedl = rTbl[ n ]; + if( pRedl->IsVisible() ) + pRedl->InvalidateRange(); + } +} + + // setze Kommentar-Text fuers Redline, das dann per AppendRedline + // hereinkommt. Wird vom Autoformat benutzt. 0-Pointer setzt den Modus + // wieder zurueck. Pointer wird nicht kopiert, muss also gueltig bleiben! +void SwDoc::SetAutoFmtRedlineComment( const String* pTxt, sal_uInt16 nSeqNo ) +{ + mbIsAutoFmtRedline = 0 != pTxt; + if( pTxt ) + { + if( !pAutoFmtRedlnComment ) + pAutoFmtRedlnComment = new String( *pTxt ); + else + *pAutoFmtRedlnComment = *pTxt; + } + else if( pAutoFmtRedlnComment ) + delete pAutoFmtRedlnComment, pAutoFmtRedlnComment = 0; + + nAutoFmtRedlnCommentNo = nSeqNo; +} + +void SwDoc::SetRedlinePassword( + /*[in]*/const uno::Sequence <sal_Int8>& rNewPassword) +{ + aRedlinePasswd = rNewPassword; + SetModified(); +} + +/* */ + +sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_Bool bIns ) +{ + sal_Bool bRet = sal_False; + if( p->HasValidRange() ) + { + bRet = _SwRedlineTbl::Insert( p ); + p->CallDisplayFunc(); + } + else if( bIns ) + bRet = InsertWithValidRanges( p ); + else + { + ASSERT( !this, "Redline: falscher Bereich" ); + } + return bRet; +} + +sal_Bool SwRedlineTbl::Insert( SwRedlinePtr& p, sal_uInt16& rP, sal_Bool bIns ) +{ + sal_Bool bRet = sal_False; + if( p->HasValidRange() ) + { + bRet = _SwRedlineTbl::Insert( p, rP ); + p->CallDisplayFunc(); + } + else if( bIns ) + bRet = InsertWithValidRanges( p, &rP ); + else + { + ASSERT( !this, "Redline: falscher Bereich" ); + } + return bRet; +} + +sal_Bool SwRedlineTbl::InsertWithValidRanges( SwRedlinePtr& p, sal_uInt16* pInsPos ) +{ + // erzeuge aus den Selektion gueltige "Teilbereiche". + sal_Bool bAnyIns = sal_False; + SwPosition* pStt = p->Start(), + * pEnd = pStt == p->GetPoint() ? p->GetMark() : p->GetPoint(); + SwPosition aNewStt( *pStt ); + SwNodes& rNds = aNewStt.nNode.GetNodes(); + SwCntntNode* pC; + + if( !aNewStt.nNode.GetNode().IsCntntNode() ) + { + pC = rNds.GoNext( &aNewStt.nNode ); + if( pC ) + aNewStt.nContent.Assign( pC, 0 ); + else + aNewStt.nNode = rNds.GetEndOfContent(); + } + + SwRedline* pNew = 0; + sal_uInt16 nInsPos; + + if( aNewStt < *pEnd ) + do { + if( !pNew ) + pNew = new SwRedline( p->GetRedlineData(), aNewStt ); + else + { + pNew->DeleteMark(); + *pNew->GetPoint() = aNewStt; + } + + pNew->SetMark(); + GoEndSection( pNew->GetPoint() ); + // i60396: If the redlines starts before a table but the table is the last member + // of the section, the GoEndSection will end inside the table. + // This will result in an incorrect redline, so we've to go back + SwNode* pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode(); + // We end in a table when pTab != 0 + if( pTab && !pNew->GetMark()->nNode.GetNode().StartOfSectionNode()->FindTableNode() ) + { // but our Mark was outside the table => Correction + do + { + // We want to be before the table + *pNew->GetPoint() = SwPosition(*pTab); + pC = GoPreviousNds( &pNew->GetPoint()->nNode, sal_False ); // here we are. + if( pC ) + pNew->GetPoint()->nContent.Assign( pC, 0 ); + pTab = pNew->GetPoint()->nNode.GetNode().StartOfSectionNode()->FindTableNode(); + }while( pTab ); // If there is another table we have to repeat our step backwards + } + + if( *pNew->GetPoint() > *pEnd ) + { + pC = 0; + if( aNewStt.nNode != pEnd->nNode ) + do { + SwNode& rCurNd = aNewStt.nNode.GetNode(); + if( rCurNd.IsStartNode() ) + { + if( rCurNd.EndOfSectionIndex() < pEnd->nNode.GetIndex() ) + aNewStt.nNode = *rCurNd.EndOfSectionNode(); + else + break; + } + else if( rCurNd.IsCntntNode() ) + pC = rCurNd.GetCntntNode(); + aNewStt.nNode++; + } while( aNewStt.nNode.GetIndex() < pEnd->nNode.GetIndex() ); + + if( aNewStt.nNode == pEnd->nNode ) + aNewStt.nContent = pEnd->nContent; + else if( pC ) + { + aNewStt.nNode = *pC; + aNewStt.nContent.Assign( pC, pC->Len() ); + } + + if( aNewStt <= *pEnd ) + *pNew->GetPoint() = aNewStt; + } + else + aNewStt = *pNew->GetPoint(); +#ifdef DEBUG + CheckPosition( pNew->GetPoint(), pNew->GetMark() ); +#endif + if( *pNew->GetPoint() != *pNew->GetMark() && + _SwRedlineTbl::Insert( pNew, nInsPos ) ) + { + pNew->CallDisplayFunc(); + bAnyIns = sal_True; + pNew = 0; + if( pInsPos && *pInsPos < nInsPos ) + *pInsPos = nInsPos; + } + + if( aNewStt >= *pEnd || + 0 == (pC = rNds.GoNext( &aNewStt.nNode )) ) + break; + + aNewStt.nContent.Assign( pC, 0 ); + + } while( aNewStt < *pEnd ); + + delete pNew; + delete p, p = 0; + return bAnyIns; +} + +void SwRedlineTbl::Remove( sal_uInt16 nP, sal_uInt16 nL ) +{ + SwDoc* pDoc = 0; + if( !nP && nL && nL == _SwRedlineTbl::Count() ) + pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc(); + + _SwRedlineTbl::Remove( nP, nL ); + + ViewShell* pSh; + if( pDoc && !pDoc->IsInDtor() && pDoc->GetRootFrm() && + 0 != ( pSh = pDoc->GetRootFrm()->GetCurrShell()) ) + pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) ); +} + +void SwRedlineTbl::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL ) +{ + SwDoc* pDoc = 0; + if( !nP && nL && nL == _SwRedlineTbl::Count() ) + pDoc = _SwRedlineTbl::GetObject( 0 )->GetDoc(); + + _SwRedlineTbl::DeleteAndDestroy( nP, nL ); + + ViewShell* pSh; + if( pDoc && !pDoc->IsInDtor() && pDoc->GetRootFrm() && + 0 != ( pSh = pDoc->GetRootFrm()->GetCurrShell()) ) + pSh->InvalidateWindows( SwRect( 0, 0, LONG_MAX, LONG_MAX ) ); +} + +// suche den naechsten oder vorherigen Redline mit dergleichen Seq.No +// Mit dem Lookahead kann die Suche eingeschraenkt werden. 0 oder +// USHRT_MAX suchen im gesamten Array. +sal_uInt16 SwRedlineTbl::FindNextOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const +{ + return nSttPos + 1 < _SwRedlineTbl::Count() + ? FindNextSeqNo( _SwRedlineTbl::GetObject( nSttPos ) + ->GetSeqNo(), nSttPos+1, nLookahead ) + : USHRT_MAX; +} + +sal_uInt16 SwRedlineTbl::FindPrevOfSeqNo( sal_uInt16 nSttPos, sal_uInt16 nLookahead ) const +{ + return nSttPos ? FindPrevSeqNo( _SwRedlineTbl::GetObject( + nSttPos )->GetSeqNo(), + nSttPos-1, nLookahead ) + : USHRT_MAX; +} + +sal_uInt16 SwRedlineTbl::FindNextSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos, + sal_uInt16 nLookahead ) const +{ + sal_uInt16 nRet = USHRT_MAX, nEnd; + if( nSeqNo && nSttPos < _SwRedlineTbl::Count() ) + { + nEnd = _SwRedlineTbl::Count(); + if( nLookahead && USHRT_MAX != nLookahead && + nSttPos + nLookahead < _SwRedlineTbl::Count() ) + nEnd = nSttPos + nLookahead; + + for( ; nSttPos < nEnd; ++nSttPos ) + if( nSeqNo == _SwRedlineTbl::GetObject( nSttPos )->GetSeqNo() ) + { + nRet = nSttPos; + break; + } + } + return nRet; +} + +sal_uInt16 SwRedlineTbl::FindPrevSeqNo( sal_uInt16 nSeqNo, sal_uInt16 nSttPos, + sal_uInt16 nLookahead ) const +{ + sal_uInt16 nRet = USHRT_MAX, nEnd; + if( nSeqNo && nSttPos < _SwRedlineTbl::Count() ) + { + nEnd = 0; + if( nLookahead && USHRT_MAX != nLookahead && nSttPos > nLookahead ) + nEnd = nSttPos - nLookahead; + + ++nSttPos; + while( nSttPos > nEnd ) + if( nSeqNo == _SwRedlineTbl::GetObject( --nSttPos )->GetSeqNo() ) + { + nRet = nSttPos; + break; + } + } + return nRet; +} + +/* */ + +SwRedlineExtraData::~SwRedlineExtraData() +{ +} + +void SwRedlineExtraData::Accept( SwPaM& ) const +{ +} + +void SwRedlineExtraData::Reject( SwPaM& ) const +{ +} + +int SwRedlineExtraData::operator == ( const SwRedlineExtraData& ) const +{ + return sal_False; +} + + +SwRedlineExtraData_FmtColl::SwRedlineExtraData_FmtColl( const String& rColl, + sal_uInt16 nPoolFmtId, + const SfxItemSet* pItemSet ) + : sFmtNm(rColl), pSet(0), nPoolId(nPoolFmtId) +{ + if( pItemSet && pItemSet->Count() ) + pSet = new SfxItemSet( *pItemSet ); +} + +SwRedlineExtraData_FmtColl::~SwRedlineExtraData_FmtColl() +{ + delete pSet; +} + +SwRedlineExtraData* SwRedlineExtraData_FmtColl::CreateNew() const +{ + return new SwRedlineExtraData_FmtColl( sFmtNm, nPoolId, pSet ); +} + +void SwRedlineExtraData_FmtColl::Reject( SwPaM& rPam ) const +{ + SwDoc* pDoc = rPam.GetDoc(); + +// was ist mit Undo ? ist das abgeschaltet ?? + SwTxtFmtColl* pColl = USHRT_MAX == nPoolId + ? pDoc->FindTxtFmtCollByName( sFmtNm ) + : pDoc->GetTxtCollFromPool( nPoolId ); + if( pColl ) + pDoc->SetTxtFmtColl( rPam, pColl, false ); + + if( pSet ) + { + rPam.SetMark(); + SwPosition& rMark = *rPam.GetMark(); + SwTxtNode* pTNd = rMark.nNode.GetNode().GetTxtNode(); + if( pTNd ) + { + rMark.nContent.Assign( pTNd, pTNd->GetTxt().Len() ); + + if( pTNd->HasSwAttrSet() ) + { + // nur die setzen, die nicht mehr vorhanden sind. Andere + // koennen jetzt veraendert drin stehen, aber die werden + // nicht angefasst. + SfxItemSet aTmp( *pSet ); + aTmp.Differentiate( *pTNd->GetpSwAttrSet() ); + pDoc->InsertItemSet( rPam, aTmp, 0 ); + } + else + { + pDoc->InsertItemSet( rPam, *pSet, 0 ); + } + } + rPam.DeleteMark(); + } +} + +int SwRedlineExtraData_FmtColl::operator == ( const SwRedlineExtraData& r) const +{ + const SwRedlineExtraData_FmtColl& rCmp = (SwRedlineExtraData_FmtColl&)r; + return sFmtNm == rCmp.sFmtNm && nPoolId == rCmp.nPoolId && + ( ( !pSet && !rCmp.pSet ) || + ( pSet && rCmp.pSet && *pSet == *rCmp.pSet ) ); +} + +void SwRedlineExtraData_FmtColl::SetItemSet( const SfxItemSet& rSet ) +{ + delete pSet; + if( rSet.Count() ) + pSet = new SfxItemSet( rSet ); + else + pSet = 0; +} + + +SwRedlineExtraData_Format::SwRedlineExtraData_Format( const SfxItemSet& rSet ) +{ + SfxItemIter aIter( rSet ); + const SfxPoolItem* pItem = aIter.FirstItem(); + while( sal_True ) + { + aWhichIds.Insert( pItem->Which(), aWhichIds.Count() ); + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } +} + +SwRedlineExtraData_Format::SwRedlineExtraData_Format( + const SwRedlineExtraData_Format& rCpy ) + : SwRedlineExtraData(), aWhichIds( (sal_uInt8)rCpy.aWhichIds.Count() ) +{ + aWhichIds.Insert( &rCpy.aWhichIds, 0 ); +} + +SwRedlineExtraData_Format::~SwRedlineExtraData_Format() +{ +} + +SwRedlineExtraData* SwRedlineExtraData_Format::CreateNew() const +{ + return new SwRedlineExtraData_Format( *this ); +} + +void SwRedlineExtraData_Format::Reject( SwPaM& rPam ) const +{ + SwDoc* pDoc = rPam.GetDoc(); + + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld & ~(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE))); + + // eigentlich muesste hier das Attribut zurueck gesetzt werden!!! + for( sal_uInt16 n = 0, nEnd = aWhichIds.Count(); n < nEnd; ++n ) + { + pDoc->InsertPoolItem( rPam, *GetDfltAttr( aWhichIds[ n ] ), + nsSetAttrMode::SETATTR_DONTEXPAND ); + } + + pDoc->SetRedlineMode_intern( eOld ); +} + +int SwRedlineExtraData_Format::operator == ( const SwRedlineExtraData& rCmp ) const +{ + int nRet = 1; + sal_uInt16 n = 0, nEnd = aWhichIds.Count(); + if( nEnd != ((SwRedlineExtraData_Format&)rCmp).aWhichIds.Count() ) + nRet = 0; + else + for( ; n < nEnd; ++n ) + if( ((SwRedlineExtraData_Format&)rCmp).aWhichIds[n] != aWhichIds[n]) + { + nRet = 0; + break; + } + return nRet; +} + +/* */ + +SwRedlineData::SwRedlineData( RedlineType_t eT, sal_uInt16 nAut ) + : pNext( 0 ), pExtraData( 0 ), eType( eT ), nAuthor( nAut ), nSeqNo( 0 ) +{ + aStamp.SetSec( 0 ); + aStamp.Set100Sec( 0 ); +} + +SwRedlineData::SwRedlineData( const SwRedlineData& rCpy, sal_Bool bCpyNext ) + : + pNext( (bCpyNext && rCpy.pNext) ? new SwRedlineData( *rCpy.pNext ) : 0 ), + pExtraData( rCpy.pExtraData ? rCpy.pExtraData->CreateNew() : 0 ), + sComment( rCpy.sComment ), aStamp( rCpy.aStamp ), eType( rCpy.eType ), + nAuthor( rCpy.nAuthor ), nSeqNo( rCpy.nSeqNo ) +{ +} + + // fuer sw3io: pNext geht in eigenen Besitz ueber! +SwRedlineData::SwRedlineData(RedlineType_t eT, sal_uInt16 nAut, const DateTime& rDT, + const String& rCmnt, SwRedlineData *pNxt, SwRedlineExtraData* pData) + : pNext(pNxt), pExtraData(pData), sComment(rCmnt), aStamp(rDT), + eType(eT), nAuthor(nAut), nSeqNo(0) +{ +} + +SwRedlineData::~SwRedlineData() +{ + delete pExtraData; + delete pNext; +} + + // ExtraData wird kopiert, der Pointer geht also NICHT in den Besitz + // des RedlineObjectes! +void SwRedlineData::SetExtraData( const SwRedlineExtraData* pData ) +{ + delete pExtraData; + + if( pData ) + pExtraData = pData->CreateNew(); + else + pExtraData = 0; +} + +// #111827# +String SwRedlineData::GetDescr() const +{ + String aResult; + + aResult += String(SW_RES(STR_REDLINE_INSERT + GetType())); + + return aResult; +} + +/* */ + +SwRedline::SwRedline(RedlineType_t eTyp, const SwPaM& rPam ) + : SwPaM( *rPam.GetMark(), *rPam.GetPoint() ), + pRedlineData( new SwRedlineData( eTyp, GetDoc()->GetRedlineAuthor() ) ), + pCntntSect( 0 ) +{ + bDelLastPara = bIsLastParaDelete = sal_False; + bIsVisible = sal_True; + if( !rPam.HasMark() ) + DeleteMark(); +} + +SwRedline::SwRedline( const SwRedlineData& rData, const SwPaM& rPam ) + : SwPaM( *rPam.GetMark(), *rPam.GetPoint() ), + pRedlineData( new SwRedlineData( rData )), + pCntntSect( 0 ) +{ + bDelLastPara = bIsLastParaDelete = sal_False; + bIsVisible = sal_True; + if( !rPam.HasMark() ) + DeleteMark(); +} + +SwRedline::SwRedline( const SwRedlineData& rData, const SwPosition& rPos ) + : SwPaM( rPos ), + pRedlineData( new SwRedlineData( rData )), + pCntntSect( 0 ) +{ + bDelLastPara = bIsLastParaDelete = sal_False; + bIsVisible = sal_True; +} + +SwRedline::SwRedline( const SwRedline& rCpy ) + : SwPaM( *rCpy.GetMark(), *rCpy.GetPoint() ), + pRedlineData( new SwRedlineData( *rCpy.pRedlineData )), + pCntntSect( 0 ) +{ + bDelLastPara = bIsLastParaDelete = sal_False; + bIsVisible = sal_True; + if( !rCpy.HasMark() ) + DeleteMark(); +} + +SwRedline::~SwRedline() +{ + if( pCntntSect ) + { + // dann den Content Bereich loeschen + if( !GetDoc()->IsInDtor() ) + GetDoc()->DeleteSection( &pCntntSect->GetNode() ); + delete pCntntSect; + } + delete pRedlineData; +} + +// liegt eine gueltige Selektion vor? +sal_Bool SwRedline::HasValidRange() const +{ + const SwNode* pPtNd = &GetPoint()->nNode.GetNode(), + * pMkNd = &GetMark()->nNode.GetNode(); + if( pPtNd->StartOfSectionNode() == pMkNd->StartOfSectionNode() && + !pPtNd->StartOfSectionNode()->IsTableNode() && + // JP 18.5.2001: Bug 87222 - invalid if points on the end of content + // DVO 25.03.2002: #96530# end-of-content only invalid if no content + // index exists + ( pPtNd != pMkNd || GetContentIdx() != NULL || + pPtNd != &pPtNd->GetNodes().GetEndOfContent() ) + ) + return sal_True; + return sal_False; +} + +void SwRedline::CallDisplayFunc( sal_uInt16 nLoop ) +{ + switch( nsRedlineMode_t::REDLINE_SHOW_MASK & GetDoc()->GetRedlineMode() ) + { + case nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE: + Show( nLoop ); + break; + case nsRedlineMode_t::REDLINE_SHOW_INSERT: + Hide( nLoop ); + break; + case nsRedlineMode_t::REDLINE_SHOW_DELETE: + ShowOriginal( nLoop ); + break; + } +} + +void SwRedline::Show( sal_uInt16 nLoop ) +{ + if( 1 <= nLoop ) + { + SwDoc* pDoc = GetDoc(); + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + switch( GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: // Inhalt wurde eingefuegt + bIsVisible = sal_True; + MoveFromSection(); + break; + + case nsRedlineType_t::REDLINE_DELETE: // Inhalt wurde geloescht + bIsVisible = sal_True; + MoveFromSection(); + break; + + case nsRedlineType_t::REDLINE_FORMAT: // Attributierung wurde angewendet + case nsRedlineType_t::REDLINE_TABLE: // TabellenStruktur wurde veraendert + InvalidateRange(); + break; + default: + break; + } + pDoc->SetRedlineMode_intern( eOld ); + } +} + +void SwRedline::Hide( sal_uInt16 nLoop ) +{ + SwDoc* pDoc = GetDoc(); + RedlineMode_t eOld = pDoc->GetRedlineMode(); + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + switch( GetType() ) + { + case nsRedlineType_t::REDLINE_INSERT: // Inhalt wurde eingefuegt + bIsVisible = sal_True; + if( 1 <= nLoop ) + MoveFromSection(); + break; + + case nsRedlineType_t::REDLINE_DELETE: // Inhalt wurde geloescht + bIsVisible = sal_False; + switch( nLoop ) + { + case 0: MoveToSection(); break; + case 1: CopyToSection(); break; + case 2: DelCopyOfSection(); break; + } + break; + + case nsRedlineType_t::REDLINE_FORMAT: // Attributierung wurde angewendet + case nsRedlineType_t::REDLINE_TABLE: // TabellenStruktur wurde veraendert + if( 1 <= nLoop ) + InvalidateRange(); + break; + default: + break; + } + pDoc->SetRedlineMode_intern( eOld ); +} + +void SwRedline::ShowOriginal( sal_uInt16 nLoop ) +{ + SwDoc* pDoc = GetDoc(); + RedlineMode_t eOld = pDoc->GetRedlineMode(); + SwRedlineData* pCur; + + pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE)); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + // bestimme den Type, ist der erste auf Stack + for( pCur = pRedlineData; pCur->pNext; ) + pCur = pCur->pNext; + + switch( pCur->eType ) + { + case nsRedlineType_t::REDLINE_INSERT: // Inhalt wurde eingefuegt + bIsVisible = sal_False; + switch( nLoop ) + { + case 0: MoveToSection(); break; + case 1: CopyToSection(); break; + case 2: DelCopyOfSection(); break; + } + break; + + case nsRedlineType_t::REDLINE_DELETE: // Inhalt wurde geloescht + bIsVisible = sal_True; + if( 1 <= nLoop ) + MoveFromSection(); + break; + + case nsRedlineType_t::REDLINE_FORMAT: // Attributierung wurde angewendet + case nsRedlineType_t::REDLINE_TABLE: // TabellenStruktur wurde veraendert + if( 1 <= nLoop ) + InvalidateRange(); + break; + default: + break; + } + pDoc->SetRedlineMode_intern( eOld ); +} + + +void SwRedline::InvalidateRange() // das Layout anstossen +{ + sal_uLong nSttNd = GetMark()->nNode.GetIndex(), + nEndNd = GetPoint()->nNode.GetIndex(); + sal_uInt16 nSttCnt = GetMark()->nContent.GetIndex(), + nEndCnt = GetPoint()->nContent.GetIndex(); + + if( nSttNd > nEndNd || ( nSttNd == nEndNd && nSttCnt > nEndCnt )) + { + sal_uLong nTmp = nSttNd; nSttNd = nEndNd; nEndNd = nTmp; + nTmp = nSttCnt; nSttCnt = nEndCnt; nEndCnt = (sal_uInt16)nTmp; + } + + SwUpdateAttr aHt( 0, 0, RES_FMT_CHG ); + SwNodes& rNds = GetDoc()->GetNodes(); + SwNode* pNd; + for( sal_uLong n = nSttNd; n <= nEndNd; ++n ) + if( ND_TEXTNODE == ( pNd = rNds[ n ] )->GetNodeType() ) + { + aHt.nStart = n == nSttNd ? nSttCnt : 0; + aHt.nEnd = n == nEndNd ? nEndCnt : ((SwTxtNode*)pNd)->GetTxt().Len(); + ((SwTxtNode*)pNd)->Modify( &aHt, &aHt ); + } +} + +/************************************************************************* + * SwRedline::CalcStartEnd() + * Calculates the start and end position of the intersection rTmp and + * text node nNdIdx + *************************************************************************/ + +void SwRedline::CalcStartEnd( sal_uLong nNdIdx, sal_uInt16& nStart, sal_uInt16& nEnd ) const +{ + const SwPosition *pRStt = Start(), *pREnd = End(); + if( pRStt->nNode < nNdIdx ) + { + if( pREnd->nNode > nNdIdx ) + { + nStart = 0; // Absatz ist komplett enthalten + nEnd = STRING_LEN; + } + else + { + ASSERT( pREnd->nNode == nNdIdx, + "SwRedlineItr::Seek: GetRedlinePos Error" ); + nStart = 0; // Absatz wird vorne ueberlappt + nEnd = pREnd->nContent.GetIndex(); + } + } + else if( pRStt->nNode == nNdIdx ) + { + nStart = pRStt->nContent.GetIndex(); + if( pREnd->nNode == nNdIdx ) + nEnd = pREnd->nContent.GetIndex(); // Innerhalb des Absatzes + else + nEnd = STRING_LEN; // Absatz wird hinten ueberlappt + } + else + { + nStart = STRING_LEN; + nEnd = STRING_LEN; + } +} + +void SwRedline::MoveToSection() +{ + if( !pCntntSect ) + { + const SwPosition* pStt = Start(), + * pEnd = pStt == GetPoint() ? GetMark() : GetPoint(); + + SwDoc* pDoc = GetDoc(); + SwPaM aPam( *pStt, *pEnd ); + SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode(); + SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode(); + + if( !pCSttNd ) + { + // damit die Indizies der anderen Redlines nicht mitverschoben + // werden, diese aufs Ende setzen (ist exclusive). + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + SwRedline* pRedl = rTbl[ n ]; + if( pRedl->GetBound(sal_True) == *pStt ) + pRedl->GetBound(sal_True) = *pEnd; + if( pRedl->GetBound(sal_False) == *pStt ) + pRedl->GetBound(sal_False) = *pEnd; + } + } + + SwStartNode* pSttNd; + SwNodes& rNds = pDoc->GetNodes(); + if( pCSttNd || pCEndNd ) + { + SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() ) + ? ((SwTxtNode*)pCSttNd)->GetTxtColl() + : (pCEndNd && pCEndNd->IsTxtNode() ) + ? ((SwTxtNode*)pCEndNd)->GetTxtColl() + : pDoc->GetTxtCollFromPool( + RES_POOLCOLL_STANDARD ); + + pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ), + SwNormalStartNode, pColl ); + SwTxtNode* pTxtNd = rNds[ pSttNd->GetIndex() + 1 ]->GetTxtNode(); + + SwNodeIndex aNdIdx( *pTxtNd ); + SwPosition aPos( aNdIdx, SwIndex( pTxtNd )); + if( pCSttNd && pCEndNd ) + pDoc->MoveAndJoin( aPam, aPos, IDocumentContentOperations::DOC_MOVEDEFAULT ); + else + { + if( pCSttNd && !pCEndNd ) + bDelLastPara = sal_True; + pDoc->MoveRange( aPam, aPos, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + } + } + else + { + pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ), + SwNormalStartNode ); + + SwPosition aPos( *pSttNd->EndOfSectionNode() ); + pDoc->MoveRange( aPam, aPos, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + } + pCntntSect = new SwNodeIndex( *pSttNd ); + + if( pStt == GetPoint() ) + Exchange(); + + DeleteMark(); + } + else + InvalidateRange(); +} + +void SwRedline::CopyToSection() +{ + if( !pCntntSect ) + { + const SwPosition* pStt = Start(), + * pEnd = pStt == GetPoint() ? GetMark() : GetPoint(); + + SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode(); + SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode(); + + SwStartNode* pSttNd; + SwDoc* pDoc = GetDoc(); + SwNodes& rNds = pDoc->GetNodes(); + + sal_Bool bSaveCopyFlag = pDoc->IsCopyIsMove(), + bSaveRdlMoveFlg = pDoc->IsRedlineMove(); + pDoc->SetCopyIsMove( sal_True ); + + // #100619# The IsRedlineMove() flag causes the behaviour of the + // SwDoc::_CopyFlyInFly method to change, which will eventually be + // called by the pDoc->Copy line below (through SwDoc::_Copy, + // SwDoc::CopyWithFlyInFly). This rather obscure bugfix was introduced + // for #63198# and #64896#, and apparently never really worked. + pDoc->SetRedlineMove( pStt->nContent == 0 ); + + if( pCSttNd ) + { + SwTxtFmtColl* pColl = (pCSttNd && pCSttNd->IsTxtNode() ) + ? ((SwTxtNode*)pCSttNd)->GetTxtColl() + : pDoc->GetTxtCollFromPool( + RES_POOLCOLL_STANDARD ); + + pSttNd = rNds.MakeTextSection( SwNodeIndex( rNds.GetEndOfRedlines() ), + SwNormalStartNode, pColl ); + + SwNodeIndex aNdIdx( *pSttNd, 1 ); + SwTxtNode* pTxtNd = aNdIdx.GetNode().GetTxtNode(); + SwPosition aPos( aNdIdx, SwIndex( pTxtNd )); + pDoc->CopyRange( *this, aPos, false ); + + // JP 08.10.98: die Vorlage vom EndNode ggfs. mit uebernehmen + // - ist im Doc::Copy nicht erwuenscht + if( pCEndNd && pCEndNd != pCSttNd ) + { + SwCntntNode* pDestNd = aPos.nNode.GetNode().GetCntntNode(); + if( pDestNd ) + { + if( pDestNd->IsTxtNode() && pCEndNd->IsTxtNode() ) + ((SwTxtNode*)pCEndNd)->CopyCollFmt( + *(SwTxtNode*)pDestNd ); + else + pDestNd->ChgFmtColl( pCEndNd->GetFmtColl() ); + } + } + } + else + { + pSttNd = rNds.MakeEmptySection( SwNodeIndex( rNds.GetEndOfRedlines() ), + SwNormalStartNode ); + + if( pCEndNd ) + { + SwPosition aPos( *pSttNd->EndOfSectionNode() ); + pDoc->CopyRange( *this, aPos, false ); + } + else + { + SwNodeIndex aInsPos( *pSttNd->EndOfSectionNode() ); + SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 ); + pDoc->CopyWithFlyInFly( aRg, 0, aInsPos ); + } + } + pCntntSect = new SwNodeIndex( *pSttNd ); + + pDoc->SetCopyIsMove( bSaveCopyFlag ); + pDoc->SetRedlineMove( bSaveRdlMoveFlg ); + } +} + +void SwRedline::DelCopyOfSection() +{ + if( pCntntSect ) + { + const SwPosition* pStt = Start(), + * pEnd = pStt == GetPoint() ? GetMark() : GetPoint(); + + SwDoc* pDoc = GetDoc(); + SwPaM aPam( *pStt, *pEnd ); + SwCntntNode* pCSttNd = pStt->nNode.GetNode().GetCntntNode(); + SwCntntNode* pCEndNd = pEnd->nNode.GetNode().GetCntntNode(); + + if( !pCSttNd ) + { + // damit die Indizies der anderen Redlines nicht mitverschoben + // werden, diese aufs Ende setzen (ist exclusive). + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + for( sal_uInt16 n = 0; n < rTbl.Count(); ++n ) + { + SwRedline* pRedl = rTbl[ n ]; + if( pRedl->GetBound(sal_True) == *pStt ) + pRedl->GetBound(sal_True) = *pEnd; + if( pRedl->GetBound(sal_False) == *pStt ) + pRedl->GetBound(sal_False) = *pEnd; + } + } + + if( pCSttNd && pCEndNd ) + { + // --> OD 2009-08-20 #i100466# + // force a <join next> on <delete and join> operation + pDoc->DeleteAndJoin( aPam, true ); + // <-- + } + else if( pCSttNd || pCEndNd ) + { + if( pCSttNd && !pCEndNd ) + bDelLastPara = sal_True; + pDoc->DeleteRange( aPam ); + + if( bDelLastPara ) + { + // #100611# To prevent dangling references to the paragraph to + // be deleted, redline that point into this paragraph should be + // moved to the new end position. Since redlines in the redline + // table are sorted and the pEnd position is an endnode (see + // bDelLastPara condition above), only redlines before the + // current ones can be affected. + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + sal_uInt16 n = rTbl.GetPos( this ); + ASSERT( n != USHRT_MAX, "How strange. We don't exist!" ); + for( sal_Bool bBreak = sal_False; !bBreak && n > 0; ) + { + --n; + bBreak = sal_True; + if( rTbl[ n ]->GetBound(sal_True) == *aPam.GetPoint() ) + { + rTbl[ n ]->GetBound(sal_True) = *pEnd; + bBreak = sal_False; + } + if( rTbl[ n ]->GetBound(sal_False) == *aPam.GetPoint() ) + { + rTbl[ n ]->GetBound(sal_False) = *pEnd; + bBreak = sal_False; + } + } + + SwPosition aEnd( *pEnd ); + *GetPoint() = *pEnd; + *GetMark() = *pEnd; + DeleteMark(); + + aPam.GetBound( sal_True ).nContent.Assign( 0, 0 ); + aPam.GetBound( sal_False ).nContent.Assign( 0, 0 ); + aPam.DeleteMark(); + pDoc->DelFullPara( aPam ); + } + } + else + { + pDoc->DeleteRange( aPam ); + } + + if( pStt == GetPoint() ) + Exchange(); + + DeleteMark(); + } +} + +void SwRedline::MoveFromSection() +{ + if( pCntntSect ) + { + SwDoc* pDoc = GetDoc(); + const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl(); + SvPtrarr aBeforeArr( 16, 16 ), aBehindArr( 16, 16 ); + sal_uInt16 nMyPos = rTbl.GetPos( this ); + ASSERT( this, "this nicht im Array?" ); + sal_Bool bBreak = sal_False; + sal_uInt16 n; + + for( n = nMyPos+1; !bBreak && n < rTbl.Count(); ++n ) + { + bBreak = sal_True; + if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() ) + { + void* pTmp = &rTbl[ n ]->GetBound(sal_True); + aBehindArr.Insert( pTmp, aBehindArr.Count()); + bBreak = sal_False; + } + if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() ) + { + void* pTmp = &rTbl[ n ]->GetBound(sal_False); + aBehindArr.Insert( pTmp, aBehindArr.Count() ); + bBreak = sal_False; + } + } + for( bBreak = sal_False, n = nMyPos; !bBreak && n ; ) + { + --n; + bBreak = sal_True; + if( rTbl[ n ]->GetBound(sal_True) == *GetPoint() ) + { + void* pTmp = &rTbl[ n ]->GetBound(sal_True); + aBeforeArr.Insert( pTmp, aBeforeArr.Count() ); + bBreak = sal_False; + } + if( rTbl[ n ]->GetBound(sal_False) == *GetPoint() ) + { + void* pTmp = &rTbl[ n ]->GetBound(sal_False); + aBeforeArr.Insert( pTmp, aBeforeArr.Count() ); + bBreak = sal_False; + } + } + + // --> OD 2009-03-17 #i95711# + const SwNode* pKeptCntntSectNode( &pCntntSect->GetNode() ); + // <-- + { + SwPaM aPam( pCntntSect->GetNode(), + *pCntntSect->GetNode().EndOfSectionNode(), 1, + ( bDelLastPara ? -2 : -1 ) ); + SwCntntNode* pCNd = aPam.GetCntntNode(); + if( pCNd ) + aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() ); + else + aPam.GetPoint()->nNode++; + + SwFmtColl* pColl = pCNd && pCNd->Len() && aPam.GetPoint()->nNode != + aPam.GetMark()->nNode + ? pCNd->GetFmtColl() : 0; + + SwNodeIndex aNdIdx( GetPoint()->nNode, -1 ); + sal_uInt16 nPos = GetPoint()->nContent.GetIndex(); + + SwPosition aPos( *GetPoint() ); + if( bDelLastPara && *aPam.GetPoint() == *aPam.GetMark() ) + { + aPos.nNode--; + + pDoc->AppendTxtNode( aPos ); + } + else + { + pDoc->MoveRange( aPam, aPos, + IDocumentContentOperations::DOC_MOVEALLFLYS ); + } + + SetMark(); + *GetPoint() = aPos; + GetMark()->nNode = aNdIdx.GetIndex() + 1; + pCNd = GetMark()->nNode.GetNode().GetCntntNode(); + GetMark()->nContent.Assign( pCNd, nPos ); + + if( bDelLastPara ) + { + GetPoint()->nNode++; + GetPoint()->nContent.Assign( pCNd = GetCntntNode(), 0 ); + bDelLastPara = sal_False; + } + else if( pColl ) + pCNd = GetCntntNode(); + + if( pColl && pCNd ) + pCNd->ChgFmtColl( pColl ); + } + // --> OD 2009-03-17 #i95771# + // Under certain conditions the previous <SwDoc::Move(..)> has already + // remove the change tracking section of this <SwRedline> instance from + // the change tracking nodes area. + // Thus, check, if <pCntntSect> still points to the change tracking section + // by comparing it with the "indexed" <SwNode> instance copied before + // perform the intrinsic move. + // Note: Such condition is e.g. a "delete" change tracking only containing a table. + if ( &pCntntSect->GetNode() == pKeptCntntSectNode ) + { + pDoc->DeleteSection( &pCntntSect->GetNode() ); + } + // <-- + delete pCntntSect, pCntntSect = 0; + + // #100611# adjustment of redline table positions must take start and + // end into account, not point and mark. + for( n = 0; n < aBeforeArr.Count(); ++n ) + *(SwPosition*)aBeforeArr[ n ] = *Start(); + for( n = 0; n < aBehindArr.Count(); ++n ) + *(SwPosition*)aBehindArr[ n ] = *End(); + } + else + InvalidateRange(); +} + +// fuers Undo +void SwRedline::SetContentIdx( const SwNodeIndex* pIdx ) +{ + if( pIdx && !pCntntSect ) + { + pCntntSect = new SwNodeIndex( *pIdx ); + bIsVisible = sal_False; + } + else if( !pIdx && pCntntSect ) + { + delete pCntntSect, pCntntSect = 0; + bIsVisible = sal_False; + } +#ifdef DBG_UTIL + else + ASSERT( !this, "das ist keine gueltige Operation" ); +#endif +} + +sal_Bool SwRedline::CanCombine( const SwRedline& rRedl ) const +{ + return IsVisible() && rRedl.IsVisible() && + pRedlineData->CanCombine( *rRedl.pRedlineData ); +} + +void SwRedline::PushData( const SwRedline& rRedl, sal_Bool bOwnAsNext ) +{ +// SwRedlineData* pNew = new SwRedlineData( rRedl.GetType(), +// rRedl.GetAuthor() ); + SwRedlineData* pNew = new SwRedlineData( *rRedl.pRedlineData, sal_False ); + if( bOwnAsNext ) + { + pNew->pNext = pRedlineData; + pRedlineData = pNew; + } + else + { + pNew->pNext = pRedlineData->pNext; + pRedlineData->pNext = pNew; + } +} + +sal_Bool SwRedline::PopData() +{ + if( !pRedlineData->pNext ) + return sal_False; + SwRedlineData* pCur = pRedlineData; + pRedlineData = pCur->pNext; + pCur->pNext = 0; + delete pCur; + return sal_True; +} + +sal_uInt16 SwRedline::GetStackCount() const +{ + sal_uInt16 nRet = 1; + for( SwRedlineData* pCur = pRedlineData; pCur->pNext; ++nRet ) + pCur = pCur->pNext; + return nRet; +} + +// -> #111827# +sal_uInt16 SwRedline::GetAuthor( sal_uInt16 nPos ) const +{ + return GetRedlineData(nPos).nAuthor; +} + +const String& SwRedline::GetAuthorString( sal_uInt16 nPos ) const +{ + return SW_MOD()->GetRedlineAuthor(GetRedlineData(nPos).nAuthor); +} + +const DateTime& SwRedline::GetTimeStamp( sal_uInt16 nPos ) const +{ + return GetRedlineData(nPos).aStamp; +} + +RedlineType_t SwRedline::GetRealType( sal_uInt16 nPos ) const +{ + return GetRedlineData(nPos).eType; +} + +const String& SwRedline::GetComment( sal_uInt16 nPos ) const +{ + return GetRedlineData(nPos).sComment; +} +// <- #111827# + +int SwRedline::operator==( const SwRedline& rCmp ) const +{ + return this == &rCmp; +} + +int SwRedline::operator<( const SwRedline& rCmp ) const +{ + sal_Bool nResult = sal_False; + + if (*Start() < *rCmp.Start()) + nResult = sal_True; + else if (*Start() == *rCmp.Start()) + if (*End() < *rCmp.End()) + nResult = sal_True; + + return nResult; +} + +// -> #111827# +const SwRedlineData & SwRedline::GetRedlineData(sal_uInt16 nPos) const +{ + SwRedlineData * pCur = pRedlineData; + + while (nPos > 0 && NULL != pCur->pNext) + { + pCur = pCur->pNext; + + nPos--; + } + + ASSERT( 0 == nPos, "Pos angabe ist zu gross" ); + + return *pCur; +} + +String SwRedline::GetDescr(sal_uInt16 nPos) +{ + String aResult; + + // get description of redline data (e.g.: "insert $1") + aResult = GetRedlineData(nPos).GetDescr(); + + SwPaM * pPaM = NULL; + bool bDeletePaM = false; + + // if this redline is visible the content is in this PaM + if (NULL == pCntntSect) + { + pPaM = this; + } + else // otherwise it is saved in pCntntSect + { + SwNodeIndex aTmpIdx( *pCntntSect->GetNode().EndOfSectionNode() ); + pPaM = new SwPaM(*pCntntSect, aTmpIdx ); + bDeletePaM = true; + } + + // replace $1 in description by description of the redlines text + String aTmpStr; + aTmpStr += String(SW_RES(STR_START_QUOTE)); + aTmpStr += ShortenString(pPaM->GetTxt(), nUndoStringLength, + String(SW_RES(STR_LDOTS))); + aTmpStr += String(SW_RES(STR_END_QUOTE)); + + SwRewriter aRewriter; + aRewriter.AddRule(UNDO_ARG1, aTmpStr); + + aResult = aRewriter.Apply(aResult); + + if (bDeletePaM) + delete pPaM; + + return aResult; +} +// <- #111827# + + +bool SwDoc::IsInRedlines(const SwNode & rNode) const +{ + SwPosition aPos(rNode); + SwNode & rEndOfRedlines = GetNodes().GetEndOfRedlines(); + SwPaM aPam(SwPosition(*rEndOfRedlines.StartOfSectionNode()), + SwPosition(rEndOfRedlines)); + + return aPam.ContainsPosition(aPos) ? true : false; +} diff --git a/sw/source/core/doc/docruby.cxx b/sw/source/core/doc/docruby.cxx new file mode 100644 index 000000000000..c8703ab6adcb --- /dev/null +++ b/sw/source/core/doc/docruby.cxx @@ -0,0 +1,361 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <string.h> // fuer strchr() + +#include <com/sun/star/i18n/UnicodeType.hdl> +#include <com/sun/star/i18n/WordType.hdl> + +#include <unotools/charclass.hxx> + +#include <hintids.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <docary.hxx> +#include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete +#include <ndtxt.hxx> +#include <txatbase.hxx> +#include <rubylist.hxx> +#include <pam.hxx> +#include <swundo.hxx> // fuer die UndoIds +#include <breakit.hxx> +#include <crsskip.hxx> + +SV_IMPL_PTRARR( SwRubyList, SwRubyListEntryPtr ) + +using namespace ::com::sun::star::i18n; + + +/* + * Members in the list: + * - String - the orig text + * - SwFmtRuby - the ruby attribut + * + * + */ +sal_uInt16 SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList, + sal_uInt16 nMode ) +{ + const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(), + *__pStartCrsr = _pStartCrsr; + sal_Bool bCheckEmpty = &rPam != _pStartCrsr; + do { + const SwPosition* pStt = _pStartCrsr->Start(), + * pEnd = pStt == _pStartCrsr->GetPoint() + ? _pStartCrsr->GetMark() + : _pStartCrsr->GetPoint(); + if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd )) + { + SwPaM aPam( *pStt ); + do { + SwRubyListEntry* pNew = new SwRubyListEntry; + if( pEnd != pStt ) + { + aPam.SetMark(); + *aPam.GetMark() = *pEnd; + } + if( _SelectNextRubyChars( aPam, *pNew, nMode )) + { + rList.Insert( pNew, rList.Count() ); + aPam.DeleteMark(); + } + else + { + delete pNew; + if( *aPam.GetPoint() < *pEnd ) + { + // goto next paragraph + aPam.DeleteMark(); + aPam.Move( fnMoveForward, fnGoNode ); + } + else + break; + } + } while( 30 > rList.Count() && *aPam.GetPoint() < *pEnd ); + } + } while( 30 > rList.Count() && + (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr ); + + return rList.Count(); +} + +sal_uInt16 SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList, + sal_uInt16 nMode ) +{ + GetIDocumentUndoRedo().StartUndo( UNDO_SETRUBYATTR, NULL ); + SvUShortsSort aDelArr; + aDelArr.Insert( RES_TXTATR_CJK_RUBY ); + + sal_uInt16 nListEntry = 0; + + const SwPaM *_pStartCrsr = (SwPaM*)rPam.GetNext(), + *__pStartCrsr = _pStartCrsr; + sal_Bool bCheckEmpty = &rPam != _pStartCrsr; + do { + const SwPosition* pStt = _pStartCrsr->Start(), + * pEnd = pStt == _pStartCrsr->GetPoint() + ? _pStartCrsr->GetMark() + : _pStartCrsr->GetPoint(); + if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd )) + { + + SwPaM aPam( *pStt ); + do { + SwRubyListEntry aCheckEntry; + if( pEnd != pStt ) + { + aPam.SetMark(); + *aPam.GetMark() = *pEnd; + } + if( _SelectNextRubyChars( aPam, aCheckEntry, nMode )) + { + const SwRubyListEntry* pEntry = rList[ nListEntry++ ]; + if( aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr() ) + { + // set/reset the attribut + if( pEntry->GetRubyAttr().GetText().Len() ) + { + InsertPoolItem( aPam, pEntry->GetRubyAttr(), 0 ); + } + else + { + ResetAttrs( aPam, sal_True, &aDelArr ); + } + } + + if( aCheckEntry.GetText() != pEntry->GetText() && + pEntry->GetText().Len() ) + { + // text is changed, so replace the original + ReplaceRange( aPam, pEntry->GetText(), false ); + } + aPam.DeleteMark(); + } + else + { + if( *aPam.GetPoint() < *pEnd ) + { + // goto next paragraph + aPam.DeleteMark(); + aPam.Move( fnMoveForward, fnGoNode ); + } + else + { + const SwRubyListEntry* pEntry = rList[ nListEntry++ ]; + + // set/reset the attribut + if( pEntry->GetRubyAttr().GetText().Len() && + pEntry->GetText().Len() ) + { + InsertString( aPam, pEntry->GetText() ); + aPam.SetMark(); + aPam.GetMark()->nContent -= pEntry->GetText().Len(); + InsertPoolItem( aPam, pEntry->GetRubyAttr(), + nsSetAttrMode::SETATTR_DONTEXPAND ); + } + else + break; + aPam.DeleteMark(); + } + } + } while( nListEntry < rList.Count() && *aPam.GetPoint() < *pEnd ); + } + } while( 30 > rList.Count() && + (_pStartCrsr=(SwPaM *)_pStartCrsr->GetNext()) != __pStartCrsr ); + + GetIDocumentUndoRedo().EndUndo( UNDO_SETRUBYATTR, NULL ); + + return nListEntry; +} + +sal_Bool SwDoc::_SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry, sal_uInt16 ) +{ + // Point must be the startposition, Mark is optional the end position + SwPosition* pPos = rPam.GetPoint(); + const SwTxtNode* pTNd = pPos->nNode.GetNode().GetTxtNode(); + const String* pTxt = &pTNd->GetTxt(); + xub_StrLen nStart = pPos->nContent.GetIndex(), nEnd = pTxt->Len(); + + sal_Bool bHasMark = rPam.HasMark(); + if( bHasMark ) + { + // in the same node? + if( rPam.GetMark()->nNode == pPos->nNode ) + { + // then use that end + xub_StrLen nTEnd = rPam.GetMark()->nContent.GetIndex(); + if( nTEnd < nEnd ) + nEnd = nTEnd; + } + rPam.DeleteMark(); + } + + // ----- search the start + // --- look where a ruby attribut starts + sal_uInt16 nHtIdx = USHRT_MAX; + const SwpHints* pHts = pTNd->GetpSwpHints(); + const SwTxtAttr* pAttr = 0; + if( pHts ) + { + const SwTxtAttr* pHt; + for( nHtIdx = 0; nHtIdx < pHts->Count(); ++nHtIdx ) + if( RES_TXTATR_CJK_RUBY == ( pHt = (*pHts)[ nHtIdx ])->Which() && + *pHt->GetAnyEnd() > nStart ) + { + if( *pHt->GetStart() < nEnd ) + { + pAttr = pHt; + if( !bHasMark && nStart > *pAttr->GetStart() ) + { + nStart = *pAttr->GetStart(); + pPos->nContent = nStart; + } + } + break; + } + } + + if( !bHasMark && nStart && ( !pAttr || nStart != *pAttr->GetStart()) ) + { + // skip to the word begin! + long nWordStt = pBreakIt->GetBreakIter()->getWordBoundary( + *pTxt, nStart, + pBreakIt->GetLocale( pTNd->GetLang( nStart )), + WordType::ANYWORD_IGNOREWHITESPACES, + sal_True ).startPos; + if( nWordStt < nStart && -1 != nWordStt ) + { + nStart = (xub_StrLen)nWordStt; + pPos->nContent = nStart; + } + } + + sal_Bool bAlphaNum = sal_False; + long nWordEnd = nEnd; + CharClass& rCC = GetAppCharClass(); + while( nStart < nEnd ) + { + if( pAttr && nStart == *pAttr->GetStart() ) + { + pPos->nContent = nStart; + if( !rPam.HasMark() ) + { + rPam.SetMark(); + pPos->nContent = *pAttr->GetAnyEnd(); + if( pPos->nContent.GetIndex() > nEnd ) + pPos->nContent = nEnd; + rEntry.SetRubyAttr( pAttr->GetRuby() ); + } + break; + } + + sal_Int32 nChType = rCC.getType( *pTxt, nStart ); + sal_Bool bIgnoreChar = sal_False, bIsAlphaNum = sal_False, bChkNxtWrd = sal_False; + switch( nChType ) + { + case UnicodeType::UPPERCASE_LETTER: + case UnicodeType::LOWERCASE_LETTER: + case UnicodeType::TITLECASE_LETTER: + case UnicodeType::DECIMAL_DIGIT_NUMBER: + bChkNxtWrd = bIsAlphaNum = sal_True; + break; + + case UnicodeType::SPACE_SEPARATOR: + case UnicodeType::CONTROL: +/*??*/ case UnicodeType::PRIVATE_USE: + case UnicodeType::START_PUNCTUATION: + case UnicodeType::END_PUNCTUATION: + bIgnoreChar = sal_True; + break; + + + case UnicodeType::OTHER_LETTER: + bChkNxtWrd = sal_True; + // no break! +// case UnicodeType::UNASSIGNED: +// case UnicodeType::MODIFIER_LETTER: +// case UnicodeType::NON_SPACING_MARK: +// case UnicodeType::ENCLOSING_MARK: +// case UnicodeType::COMBINING_SPACING_MARK: +// case UnicodeType::LETTER_NUMBER: +// case UnicodeType::OTHER_NUMBER: +// case UnicodeType::LINE_SEPARATOR: +// case UnicodeType::PARAGRAPH_SEPARATOR: +// case UnicodeType::FORMAT: +// case UnicodeType::SURROGATE: +// case UnicodeType::DASH_PUNCTUATION: +// case UnicodeType::CONNECTOR_PUNCTUATION: +///*?? */case UnicodeType::OTHER_PUNCTUATION: +//--> char '!' is to ignore! +// case UnicodeType::MATH_SYMBOL: +// case UnicodeType::CURRENCY_SYMBOL: +// case UnicodeType::MODIFIER_SYMBOL: +// case UnicodeType::OTHER_SYMBOL: +// case UnicodeType::INITIAL_PUNCTUATION: +// case UnicodeType::FINAL_PUNCTUATION: + default: + bIsAlphaNum = sal_False; + break; + } + + if( rPam.HasMark() ) + { + if( bIgnoreChar || bIsAlphaNum != bAlphaNum || nStart >= nWordEnd ) + break; + } + else if( !bIgnoreChar ) + { + rPam.SetMark(); + bAlphaNum = bIsAlphaNum; + if( bChkNxtWrd && pBreakIt->GetBreakIter().is() ) + { + // search the end of this word + nWordEnd = pBreakIt->GetBreakIter()->getWordBoundary( + *pTxt, nStart, + pBreakIt->GetLocale( pTNd->GetLang( nStart )), + WordType::ANYWORD_IGNOREWHITESPACES, + sal_True ).endPos; + if( 0 > nWordEnd || nWordEnd > nEnd || nWordEnd == nStart ) + nWordEnd = nEnd; + } + } + pTNd->GoNext( &pPos->nContent, CRSR_SKIP_CHARS ); + nStart = pPos->nContent.GetIndex(); + } + + nStart = rPam.GetMark()->nContent.GetIndex(); + rEntry.SetText( pTxt->Copy( nStart, + rPam.GetPoint()->nContent.GetIndex() - nStart )); + return rPam.HasMark(); +} + +SwRubyListEntry::~SwRubyListEntry() +{ +} diff --git a/sw/source/core/doc/docsort.cxx b/sw/source/core/doc/docsort.cxx new file mode 100644 index 000000000000..497e00b70125 --- /dev/null +++ b/sw/source/core/doc/docsort.cxx @@ -0,0 +1,1036 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <rtl/math.hxx> +#include <unotools/collatorwrapper.hxx> +#include <unotools/localedatawrapper.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/CollatorOptions.hpp> +#include <comphelper/processfactory.hxx> +#include <editeng/unolingu.hxx> +#include <docary.hxx> +#include <fmtanchr.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <node.hxx> +#include <pam.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <swundo.hxx> +#include <sortopt.hxx> +#include <docsort.hxx> +#include <UndoSort.hxx> +#include <UndoRedline.hxx> +#include <hints.hxx> +#include <tblsel.hxx> +#include <cellatr.hxx> +#include <redline.hxx> +#include <node2lay.hxx> +#include <unochart.hxx> + +#if OSL_DEBUG_LEVEL > 1 +//nur zum debugen +#include <cellatr.hxx> +#endif + +using namespace ::com::sun::star::lang; + +SwSortOptions* SwSortElement::pOptions = 0; +SwDoc* SwSortElement::pDoc = 0; +const FlatFndBox* SwSortElement::pBox = 0; +CollatorWrapper* SwSortElement::pSortCollator = 0; +Locale* SwSortElement::pLocale = 0; +String* SwSortElement::pLastAlgorithm = 0; +LocaleDataWrapper* SwSortElement::pLclData = 0; + +SV_IMPL_OP_PTRARR_SORT( SwSortElements, SwSortElementPtr ); + + +/*-------------------------------------------------------------------- + Beschreibung: Ein Sortierelement fuers Sort konstruieren + --------------------------------------------------------------------*/ + + +void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt, + FlatFndBox* pFltBx ) +{ + ASSERT( !pDoc && !pOptions && !pBox, "wer hat das Finit vergessen?" ); + pDoc = pD; + pOptions = new SwSortOptions( rOpt ); + pBox = pFltBx; + + LanguageType nLang = rOpt.nLanguage; + switch ( nLang ) + { + case LANGUAGE_NONE: + case LANGUAGE_DONTKNOW: + nLang = (LanguageType)GetAppLanguage(); + break; + } + pLocale = new Locale( SvxCreateLocale( nLang ) ); + + pSortCollator = new CollatorWrapper( + ::comphelper::getProcessServiceFactory() ); +// pSortCollator->loadCollatorAlgorithm( sAlgorithm, aLocale, +// rOpt.bIgnoreCase ? SW_COLLATOR_IGNORES : 0 ); +} + + +void SwSortElement::Finit() +{ + delete pOptions, pOptions = 0; + delete pLocale, pLocale = 0; + delete pLastAlgorithm, pLastAlgorithm = 0; + delete pSortCollator, pSortCollator = 0; + delete pLclData, pLclData = 0; + pDoc = 0; + pBox = 0; +} + + +SwSortElement::~SwSortElement() +{ +} + + +double SwSortElement::StrToDouble( const String& rStr ) const +{ + if( !pLclData ) + pLclData = new LocaleDataWrapper( + ::comphelper::getProcessServiceFactory(), *pLocale ); + + rtl_math_ConversionStatus eStatus; + sal_Int32 nEnd; + double nRet = ::rtl::math::stringToDouble( rStr, + pLclData->getNumDecimalSep().GetChar(0), + pLclData->getNumThousandSep().GetChar(0), + &eStatus, &nEnd ); + + if( rtl_math_ConversionStatus_Ok != eStatus || nEnd == 0 ) + nRet = 0.0; + return nRet; +} + +/*-------------------------------------------------------------------- + Beschreibung: Operatoren zum Vergleichen + --------------------------------------------------------------------*/ + + +sal_Bool SwSortElement::operator==(const SwSortElement& ) +{ + return sal_False; +} + +/*-------------------------------------------------------------------- + Beschreibung: Kleiner-Operator fuers sortieren + --------------------------------------------------------------------*/ + +sal_Bool SwSortElement::operator<(const SwSortElement& rCmp) +{ + + // der eigentliche Vergleich + // + for(sal_uInt16 nKey = 0; nKey < pOptions->aKeys.Count(); ++nKey) + { + const SwSortElement *pOrig, *pCmp; + + const SwSortKey* pSrtKey = pOptions->aKeys[ nKey ]; + if( pSrtKey->eSortOrder == SRT_ASCENDING ) + pOrig = this, pCmp = &rCmp; + else + pOrig = &rCmp, pCmp = this; + + if( pSrtKey->bIsNumeric ) + { + double n1 = pOrig->GetValue( nKey ); + double n2 = pCmp->GetValue( nKey ); + + if( n1 == n2 ) + continue; + + return n1 < n2; + } + else + { + if( !pLastAlgorithm || *pLastAlgorithm != pSrtKey->sSortType ) + { + if( pLastAlgorithm ) + *pLastAlgorithm = pSrtKey->sSortType; + else + pLastAlgorithm = new String( pSrtKey->sSortType ); + pSortCollator->loadCollatorAlgorithm( *pLastAlgorithm, + *pLocale, + pOptions->bIgnoreCase ? SW_COLLATOR_IGNORES : 0 ); + } + + sal_Int32 nCmp = pSortCollator->compareString( + pOrig->GetKey( nKey ), pCmp->GetKey( nKey )); + if( 0 == nCmp ) + continue; + + return -1 == nCmp; + } + } + return sal_False; +} + +double SwSortElement::GetValue( sal_uInt16 nKey ) const +{ + return StrToDouble( GetKey( nKey )); +} + +/*-------------------------------------------------------------------- + Beschreibung: SortierElemente fuer Text + --------------------------------------------------------------------*/ + + +SwSortTxtElement::SwSortTxtElement(const SwNodeIndex& rPos) + : nOrg(rPos.GetIndex()), aPos(rPos) +{ +} + + +SwSortTxtElement::~SwSortTxtElement() +{ +} + + +/*-------------------------------------------------------------------- + Beschreibung: Key ermitteln + --------------------------------------------------------------------*/ + + +String SwSortTxtElement::GetKey(sal_uInt16 nId) const +{ + SwTxtNode* pTxtNd = aPos.GetNode().GetTxtNode(); + if( !pTxtNd ) + return aEmptyStr; + + // fuer TextNodes + const String& rStr = pTxtNd->GetTxt(); + + sal_Unicode nDeli = pOptions->cDeli; + sal_uInt16 nDCount = pOptions->aKeys[nId]->nColumnId, i = 1; + xub_StrLen nStart = 0; + + // Den Delimitter suchen + while( nStart != STRING_NOTFOUND && i < nDCount) + if( STRING_NOTFOUND != ( nStart = rStr.Search( nDeli, nStart ) ) ) + { + nStart++; + i++; + } + + // naechsten Delimitter gefunden oder Ende des Strings und Kopieren + xub_StrLen nEnd = rStr.Search( nDeli, nStart+1 ); + return rStr.Copy( nStart, nEnd-nStart ); +} + + +/*-------------------------------------------------------------------- + Beschreibung: Sortier-Elemente fuer Tabellen + --------------------------------------------------------------------*/ + +SwSortBoxElement::SwSortBoxElement( sal_uInt16 nRC ) + : nRow( nRC ) +{ +} + + +SwSortBoxElement::~SwSortBoxElement() +{ +} + +/*-------------------------------------------------------------------- + Beschreibung: Schluessel zu einer Zelle ermitteln + --------------------------------------------------------------------*/ + + +String SwSortBoxElement::GetKey(sal_uInt16 nKey) const +{ + const _FndBox* pFndBox; + sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1; + + if( SRT_ROWS == pOptions->eDirection ) + pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren + else + pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren + + // Den Text rausfieseln + String aRetStr; + if( pFndBox ) + { // StartNode holen und ueberlesen + const SwTableBox* pMyBox = pFndBox->GetBox(); + ASSERT(pMyBox, "Keine atomare Box"); + + if( pMyBox->GetSttNd() ) + { + // ueber alle TextNodes der Box + const SwNode *pNd = 0, *pEndNd = pMyBox->GetSttNd()->EndOfSectionNode(); + for( sal_uLong nIdx = pMyBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx ) + if( ( pNd = pDoc->GetNodes()[ nIdx ])->IsTxtNode() ) + aRetStr += ((SwTxtNode*)pNd)->GetTxt(); + } + } + return aRetStr; +} + +double SwSortBoxElement::GetValue( sal_uInt16 nKey ) const +{ + const _FndBox* pFndBox; + sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1; + + if( SRT_ROWS == pOptions->eDirection ) + pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren + else + pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren + + double nVal; + if( pFndBox ) + { + const SwFmt *pFmt = pFndBox->GetBox()->GetFrmFmt(); + if (pFmt->GetTblBoxNumFmt().GetValue() & NUMBERFORMAT_TEXT) + nVal = SwSortElement::GetValue( nKey ); + else + nVal = pFmt->GetTblBoxValue().GetValue(); + } + else + nVal = 0; + + return nVal; +} + +/*-------------------------------------------------------------------- + Beschreibung: Text sortieren im Document + --------------------------------------------------------------------*/ + + +sal_Bool SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt) +{ + // pruefen ob Rahmen im Text + const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End(); + // Index auf den Start der Selektion + + for ( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>((*GetSpzFrmFmts())[n]); + SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + + if (pAPos && (FLY_AT_PARA == pAnchor->GetAnchorId()) && + pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) + return sal_False; + } + + // pruefe ob nur TextNodes in der Selection liegen + { + sal_uLong nStart = pStart->nNode.GetIndex(), + nEnd = pEnd->nNode.GetIndex(); + while( nStart <= nEnd ) + // Iterieren ueber einen selektierten Bereich + if( !GetNodes()[ nStart++ ]->IsTxtNode() ) + return sal_False; + } + + bool const bUndo = GetIDocumentUndoRedo().DoesUndo(); + if( bUndo ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL ); + } + + SwPaM* pRedlPam = 0; + SwUndoRedlineSort* pRedlUndo = 0; + SwUndoSort* pUndoSort = 0; + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 ); + SwCntntNode* pCNd = pRedlPam->GetCntntNode( sal_False ); + if( pCNd ) + pRedlPam->GetMark()->nContent = pCNd->Len(); + + if( IsRedlineOn() && !IsShowOriginal( GetRedlineMode() ) ) + { + if( bUndo ) + { + pRedlUndo = new SwUndoRedlineSort( *pRedlPam,rOpt ); + GetIDocumentUndoRedo().DoUndo(false); + } + // erst den Bereich kopieren, dann + SwNodeIndex aEndIdx( pEnd->nNode, 1 ); + SwNodeRange aRg( pStart->nNode, aEndIdx ); + GetNodes()._Copy( aRg, aEndIdx ); + + // Bereich neu ist von pEnd->nNode+1 bis aEndIdx + DeleteRedline( *pRedlPam, true, USHRT_MAX ); + + pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 ); + pCNd = pRedlPam->GetCntntNode( sal_False ); + pRedlPam->GetMark()->nContent.Assign( pCNd, 0 ); + + pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() ); + pCNd = pRedlPam->GetCntntNode( sal_True ); + xub_StrLen nCLen = 0; + if( !pCNd && + 0 != (pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetCntntNode())) + { + nCLen = pCNd->Len(); + pRedlPam->GetPoint()->nNode.Assign( *pCNd ); + } + pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen ); + + if( pRedlUndo ) + pRedlUndo->SetValues( rPaM ); + } + else + { + DeleteRedline( *pRedlPam, true, USHRT_MAX ); + delete pRedlPam, pRedlPam = 0; + } + } + + SwNodeIndex aStart(pStart->nNode); + SwSortElement::Init( this, rOpt ); + SwSortElements aSortArr; + while( aStart <= pEnd->nNode ) + { + // Iterieren ueber einen selektierten Bereich + SwSortTxtElement* pSE = new SwSortTxtElement( aStart ); + aSortArr.Insert(pSE); + aStart++; + } + + // Und jetzt der Akt: Verschieben von Nodes und immer schoen auf UNDO + // achten + // + sal_uLong nBeg = pStart->nNode.GetIndex(); + SwNodeRange aRg( aStart, aStart ); + + if( bUndo && !pRedlUndo ) + { + pUndoSort = new SwUndoSort(rPaM, rOpt); + GetIDocumentUndoRedo().AppendUndo(pUndoSort); + } + + GetIDocumentUndoRedo().DoUndo(false); + + for ( sal_uInt16 n = 0; n < aSortArr.Count(); ++n ) + { + SwSortTxtElement* pBox = (SwSortTxtElement*)aSortArr[n]; + aStart = nBeg + n; + aRg.aStart = pBox->aPos.GetIndex(); + aRg.aEnd = aRg.aStart.GetIndex() + 1; + + // Nodes verschieben + MoveNodeRange( aRg, aStart, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + + // Undo Verschiebungen einpflegen + if(pUndoSort) + pUndoSort->Insert(pBox->nOrg, nBeg + n); + } + // Alle Elemente aus dem SortArray loeschen + aSortArr.DeleteAndDestroy(0, aSortArr.Count()); + SwSortElement::Finit(); + + if( pRedlPam ) + { + if( pRedlUndo ) + { + pRedlUndo->SetSaveRange( *pRedlPam ); + // UGLY: temp. enable Undo + GetIDocumentUndoRedo().DoUndo(true); + GetIDocumentUndoRedo().AppendUndo( pRedlUndo ); + GetIDocumentUndoRedo().DoUndo(false); + } + + // nBeg is start of sorted range + SwNodeIndex aSttIdx( GetNodes(), nBeg ); + + // the copied range is deleted + SwRedline *const pDeleteRedline( + new SwRedline( nsRedlineType_t::REDLINE_DELETE, *pRedlPam )); + + // pRedlPam points to nodes that may be deleted (hidden) by + // AppendRedline, so adjust it beforehand to prevent ASSERT + pRedlPam->GetPoint()->nNode = aSttIdx; + SwCntntNode* pCNd = aSttIdx.GetNode().GetCntntNode(); + pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + AppendRedline(pDeleteRedline, true); + + // the sorted range is inserted + AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlPam ), true); + + if( pRedlUndo ) + { + SwNodeIndex aInsEndIdx( pRedlPam->GetMark()->nNode, -1 ); + pRedlPam->GetMark()->nNode = aInsEndIdx; + SwCntntNode *const pPrevNode = + pRedlPam->GetMark()->nNode.GetNode().GetCntntNode(); + pRedlPam->GetMark()->nContent.Assign( pPrevNode, pPrevNode->Len() ); + + pRedlUndo->SetValues( *pRedlPam ); + } + + if( pRedlUndo ) + pRedlUndo->SetOffset( aSttIdx ); + + delete pRedlPam, pRedlPam = 0; + } + GetIDocumentUndoRedo().DoUndo( bUndo ); + if( bUndo ) + { + GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL ); + } + + return sal_True; +} + +/*-------------------------------------------------------------------- + Beschreibung: Tabelle sortieren im Document + --------------------------------------------------------------------*/ + +sal_Bool SwDoc::SortTbl(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt) +{ + // uebers SwDoc fuer Undo !! + ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // Auf gehts sortieren + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );; + } + + if(!aFndBox.GetLines().Count()) + return sal_False; + + if( !IsIgnoreRedline() && GetRedlineTbl().Count() ) + DeleteRedline( *pTblNd, true, USHRT_MAX ); + + sal_uInt16 nStart = 0; + if( pTblNd->GetTable().GetRowsToRepeat() > 0 && rOpt.eDirection == SRT_ROWS ) + { + // Oberste seleketierte Zeile + _FndLines& rLines = aFndBox.GetLines(); + + while( nStart < rLines.Count() ) + { + // Verschachtelung durch Split Merge beachten, + // die oberste rausholen + SwTableLine* pLine = rLines[nStart]->GetLine(); + while ( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + if( pTblNd->GetTable().IsHeadline( *pLine ) ) + nStart++; + else + break; + } + // Alle selektierten in der HeaderLine ? -> kein Offset + if( nStart == rLines.Count() ) + nStart = 0; + } + + // umschalten auf relative Formeln + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + UpdateTblFlds( &aMsgHnt ); + + // Tabelle als flache Array-Struktur + FlatFndBox aFlatBox(this, aFndBox); + + if(!aFlatBox.IsSymmetric()) + return sal_False; + + // MIB 9.7.97: HTML-Layout loeschen + pTblNd->GetTable().SetHTMLTableLayout( 0 ); + + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + SwNode2Layout aNode2Layout( *pTblNd ); + // <-- + + // loesche die Frames der Tabelle + pTblNd->DelFrms(); + // ? TL_CHART2: ? + + SwUndoSort* pUndoSort = 0; + if (GetIDocumentUndoRedo().DoesUndo()) + { + pUndoSort = new SwUndoSort( rBoxes[0]->GetSttIdx(), + rBoxes[rBoxes.Count()-1]->GetSttIdx(), + *pTblNd, rOpt, aFlatBox.HasItemSets() ); + GetIDocumentUndoRedo().AppendUndo(pUndoSort); + } + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + + // SchluesselElemente einsortieren + sal_uInt16 nCount = (rOpt.eDirection == SRT_ROWS) ? + aFlatBox.GetRows() : aFlatBox.GetCols(); + + // SortList nach Schluessel sortieren + SwSortElement::Init( this, rOpt, &aFlatBox ); + SwSortElements aSortList; + + // wenn die HeaderLine wiederholt wird und die + // Zeilen sortiert werden 1.Zeile nicht mitsortieren + sal_uInt16 i; + + for( i = nStart; i < nCount; ++i) + { + SwSortBoxElement* pEle = new SwSortBoxElement( i ); + aSortList.Insert(pEle); + } + + // nach Sortierung verschieben + SwMovedBoxes aMovedList; + for(i=0; i < aSortList.Count(); ++i) + { + SwSortBoxElement* pBox = (SwSortBoxElement*)aSortList[i]; + if(rOpt.eDirection == SRT_ROWS) + MoveRow(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort); + else + MoveCol(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort); + } + + // Restore table frames: + // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting + // does not work if the table is inside a frame and has no prev/next. + const sal_uLong nIdx = pTblNd->GetIndex(); + aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 ); + // <-- + + // TL_CHART2: need to inform chart of probably changed cell names + UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() ); + + // Alle Elemente aus dem SortArray loeschen + aSortList.DeleteAndDestroy( 0, aSortList.Count() ); + SwSortElement::Finit(); + + SetModified(); + return sal_True; +} + +/*-------------------------------------------------------------------- + Beschreibung: Zeilenweise verschieben + --------------------------------------------------------------------*/ + + +void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT, + SwMovedBoxes& rMovedList, SwUndoSort* pUD) +{ + for( sal_uInt16 i=0; i < rBox.GetCols(); ++i ) + { // Alte Zellen-Pos bestimmen und merken + const _FndBox* pSource = rBox.GetBox(i, nS); + + // neue Zellen-Pos + const _FndBox* pTarget = rBox.GetBox(i, nT); + + const SwTableBox* pT = pTarget->GetBox(); + const SwTableBox* pS = pSource->GetBox(); + + sal_Bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX; + + // und verschieben + MoveCell(pDoc, pS, pT, bMoved, pUD); + + rMovedList.Insert(pS, rMovedList.Count() ); + + if( pS != pT ) + { + SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt(); + const SfxItemSet* pSSet = rBox.GetItemSet( i, nS ); + + if( pSSet || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt(); + pTFmt->LockModify(); + if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) + pTFmt->ResetFmtAttr( RES_VERT_ORIENT ); + + if( pSSet ) + pTFmt->SetFmtAttr( *pSSet ); + pTFmt->UnlockModify(); + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Spaltenweise verschieben + --------------------------------------------------------------------*/ + + +void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT, + SwMovedBoxes& rMovedList, SwUndoSort* pUD) +{ + for(sal_uInt16 i=0; i < rBox.GetRows(); ++i) + { // Alte Zellen-Pos bestimmen und merken + const _FndBox* pSource = rBox.GetBox(nS, i); + + // neue Zellen-Pos + const _FndBox* pTarget = rBox.GetBox(nT, i); + + // und verschieben + const SwTableBox* pT = pTarget->GetBox(); + const SwTableBox* pS = pSource->GetBox(); + + // und verschieben + sal_Bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX; + MoveCell(pDoc, pS, pT, bMoved, pUD); + + rMovedList.Insert(pS, rMovedList.Count() ); + + if( pS != pT ) + { + SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt(); + const SfxItemSet* pSSet = rBox.GetItemSet( nS, i ); + + if( pSSet || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt(); + pTFmt->LockModify(); + if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) + pTFmt->ResetFmtAttr( RES_VERT_ORIENT ); + + if( pSSet ) + pTFmt->SetFmtAttr( *pSSet ); + pTFmt->UnlockModify(); + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Eine einzelne Zelle verschieben + --------------------------------------------------------------------*/ + + +void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar, + sal_Bool bMovedBefore, SwUndoSort* pUD) +{ + ASSERT(pSource && pTar,"Fehlende Quelle oder Ziel"); + + if(pSource == pTar) + return; + + if(pUD) + pUD->Insert( pSource->GetName(), pTar->GetName() ); + + // Pam Quelle auf den ersten ContentNode setzen + SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() ); + SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart ); + + // wurde die Zelle (Source) nicht verschoben + // -> einen Leer-Node einfuegen und den Rest verschieben + // ansonsten steht der Mark auf dem ersten Content-Node + if( pNd->StartOfSectionNode() == pSource->GetSttNd() ) + pNd = pDoc->GetNodes().MakeTxtNode( aRg.aStart, + (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + aRg.aEnd = *pNd->EndOfSectionNode(); + + // Ist das Ziel leer(1 leerer Node vorhanden) + // -> diesen loeschen und move + // Ziel + SwNodeIndex aTar( *pTar->GetSttNd() ); + pNd = pDoc->GetNodes().GoNext( &aTar ); // naechsten ContentNode + sal_uLong nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex(); + + sal_Bool bDelFirst = sal_False; + if( nCount == 2 ) + { + ASSERT( pNd->GetCntntNode(), "Kein ContentNode"); + bDelFirst = !pNd->GetCntntNode()->Len() && bMovedBefore; + } + + if(!bDelFirst) + { // Es besteht schon Inhalt -> alter I n h a l t Section Down + SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() ); + pDoc->GetNodes().SectionDown( &aRgTar ); + } + + // Einfuegen der Source + SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() ); + pDoc->MoveNodeRange( aRg, aIns, + IDocumentContentOperations::DOC_MOVEDEFAULT ); + + // Falls erster Node leer -> weg damit + if(bDelFirst) + pDoc->GetNodes().Delete( aTar, 1 ); +} + +/*-------------------------------------------------------------------- + Beschreibung: Zweidimensionales Array aus FndBoxes generieren + --------------------------------------------------------------------*/ + + +FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const _FndBox& rBox) : + pDoc(pDocPtr), + rBoxRef(rBox), + pArr(0), + ppItemSets(0), + nRow(0), + nCol(0) +{ // Ist das Array symmetrisch + if((bSym = CheckLineSymmetry(rBoxRef)) != 0) + { + // Spalten/Reihen-Anzahl ermitteln + nCols = GetColCount(rBoxRef); + nRows = GetRowCount(rBoxRef); + + // lineares Array anlegen + pArr = new _FndBoxPtr[ nRows * nCols ]; + _FndBox** ppTmp = (_FndBox**)pArr; + memset( ppTmp, 0, sizeof(_FndBoxPtr) * nRows * nCols ); + + + FillFlat( rBoxRef ); + } +} + + +FlatFndBox::~FlatFndBox() +{ + _FndBox** ppTmp = (_FndBox**)pArr; + delete [] ppTmp; + + if( ppItemSets ) + delete [] ppItemSets; +} + +/*-------------------------------------------------------------------- + Beschreibung: Alle Lines einer Box muessen gleichviel Boxen haben + --------------------------------------------------------------------*/ + + +sal_Bool FlatFndBox::CheckLineSymmetry(const _FndBox& rBox) +{ + const _FndLines &rLines = rBox.GetLines(); + sal_uInt16 nBoxes(0); + + // UeberLines iterieren + for(sal_uInt16 i=0; i < rLines.Count(); ++i) + { // Die Boxen einer Line + _FndLine* pLn = rLines[i]; + const _FndBoxes& rBoxes = pLn->GetBoxes(); + + // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie + if( i && nBoxes != rBoxes.Count()) + return sal_False; + + nBoxes = rBoxes.Count(); + if( !CheckBoxSymmetry( *pLn ) ) + return sal_False; + } + return sal_True; +} + +/*-------------------------------------------------------------------- + Beschreibung: Box auf Symmetrie pruefen + Alle Boxen einer Line muessen gleichviele Lines haben + --------------------------------------------------------------------*/ + + +sal_Bool FlatFndBox::CheckBoxSymmetry(const _FndLine& rLn) +{ + const _FndBoxes &rBoxes = rLn.GetBoxes(); + sal_uInt16 nLines(0); + + // Ueber Boxes iterieren + for(sal_uInt16 i=0; i < rBoxes.Count(); ++i) + { // Die Boxen einer Line + _FndBox* pBox = rBoxes[i]; + const _FndLines& rLines = pBox->GetLines(); + + // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie + if( i && nLines != rLines.Count() ) + return sal_False; + + nLines = rLines.Count(); + if( nLines && !CheckLineSymmetry( *pBox ) ) + return sal_False; + } + return sal_True; +} + +/*-------------------------------------------------------------------- + Beschreibung: max Anzahl der Spalten (Boxes) + --------------------------------------------------------------------*/ + + +sal_uInt16 FlatFndBox::GetColCount(const _FndBox& rBox) +{ + const _FndLines& rLines = rBox.GetLines(); + // Ueber Lines iterieren + if( !rLines.Count() ) + return 1; + + sal_uInt16 nSum = 0; + for( sal_uInt16 i=0; i < rLines.Count(); ++i ) + { + // Die Boxen einer Line + sal_uInt16 nCount = 0; + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + for( sal_uInt16 j=0; j < rBoxes.Count(); ++j ) + // Rekursiv wirder ueber die Lines Iterieren + nCount += rBoxes[j]->GetLines().Count() + ? GetColCount(*rBoxes[j]) : 1; + + if( nSum < nCount ) + nSum = nCount; + } + return nSum; +} + +/*-------------------------------------------------------------------- + Beschreibung: max Anzahl der Zeilen (Lines) + --------------------------------------------------------------------*/ + + +sal_uInt16 FlatFndBox::GetRowCount(const _FndBox& rBox) +{ + const _FndLines& rLines = rBox.GetLines(); + if( !rLines.Count() ) + return 1; + + sal_uInt16 nLines = 0; + for(sal_uInt16 i=0; i < rLines.Count(); ++i) + { // Die Boxen einer Line + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + sal_uInt16 nLn = 1; + for(sal_uInt16 j=0; j < rBoxes.Count(); ++j) + if( rBoxes[j]->GetLines().Count() ) + // Rekursiv ueber die Lines Iterieren + nLn = Max(GetRowCount(*rBoxes[j]), nLn); + + nLines = nLines + nLn; + } + return nLines; +} + +/*-------------------------------------------------------------------- + Beschreibung: lineares Array aus atomaren FndBoxes erzeugen + --------------------------------------------------------------------*/ + + +void FlatFndBox::FillFlat(const _FndBox& rBox, sal_Bool bLastBox) +{ + sal_Bool bModRow = sal_False; + const _FndLines& rLines = rBox.GetLines(); + + // Ueber Lines iterieren + sal_uInt16 nOldRow = nRow; + for( sal_uInt16 i=0; i < rLines.Count(); ++i ) + { + // Die Boxen einer Line + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + sal_uInt16 nOldCol = nCol; + for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j ) + { + // Die Box pruefen ob es eine atomare Box ist + const _FndBox* pBox = rBoxes[ j ]; + + if( !pBox->GetLines().Count() ) + { + // peichern + sal_uInt16 nOff = nRow * nCols + nCol; + *(pArr + nOff) = pBox; + + // sicher die Formel/Format/Value Werte + const SwFrmFmt* pFmt = pBox->GetBox()->GetFrmFmt(); + if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + SfxItemSet* pSet = new SfxItemSet( pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pSet->Put( pFmt->GetAttrSet() ); + if( !ppItemSets ) + { + ppItemSets = new SfxItemSet*[ nRows * nCols ]; + memset( ppItemSets, 0, sizeof(SfxItemSet*) * nRows * nCols ); + } + *(ppItemSets + nOff ) = pSet; + } + + bModRow = sal_True; + } + else + { + // Rekursiv wieder ueber die Lines einer Box Iterieren + FillFlat( *pBox, ( j == rBoxes.Count()-1 ) ); + } + nCol++; + } + if(bModRow) + nRow++; + nCol = nOldCol; + } + if(!bLastBox) + nRow = nOldRow; +} + +/*-------------------------------------------------------------------- + Beschreibung: Zugriff auf eine bestimmte Zelle + --------------------------------------------------------------------*/ + + +const _FndBox* FlatFndBox::GetBox(sal_uInt16 n_Col, sal_uInt16 n_Row) const +{ + sal_uInt16 nOff = n_Row * nCols + n_Col; + const _FndBox* pTmp = *(pArr + nOff); + + ASSERT(n_Col < nCols && n_Row < nRows && pTmp, "unzulaessiger Array-Zugriff"); + return pTmp; +} + +const SfxItemSet* FlatFndBox::GetItemSet(sal_uInt16 n_Col, sal_uInt16 n_Row) const +{ + ASSERT( !ppItemSets || ( n_Col < nCols && n_Row < nRows), "unzulaessiger Array-Zugriff"); + + return ppItemSets ? *(ppItemSets + (n_Row * nCols + n_Col )) : 0; +} + + diff --git a/sw/source/core/doc/docstat.cxx b/sw/source/core/doc/docstat.cxx new file mode 100644 index 000000000000..ee44bf142de3 --- /dev/null +++ b/sw/source/core/doc/docstat.cxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <docstat.hxx> + + +/************************************************************************ + * SwDocStat::SwDocStat() + ************************************************************************/ + +SwDocStat::SwDocStat() : + nTbl(0), + nGrf(0), + nOLE(0), + nPage(1), + nPara(1), + nAllPara(1), + nWord(0), + nChar(0), + bModified(sal_True) +{} + +/************************************************************************ + * void SwDocStat::Reset() + ************************************************************************/ + +void SwDocStat::Reset() +{ + nTbl = 0; + nGrf = 0; + nOLE = 0; + nPage = 1; + nPara = 1; + nAllPara= 1; + nWord = 0; + nChar = 0; + bModified = sal_True; +} + diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx new file mode 100644 index 000000000000..79fcfc60049d --- /dev/null +++ b/sw/source/core/doc/doctxm.cxx @@ -0,0 +1,2464 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <limits.h> +#include <hintids.hxx> + +#define _SVSTDARR_STRINGSSORT +#include <svl/svstdarr.hxx> +#include <editeng/langitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <sot/clsids.hxx> +#include <docsh.hxx> +#include <ndole.hxx> +#include <txttxmrk.hxx> +#include <fmtinfmt.hxx> +#include <fmtpdsc.hxx> +#include <frmfmt.hxx> +#include <fmtfsize.hxx> +#include <frmatr.hxx> +#include <pagedesc.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <pagefrm.hxx> +#include <ndtxt.hxx> +#include <swtable.hxx> +#include <doctxm.hxx> +#include <txmsrt.hxx> +#include <rolbck.hxx> +#include <poolfmt.hxx> +#include <txtfrm.hxx> +#include <rootfrm.hxx> +#include <UndoAttribute.hxx> +#include <swundo.hxx> +#include <mdiexp.hxx> +#include <docary.hxx> +#include <charfmt.hxx> +#include <fchrfmt.hxx> +#include <fldbas.hxx> +#include <fmtfld.hxx> +#include <txtfld.hxx> +#include <expfld.hxx> +#include <chpfld.hxx> +#include <mvsave.hxx> +#include <node2lay.hxx> +#include <SwStyleNameMapper.hxx> +#include <breakit.hxx> +#include <editsh.hxx> +#include <scriptinfo.hxx> + +using namespace ::com::sun::star; + +const sal_Unicode cNumRepl = '@'; +const sal_Unicode cEndPageNum = '~'; +const sal_Char __FAR_DATA sPageDeli[] = ", "; + +SV_IMPL_PTRARR(SwTOXSortTabBases, SwTOXSortTabBasePtr) + +TYPEINIT2( SwTOXBaseSection, SwTOXBase, SwSection ); // fuers RTTI + +struct LinkStruct +{ + SwFmtINetFmt aINetFmt; + xub_StrLen nStartTextPos, nEndTextPos; + + LinkStruct( const String& rURL, xub_StrLen nStart, xub_StrLen nEnd ) + : aINetFmt( rURL, aEmptyStr), + nStartTextPos( nStart), + nEndTextPos(nEnd) {} +}; + +typedef LinkStruct* LinkStructPtr; +SV_DECL_PTRARR(LinkStructArr, LinkStructPtr, 0, 5 ) +SV_IMPL_PTRARR(LinkStructArr, LinkStructPtr) + +sal_uInt16 SwDoc::GetTOIKeys( SwTOIKeyType eTyp, SvStringsSort& rArr ) const +{ + if( rArr.Count() ) + rArr.Remove( sal_uInt16(0), rArr.Count() ); + + // dann mal ueber den Pool und alle Primary oder Secondary heraussuchen + const SwTxtTOXMark* pMark; + const SfxPoolItem* pItem; + const SwTOXType* pTOXType; + sal_uInt32 i, nMaxItems = GetAttrPool().GetItemCount2( RES_TXTATR_TOXMARK ); + for( i = 0; i < nMaxItems; ++i ) + if( 0 != (pItem = GetAttrPool().GetItem2( RES_TXTATR_TOXMARK, i ) ) && + 0!= ( pTOXType = ((SwTOXMark*)pItem)->GetTOXType()) && + TOX_INDEX == pTOXType->GetType() && + 0 != ( pMark = ((SwTOXMark*)pItem)->GetTxtTOXMark() ) && + pMark->GetpTxtNd() && + pMark->GetpTxtNd()->GetNodes().IsDocNodes() ) + { + const String* pStr; + if( TOI_PRIMARY == eTyp ) + pStr = &((SwTOXMark*)pItem)->GetPrimaryKey(); + else + pStr = &((SwTOXMark*)pItem)->GetSecondaryKey(); + + if( pStr->Len() ) + rArr.Insert( (StringPtr)pStr ); + } + + return rArr.Count(); +} + +/*-------------------------------------------------------------------- + Beschreibung: aktuelle Verzeichnismarkierungen ermitteln + --------------------------------------------------------------------*/ + + +sal_uInt16 SwDoc::GetCurTOXMark( const SwPosition& rPos, + SwTOXMarks& rArr ) const +{ + // search on Position rPos for all SwTOXMarks + SwTxtNode *const pTxtNd = rPos.nNode.GetNode().GetTxtNode(); + if( !pTxtNd || !pTxtNd->GetpSwpHints() ) + return 0; + + const SwpHints & rHts = *pTxtNd->GetpSwpHints(); + const SwTxtAttr* pHt; + xub_StrLen nSttIdx; + const xub_StrLen *pEndIdx; + + xub_StrLen nAktPos = rPos.nContent.GetIndex(); + + for( sal_uInt16 n = 0; n < rHts.Count(); ++n ) + { + if( RES_TXTATR_TOXMARK != (pHt = rHts[n])->Which() ) + continue; + if( ( nSttIdx = *pHt->GetStart() ) < nAktPos ) + { + // pruefe Ende mit ab + if( 0 == ( pEndIdx = pHt->GetEnd() ) || + *pEndIdx <= nAktPos ) + continue; // weiter suchen + } + else if( nSttIdx > nAktPos ) + // ist Start vom Hint groesser als rPos, dann abbrechen. Denn + // die Attribute sind nach Start sortiert ! + break; + + const SwTOXMark* pTMark = &pHt->GetTOXMark(); + rArr.Insert( pTMark, rArr.Count() ); + } + return rArr.Count(); +} + +/*-------------------------------------------------------------------- + Beschreibung: Marke loeschen + --------------------------------------------------------------------*/ + +void SwDoc::DeleteTOXMark( const SwTOXMark* pTOXMark ) +{ + // hole den TextNode und + const SwTxtTOXMark* pTxtTOXMark = pTOXMark->GetTxtTOXMark(); + ASSERT( pTxtTOXMark, "Kein TxtTOXMark, kann nicht geloescht werden" ); + + SwTxtNode& rTxtNd = const_cast<SwTxtNode&>(pTxtTOXMark->GetTxtNode()); + ASSERT( rTxtNd.GetpSwpHints(), "kann nicht geloescht werden" ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + // save attributes for Undo + SwUndoResetAttr* pUndo = new SwUndoResetAttr( + SwPosition( rTxtNd, SwIndex( &rTxtNd, *pTxtTOXMark->GetStart() ) ), + RES_TXTATR_TOXMARK ); + GetIDocumentUndoRedo().AppendUndo( pUndo ); + + SwRegHistory aRHst( rTxtNd, &pUndo->GetHistory() ); + rTxtNd.GetpSwpHints()->Register( &aRHst ); + } + + rTxtNd.DeleteAttribute( const_cast<SwTxtTOXMark*>(pTxtTOXMark) ); + + if (GetIDocumentUndoRedo().DoesUndo()) + { + if( rTxtNd.GetpSwpHints() ) + rTxtNd.GetpSwpHints()->DeRegister(); + } + SetModified(); +} + +/*-------------------------------------------------------------------- + Beschreibung: Traveln zwischen TOXMarks + --------------------------------------------------------------------*/ + +class CompareNodeCntnt +{ + sal_uLong nNode; + xub_StrLen nCntnt; +public: + CompareNodeCntnt( sal_uLong nNd, xub_StrLen nCnt ) + : nNode( nNd ), nCntnt( nCnt ) {} + + int operator==( const CompareNodeCntnt& rCmp ) + { return nNode == rCmp.nNode && nCntnt == rCmp.nCntnt; } + int operator!=( const CompareNodeCntnt& rCmp ) + { return nNode != rCmp.nNode || nCntnt != rCmp.nCntnt; } + int operator< ( const CompareNodeCntnt& rCmp ) + { return nNode < rCmp.nNode || + ( nNode == rCmp.nNode && nCntnt < rCmp.nCntnt); } + int operator<=( const CompareNodeCntnt& rCmp ) + { return nNode < rCmp.nNode || + ( nNode == rCmp.nNode && nCntnt <= rCmp.nCntnt); } + int operator> ( const CompareNodeCntnt& rCmp ) + { return nNode > rCmp.nNode || + ( nNode == rCmp.nNode && nCntnt > rCmp.nCntnt); } + int operator>=( const CompareNodeCntnt& rCmp ) + { return nNode > rCmp.nNode || + ( nNode == rCmp.nNode && nCntnt >= rCmp.nCntnt); } +}; + +const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark, + SwTOXSearch eDir, sal_Bool bInReadOnly ) +{ + const SwTxtTOXMark* pMark = rCurTOXMark.GetTxtTOXMark(); + ASSERT(pMark, "pMark==0 Ungueltige TxtTOXMark"); + + const SwTxtNode *pTOXSrc = pMark->GetpTxtNd(); + + CompareNodeCntnt aAbsIdx( pTOXSrc->GetIndex(), *pMark->GetStart() ); + CompareNodeCntnt aPrevPos( 0, 0 ); + CompareNodeCntnt aNextPos( ULONG_MAX, STRING_NOTFOUND ); + CompareNodeCntnt aMax( 0, 0 ); + CompareNodeCntnt aMin( ULONG_MAX, STRING_NOTFOUND ); + + const SwTOXMark* pNew = 0; + const SwTOXMark* pMax = &rCurTOXMark; + const SwTOXMark* pMin = &rCurTOXMark; + + const SwModify* pType = rCurTOXMark.GetRegisteredIn(); + SwClientIter aIter( *(SwModify*)pType ); + + const SwTOXMark* pTOXMark; + const SwCntntFrm* pCFrm; + Point aPt; + for( pTOXMark = (SwTOXMark*)aIter.First( TYPE( SwTOXMark )); pTOXMark; + pTOXMark = (SwTOXMark*)aIter.Next() ) + { + if( pTOXMark != &rCurTOXMark && + 0 != ( pMark = pTOXMark->GetTxtTOXMark()) && + 0 != ( pTOXSrc = pMark->GetpTxtNd() ) && + 0 != ( pCFrm = pTOXSrc->GetFrm( &aPt, 0, sal_False )) && + ( bInReadOnly || !pCFrm->IsProtected() )) + { + CompareNodeCntnt aAbsNew( pTOXSrc->GetIndex(), *pMark->GetStart() ); + switch( eDir ) + { + //Die untenstehenden etwas komplizierter ausgefallen Ausdruecke + //dienen dazu auch ueber Eintraege auf der selben (!) Position + //traveln zu koennen. Wenn einer Zeit hat mag er sie mal + //optimieren. + + case TOX_SAME_PRV: + if( pTOXMark->GetText() != rCurTOXMark.GetText() ) + break; + /* no break here */ + case TOX_PRV: + if ( (aAbsNew < aAbsIdx && aAbsNew > aPrevPos && + aPrevPos != aAbsIdx && aAbsNew != aAbsIdx ) || + (aAbsIdx == aAbsNew && + (sal_uLong(&rCurTOXMark) > sal_uLong(pTOXMark) && + (!pNew || + (pNew && (aPrevPos < aAbsIdx || + sal_uLong(pNew) < sal_uLong(pTOXMark)))))) || + (aPrevPos == aAbsNew && aAbsIdx != aAbsNew && + sal_uLong(pTOXMark) > sal_uLong(pNew)) ) + { + pNew = pTOXMark; + aPrevPos = aAbsNew; + if ( aAbsNew >= aMax ) + { + aMax = aAbsNew; + pMax = pTOXMark; + } + } + break; + + case TOX_SAME_NXT: + if( pTOXMark->GetText() != rCurTOXMark.GetText() ) + break; + /* no break here */ + case TOX_NXT: + if ( (aAbsNew > aAbsIdx && aAbsNew < aNextPos && + aNextPos != aAbsIdx && aAbsNew != aAbsIdx ) || + (aAbsIdx == aAbsNew && + (sal_uLong(&rCurTOXMark) < sal_uLong(pTOXMark) && + (!pNew || + (pNew && (aNextPos > aAbsIdx || + sal_uLong(pNew) > sal_uLong(pTOXMark)))))) || + (aNextPos == aAbsNew && aAbsIdx != aAbsNew && + sal_uLong(pTOXMark) < sal_uLong(pNew)) ) + { + pNew = pTOXMark; + aNextPos = aAbsNew; + if ( aAbsNew <= aMin ) + { + aMin = aAbsNew; + pMin = pTOXMark; + } + } + break; + } + } + } + + + // kein Nachfolger wurde gefunden + // Min oder Max benutzen + if(!pNew) + { + switch(eDir) + { + case TOX_PRV: + case TOX_SAME_PRV: + pNew = pMax; + break; + case TOX_NXT: + case TOX_SAME_NXT: + pNew = pMin; + break; + default: + pNew = &rCurTOXMark; + } + } + return *pNew; +} + +/* */ + +const SwTOXBaseSection* SwDoc::InsertTableOf( const SwPosition& rPos, + const SwTOXBase& rTOX, + const SfxItemSet* pSet, + sal_Bool bExpand ) +{ + GetIDocumentUndoRedo().StartUndo( UNDO_INSTOX, NULL ); + + String sSectNm( rTOX.GetTOXName() ); + sSectNm = GetUniqueTOXBaseName( *rTOX.GetTOXType(), &sSectNm ); + SwPaM aPam( rPos ); + SwSectionData aSectionData( TOX_CONTENT_SECTION, sSectNm ); + SwTOXBaseSection *const pNewSection = dynamic_cast<SwTOXBaseSection *>( + InsertSwSection( aPam, aSectionData, & rTOX, pSet, false )); + if (pNewSection) + { + SwSectionNode *const pSectNd = pNewSection->GetFmt()->GetSectionNode(); + pNewSection->SetTOXName(sSectNm); // rTOX may have had no name... + + if( bExpand ) + { + // OD 19.03.2003 #106329# - add value for 2nd parameter = true to + // indicate, that a creation of a new table of content has to be performed. + // Value of 1st parameter = default value. + pNewSection->Update( 0, true ); + } + else if( 1 == rTOX.GetTitle().Len() && IsInReading() ) + // insert title of TOX + { + // then insert the headline section + SwNodeIndex aIdx( *pSectNd, +1 ); + + SwTxtNode* pHeadNd = GetNodes().MakeTxtNode( aIdx, + GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) ); + + String sNm( pNewSection->GetTOXName() ); +// ??Resource +sNm.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "_Head" )); + + SwSectionData headerData( TOX_HEADER_SECTION, sNm ); + + SwNodeIndex aStt( *pHeadNd ); aIdx--; + SwSectionFmt* pSectFmt = MakeSectionFmt( 0 ); + GetNodes().InsertTextSection( + aStt, *pSectFmt, headerData, 0, &aIdx, true, false); + } + } + + GetIDocumentUndoRedo().EndUndo( UNDO_INSTOX, NULL ); + + return pNewSection; +} + + + +const SwTOXBaseSection* SwDoc::InsertTableOf( sal_uLong nSttNd, sal_uLong nEndNd, + const SwTOXBase& rTOX, + const SfxItemSet* pSet ) +{ + // check for recursiv TOX + SwNode* pNd = GetNodes()[ nSttNd ]; + SwSectionNode* pSectNd = pNd->FindSectionNode(); + while( pSectNd ) + { + SectionType eT = pSectNd->GetSection().GetType(); + if( TOX_HEADER_SECTION == eT || TOX_CONTENT_SECTION == eT ) + return 0; + pSectNd = pSectNd->StartOfSectionNode()->FindSectionNode(); + } + + String sSectNm( rTOX.GetTOXName() ); + sSectNm = GetUniqueTOXBaseName(*rTOX.GetTOXType(), &sSectNm); + + SwSectionData aSectionData( TOX_CONTENT_SECTION, sSectNm ); + + SwNodeIndex aStt( GetNodes(), nSttNd ), aEnd( GetNodes(), nEndNd ); + SwSectionFmt* pFmt = MakeSectionFmt( 0 ); + if(pSet) + pFmt->SetFmtAttr(*pSet); + +// --aEnd; // im InsertSection ist Ende inclusive + + SwSectionNode *const pNewSectionNode = + GetNodes().InsertTextSection(aStt, *pFmt, aSectionData, &rTOX, &aEnd); + if (!pNewSectionNode) + { + DelSectionFmt( pFmt ); + return 0; + } + + SwTOXBaseSection *const pNewSection( + dynamic_cast<SwTOXBaseSection*>(& pNewSectionNode->GetSection())); + pNewSection->SetTOXName(sSectNm); // rTOX may have had no name... + return pNewSection; +} + +/*-------------------------------------------------------------------- + Beschreibung: Aktuelles Verzeichnis ermitteln + --------------------------------------------------------------------*/ + +const SwTOXBase* SwDoc::GetCurTOX( const SwPosition& rPos ) const +{ + const SwNode& rNd = rPos.nNode.GetNode(); + const SwSectionNode* pSectNd = rNd.FindSectionNode(); + while( pSectNd ) + { + SectionType eT = pSectNd->GetSection().GetType(); + if( TOX_CONTENT_SECTION == eT ) + { + ASSERT( pSectNd->GetSection().ISA( SwTOXBaseSection ), + "keine TOXBaseSection!" ); + SwTOXBaseSection& rTOXSect = (SwTOXBaseSection&) + pSectNd->GetSection(); + return &rTOXSect; + } + pSectNd = pSectNd->StartOfSectionNode()->FindSectionNode(); + } + return 0; +} +/* -----------------01.09.99 16:01------------------- + + --------------------------------------------------*/ +const SwAttrSet& SwDoc::GetTOXBaseAttrSet(const SwTOXBase& rTOXBase) const +{ + ASSERT( rTOXBase.ISA( SwTOXBaseSection ), "no TOXBaseSection!" ); + const SwTOXBaseSection& rTOXSect = (const SwTOXBaseSection&)rTOXBase; + SwSectionFmt* pFmt = rTOXSect.GetFmt(); + ASSERT( pFmt, "invalid TOXBaseSection!" ); + return pFmt->GetAttrSet(); +} +/* -----------------02.09.99 07:48------------------- + + --------------------------------------------------*/ +const SwTOXBase* SwDoc::GetDefaultTOXBase( TOXTypes eTyp, sal_Bool bCreate ) +{ + SwTOXBase** prBase = 0; + switch(eTyp) + { + case TOX_CONTENT: prBase = &pDefTOXBases->pContBase; break; + case TOX_INDEX: prBase = &pDefTOXBases->pIdxBase; break; + case TOX_USER: prBase = &pDefTOXBases->pUserBase; break; + case TOX_TABLES: prBase = &pDefTOXBases->pTblBase; break; + case TOX_OBJECTS: prBase = &pDefTOXBases->pObjBase; break; + case TOX_ILLUSTRATIONS: prBase = &pDefTOXBases->pIllBase; break; + case TOX_AUTHORITIES: prBase = &pDefTOXBases->pAuthBase; break; + } + if(!(*prBase) && bCreate) + { + SwForm aForm(eTyp); + const SwTOXType* pType = GetTOXType(eTyp, 0); + (*prBase) = new SwTOXBase(pType, aForm, 0, pType->GetTypeName()); + } + return (*prBase); +} +/* -----------------02.09.99 08:06------------------- + + --------------------------------------------------*/ +void SwDoc::SetDefaultTOXBase(const SwTOXBase& rBase) +{ + SwTOXBase** prBase = 0; + switch(rBase.GetType()) + { + case TOX_CONTENT: prBase = &pDefTOXBases->pContBase; break; + case TOX_INDEX: prBase = &pDefTOXBases->pIdxBase; break; + case TOX_USER: prBase = &pDefTOXBases->pUserBase; break; + case TOX_TABLES: prBase = &pDefTOXBases->pTblBase; break; + case TOX_OBJECTS: prBase = &pDefTOXBases->pObjBase; break; + case TOX_ILLUSTRATIONS: prBase = &pDefTOXBases->pIllBase; break; + case TOX_AUTHORITIES: prBase = &pDefTOXBases->pAuthBase; break; + } + if(*prBase) + delete (*prBase); + (*prBase) = new SwTOXBase(rBase); +} + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnis loeschen + --------------------------------------------------------------------*/ + + +sal_Bool SwDoc::DeleteTOX( const SwTOXBase& rTOXBase, sal_Bool bDelNodes ) +{ + // its only delete the TOX, not the nodes + sal_Bool bRet = sal_False; + ASSERT( rTOXBase.ISA( SwTOXBaseSection ), "keine TOXBaseSection!" ); + + const SwTOXBaseSection& rTOXSect = (const SwTOXBaseSection&)rTOXBase; + SwSectionFmt* pFmt = rTOXSect.GetFmt(); + if( pFmt ) + { + GetIDocumentUndoRedo().StartUndo( UNDO_CLEARTOXRANGE, NULL ); + + /* Save the start node of the TOX' section. */ + SwSectionNode * pMyNode = pFmt->GetSectionNode(); + /* Save start node of section's surrounding. */ + SwNode * pStartNd = pMyNode->StartOfSectionNode(); + + /* Look for point where to move the cursors in the area to + delete to. This is done by first searching forward from the + end of the TOX' section. If no content node is found behind + the TOX one is searched before it. If this is not + successfull, too, insert new text node behind the end of + the TOX' section. The cursors from the TOX' section will be + moved to the content node found or the new text node. */ + + /* Set PaM to end of TOX' section and search following content node. + + aSearchPam will contain the point where to move the cursors + to. */ + SwPaM aSearchPam(*pMyNode->EndOfSectionNode()); + SwPosition aEndPos(*pStartNd->EndOfSectionNode()); + if (! aSearchPam.Move() /* no content node found */ + || *aSearchPam.GetPoint() >= aEndPos /* content node found + outside surrounding */ + ) + { + /* Set PaM to beginning of TOX' section and search previous + content node */ + SwPaM aTmpPam(*pMyNode); + aSearchPam = aTmpPam; + SwPosition aStartPos(*pStartNd); + + if ( ! aSearchPam.Move(fnMoveBackward) /* no content node found */ + || *aSearchPam.GetPoint() <= aStartPos /* content node + found outside + surrounding */ + ) + { + /* There is no content node in the surrounding of + TOX'. Append text node behind TOX' section. */ + + SwPosition aInsPos(*pMyNode->EndOfSectionNode()); + AppendTxtNode(aInsPos); + + SwPaM aTmpPam1(aInsPos); + aSearchPam = aTmpPam1; + } + } + + + /* PaM containing the TOX. */ + SwPaM aPam(*pMyNode->EndOfSectionNode(), *pMyNode); + + /* Move cursors contained in TOX to point determined above. */ + PaMCorrAbs(aPam, *aSearchPam.GetPoint()); + + if( !bDelNodes ) + { + SwSections aArr( 0, 4 ); + sal_uInt16 nCnt = pFmt->GetChildSections( aArr, SORTSECT_NOT, sal_False ); + for( sal_uInt16 n = 0; n < nCnt; ++n ) + { + SwSection* pSect = aArr[ n ]; + if( TOX_HEADER_SECTION == pSect->GetType() ) + { + DelSectionFmt( pSect->GetFmt(), bDelNodes ); + } + } + } + + DelSectionFmt( pFmt, bDelNodes ); + + GetIDocumentUndoRedo().EndUndo( UNDO_CLEARTOXRANGE, NULL ); + bRet = sal_True; + } + + return bRet; +} + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnistypen verwalten + --------------------------------------------------------------------*/ + +sal_uInt16 SwDoc::GetTOXTypeCount(TOXTypes eTyp) const +{ + const SwTOXTypePtr * ppTTypes = pTOXTypes->GetData(); + sal_uInt16 nCnt = 0; + for( sal_uInt16 n = 0; n < pTOXTypes->Count(); ++n, ++ppTTypes ) + if( eTyp == (*ppTTypes)->GetType() ) + ++nCnt; + return nCnt; +} +/*-------------------------------------------------------------------- + + --------------------------------------------------------------------*/ +const SwTOXType* SwDoc::GetTOXType( TOXTypes eTyp, sal_uInt16 nId ) const +{ + const SwTOXTypePtr * ppTTypes = pTOXTypes->GetData(); + sal_uInt16 nCnt = 0; + for( sal_uInt16 n = 0; n < pTOXTypes->Count(); ++n, ++ppTTypes ) + if( eTyp == (*ppTTypes)->GetType() && nCnt++ == nId ) + return (*ppTTypes); + return 0; +} + +/*-------------------------------------------------------------------- + + --------------------------------------------------------------------*/ +const SwTOXType* SwDoc::InsertTOXType( const SwTOXType& rTyp ) +{ + SwTOXType * pNew = new SwTOXType( rTyp ); + pTOXTypes->Insert( pNew, pTOXTypes->Count() ); + return pNew; +} +/*-------------------------------------------------------------------- + + --------------------------------------------------------------------*/ +String SwDoc::GetUniqueTOXBaseName( const SwTOXType& rType, + const String* pChkStr ) const +{ + sal_uInt16 n; + const SwSectionNode* pSectNd; + const SwSection* pSect; + + if(pChkStr && !pChkStr->Len()) + pChkStr = 0; + String aName( rType.GetTypeName() ); + xub_StrLen nNmLen = aName.Len(); + + sal_uInt16 nNum = 0; + sal_uInt16 nTmp = 0; + sal_uInt16 nFlagSize = ( pSectionFmtTbl->Count() / 8 ) +2; + sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ]; + memset( pSetFlags, 0, nFlagSize ); + + for( n = 0; n < pSectionFmtTbl->Count(); ++n ) + if( 0 != ( pSectNd = (*pSectionFmtTbl)[ n ]->GetSectionNode( sal_False ) )&& + TOX_CONTENT_SECTION == (pSect = &pSectNd->GetSection())->GetType()) + { + const String& rNm = pSect->GetSectionName(); + if( rNm.Match( aName ) == nNmLen ) + { + // Nummer bestimmen und das Flag setzen + nNum = (sal_uInt16)rNm.Copy( nNmLen ).ToInt32(); + if( nNum-- && nNum < pSectionFmtTbl->Count() ) + pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 )); + } + if( pChkStr && pChkStr->Equals( rNm ) ) + pChkStr = 0; + } + + if( !pChkStr ) + { + // alle Nummern entsprechend geflag, also bestimme die richtige Nummer + nNum = pSectionFmtTbl->Count(); + for( n = 0; n < nFlagSize; ++n ) + if( 0xff != ( nTmp = pSetFlags[ n ] )) + { + // also die Nummer bestimmen + nNum = n * 8; + while( nTmp & 1 ) + ++nNum, nTmp >>= 1; + break; + } + } + delete [] pSetFlags; + if( pChkStr ) + return *pChkStr; + return aName += String::CreateFromInt32( ++nNum ); +} + +/*-------------------------------------------------------------------- + + --------------------------------------------------------------------*/ +sal_Bool SwDoc::SetTOXBaseName(const SwTOXBase& rTOXBase, const String& rName) +{ + ASSERT( rTOXBase.ISA( SwTOXBaseSection ), + "keine TOXBaseSection!" ); + SwTOXBaseSection* pTOX = (SwTOXBaseSection*)&rTOXBase; + + String sTmp = GetUniqueTOXBaseName(*rTOXBase.GetTOXType(), &rName); + sal_Bool bRet = sTmp == rName; + if(bRet) + { + pTOX->SetTOXName(rName); + pTOX->SetSectionName(rName); + SetModified(); + } + return bRet; +} + +/* */ + +const SwTxtNode* lcl_FindChapterNode( const SwNode& rNd, sal_uInt8 nLvl = 0 ) +{ + const SwNode* pNd = &rNd; + if( pNd->GetNodes().GetEndOfExtras().GetIndex() > pNd->GetIndex() ) + { + // then find the "Anchor" (Body) position + Point aPt; + SwNode2Layout aNode2Layout( *pNd, pNd->GetIndex() ); + const SwFrm* pFrm = aNode2Layout.GetFrm( &aPt, 0, sal_False ); + + if( pFrm ) + { + SwPosition aPos( *pNd ); + pNd = GetBodyTxtNode( *pNd->GetDoc(), aPos, *pFrm ); + ASSERT( pNd, "wo steht der Absatz" ); + } + } + return pNd ? pNd->FindOutlineNodeOfLevel( nLvl ) : 0; +} + + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnis-Klasse + --------------------------------------------------------------------*/ + +SwTOXBaseSection::SwTOXBaseSection(SwTOXBase const& rBase, SwSectionFmt & rFmt) + : SwTOXBase( rBase ) + , SwSection( TOX_CONTENT_SECTION, aEmptyStr, rFmt ) +{ + SetProtect( rBase.IsProtected() ); + SetSectionName( GetTOXName() ); +} + + +SwTOXBaseSection::~SwTOXBaseSection() +{ +} + + +sal_Bool SwTOXBaseSection::SetPosAtStartEnd( SwPosition& rPos, sal_Bool bAtStart ) const +{ + sal_Bool bRet = sal_False; + const SwSectionNode* pSectNd = GetFmt()->GetSectionNode(); + if( pSectNd ) + { + SwCntntNode* pCNd; + xub_StrLen nC = 0; + if( bAtStart ) + { + rPos.nNode = *pSectNd; + pCNd = pSectNd->GetDoc()->GetNodes().GoNext( &rPos.nNode ); + } + else + { + rPos.nNode = *pSectNd->EndOfSectionNode(); + pCNd = pSectNd->GetDoc()->GetNodes().GoPrevious( &rPos.nNode ); + if( pCNd ) nC = pCNd->Len(); + } + rPos.nContent.Assign( pCNd, nC ); + bRet = sal_True; + } + return bRet; +} + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnisinhalt zusammensammeln + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::Update(const SfxItemSet* pAttr, + const bool _bNewTOX ) +{ + const SwSectionNode* pSectNd; + if( !SwTOXBase::GetRegisteredIn()->GetDepends() || + !GetFmt() || 0 == (pSectNd = GetFmt()->GetSectionNode() ) || + !pSectNd->GetNodes().IsDocNodes() || + IsHiddenFlag() ) + return; + + SwDoc* pDoc = (SwDoc*)pSectNd->GetDoc(); + + DBG_ASSERT(pDoc != NULL, "Where is the document?"); + + if(pAttr && pDoc && GetFmt()) + pDoc->ChgFmt(*GetFmt(), *pAttr); + + // OD 18.03.2003 #106329# - determine default page description, which + // will be used by the content nodes, if no approriate one is found. + const SwPageDesc* pDefaultPageDesc; + { + pDefaultPageDesc = + pSectNd->GetSection().GetFmt()->GetPageDesc().GetPageDesc(); + if ( !_bNewTOX && !pDefaultPageDesc ) + { + // determine page description of table-of-content + sal_uInt32 nPgDescNdIdx = pSectNd->GetIndex() + 1; + sal_uInt32* pPgDescNdIdx = &nPgDescNdIdx; + pDefaultPageDesc = pSectNd->FindPageDesc( sal_False, pPgDescNdIdx ); + if ( nPgDescNdIdx < pSectNd->GetIndex() ) + { + pDefaultPageDesc = 0; + } + } + // OD 28.04.2003 #109166# - consider end node of content section in the + // node array. + if ( !pDefaultPageDesc && + ( pSectNd->EndOfSectionNode()->GetIndex() < + (pSectNd->GetNodes().GetEndOfContent().GetIndex() - 1) ) + ) + { + // determine page description of content after table-of-content + SwNodeIndex aIdx( *(pSectNd->EndOfSectionNode()) ); + const SwCntntNode* pNdAfterTOX = pSectNd->GetNodes().GoNext( &aIdx ); + const SwAttrSet& aNdAttrSet = pNdAfterTOX->GetSwAttrSet(); + const SvxBreak eBreak = aNdAttrSet.GetBreak().GetBreak(); + if ( !( eBreak == SVX_BREAK_PAGE_BEFORE || + eBreak == SVX_BREAK_PAGE_BOTH ) + ) + { + pDefaultPageDesc = pNdAfterTOX->FindPageDesc( sal_False ); + } + } + // OD 28.04.2003 #109166# - consider start node of content section in + // the node array. + if ( !pDefaultPageDesc && + ( pSectNd->GetIndex() > + (pSectNd->GetNodes().GetEndOfContent().StartOfSectionIndex() + 1) ) + ) + { + // determine page description of content before table-of-content + SwNodeIndex aIdx( *pSectNd ); + pDefaultPageDesc = + pSectNd->GetNodes().GoPrevious( &aIdx )->FindPageDesc( sal_False ); + + } + if ( !pDefaultPageDesc ) + { + // determine default page description + pDefaultPageDesc = + &const_cast<const SwDoc *>(pDoc)->GetPageDesc( 0 ); + } + } + + pDoc->SetModified(); + + // get current Language + SwTOXInternational aIntl( GetLanguage(), + TOX_INDEX == GetTOXType()->GetType() ? + GetOptions() : 0, + GetSortAlgorithm() ); + + aSortArr.DeleteAndDestroy( 0, aSortArr.Count() ); + + // find the first layout node for this TOX, if it only find the content + // in his own chapter + const SwTxtNode* pOwnChapterNode = IsFromChapter() + ? ::lcl_FindChapterNode( *pSectNd, 0 ) + : 0; + + SwNode2Layout aN2L( *pSectNd ); + ((SwSectionNode*)pSectNd)->DelFrms(); + + // remove old content an insert one empty textnode (to hold the layout!) + SwTxtNode* pFirstEmptyNd; + { + pDoc->DeleteRedline( *pSectNd, true, USHRT_MAX ); + + SwNodeIndex aSttIdx( *pSectNd, +1 ); + SwNodeIndex aEndIdx( *pSectNd->EndOfSectionNode() ); + pFirstEmptyNd = pDoc->GetNodes().MakeTxtNode( aEndIdx, + pDoc->GetTxtCollFromPool( RES_POOLCOLL_TEXT ) ); + + { + // Task 70995 - save and restore PageDesc and Break Attributes + SwNodeIndex aNxtIdx( aSttIdx ); + const SwCntntNode* pCNd = aNxtIdx.GetNode().GetCntntNode(); + if( !pCNd ) + pCNd = pDoc->GetNodes().GoNext( &aNxtIdx ); + if( pCNd->HasSwAttrSet() ) + { + SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange ); + aBrkSet.Put( *pCNd->GetpSwAttrSet() ); + if( aBrkSet.Count() ) + pFirstEmptyNd->SetAttr( aBrkSet ); + } + } + aEndIdx--; + SwPosition aPos( aEndIdx, SwIndex( pFirstEmptyNd, 0 )); + pDoc->CorrAbs( aSttIdx, aEndIdx, aPos, sal_True ); + + // delete all before + DelFlyInRange( aSttIdx, aEndIdx ); + _DelBookmarks( aSttIdx, aEndIdx ); + + pDoc->GetNodes().Delete( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() ); + + } + + // + // insert title of TOX + if( GetTitle().Len() ) + { + // then insert the headline section + SwNodeIndex aIdx( *pSectNd, +1 ); + + SwTxtNode* pHeadNd = pDoc->GetNodes().MakeTxtNode( aIdx, + GetTxtFmtColl( FORM_TITLE ) ); + pHeadNd->InsertText( GetTitle(), SwIndex( pHeadNd ) ); + + String sNm( GetTOXName() ); +// ??Resource +sNm.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "_Head" )); + + SwSectionData headerData( TOX_HEADER_SECTION, sNm ); + + SwNodeIndex aStt( *pHeadNd ); aIdx--; + SwSectionFmt* pSectFmt = pDoc->MakeSectionFmt( 0 ); + pDoc->GetNodes().InsertTextSection( + aStt, *pSectFmt, headerData, 0, &aIdx, true, false); + } + + // jetzt waere ein prima Zeitpunkt, um die Numerierung zu updaten + pDoc->UpdateNumRule(); + + if( GetCreateType() & nsSwTOXElement::TOX_MARK ) + UpdateMarks( aIntl, pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_OUTLINELEVEL ) + UpdateOutline( pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_TEMPLATE ) + UpdateTemplate( pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_OLE || + TOX_OBJECTS == SwTOXBase::GetType()) + UpdateCntnt( nsSwTOXElement::TOX_OLE, pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_TABLE || + (TOX_TABLES == SwTOXBase::GetType() && IsFromObjectNames()) ) + UpdateTable( pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_GRAPHIC || + (TOX_ILLUSTRATIONS == SwTOXBase::GetType() && IsFromObjectNames())) + UpdateCntnt( nsSwTOXElement::TOX_GRAPHIC, pOwnChapterNode ); + + if( GetSequenceName().Len() && !IsFromObjectNames() && + (TOX_TABLES == SwTOXBase::GetType() || + TOX_ILLUSTRATIONS == SwTOXBase::GetType() ) ) + UpdateSequence( pOwnChapterNode ); + + if( GetCreateType() & nsSwTOXElement::TOX_FRAME ) + UpdateCntnt( nsSwTOXElement::TOX_FRAME, pOwnChapterNode ); + + if(TOX_AUTHORITIES == SwTOXBase::GetType()) + UpdateAuthorities( aIntl ); + + // Bei Bedarf Alphadelimitter einfuegen (nur bei Stichwoertern) + // + if( TOX_INDEX == SwTOXBase::GetType() && + ( GetOptions() & nsSwTOIOptions::TOI_ALPHA_DELIMITTER ) ) + InsertAlphaDelimitter( aIntl ); + + // sortierte Liste aller Verzeichnismarken und Verzeichnisbereiche + void* p = 0; + String* pStr = 0; + sal_uInt16 nCnt = 0, nFormMax = GetTOXForm().GetFormMax(); + SvStringsDtor aStrArr( (sal_uInt8)nFormMax ); + SvPtrarr aCollArr( (sal_uInt8)nFormMax ); + for( ; nCnt < nFormMax; ++nCnt ) + { + aCollArr.Insert( p, nCnt ); + aStrArr.Insert( pStr, nCnt ); + } + + SwNodeIndex aInsPos( *pFirstEmptyNd, 1 ); + for( nCnt = 0; nCnt < aSortArr.Count(); ++nCnt ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + // setze den Text in das Verzeichniss + sal_uInt16 nLvl = aSortArr[ nCnt ]->GetLevel(); + SwTxtFmtColl* pColl = (SwTxtFmtColl*)aCollArr[ nLvl ]; + if( !pColl ) + { + pColl = GetTxtFmtColl( nLvl ); + aCollArr.Remove( nLvl ); + p = pColl; + aCollArr.Insert( p , nLvl ); + } + + // Generierung: dynamische TabStops setzen + SwTxtNode* pTOXNd = pDoc->GetNodes().MakeTxtNode( aInsPos , pColl ); + aSortArr[ nCnt ]->pTOXNd = pTOXNd; + + // Generierung: Form auswerten und Platzhalter + // fuer die Seitennummer eintragen + //if it is a TOX_INDEX and the SwForm IsCommaSeparated() + // then a range of entries must be generated into one paragraph + sal_uInt16 nRange = 1; + if(TOX_INDEX == SwTOXBase::GetType() && + GetTOXForm().IsCommaSeparated() && + aSortArr[nCnt]->GetType() == TOX_SORT_INDEX) + { + const SwTOXMark& rMark = aSortArr[nCnt]->pTxtMark->GetTOXMark(); + const String sPrimKey = rMark.GetPrimaryKey(); + const String sSecKey = rMark.GetSecondaryKey(); + const SwTOXMark* pNextMark = 0; + while(aSortArr.Count() > (nCnt + nRange)&& + aSortArr[nCnt + nRange]->GetType() == TOX_SORT_INDEX && + 0 != (pNextMark = &(aSortArr[nCnt + nRange]->pTxtMark->GetTOXMark())) && + pNextMark->GetPrimaryKey() == sPrimKey && + pNextMark->GetSecondaryKey() == sSecKey) + nRange++; + } + // OD 18.03.2003 #106329# - pass node index of table-of-content section + // and default page description to method <GenerateText(..)>. + GenerateText( nCnt, nRange, aStrArr, pSectNd->GetIndex(), pDefaultPageDesc ); + nCnt += nRange - 1; + } + + // delete the first dummy node and remove all Cursor into the prev node + aInsPos = *pFirstEmptyNd; + { + SwPaM aCorPam( *pFirstEmptyNd ); + aCorPam.GetPoint()->nContent.Assign( pFirstEmptyNd, 0 ); + if( !aCorPam.Move( fnMoveForward ) ) + aCorPam.Move( fnMoveBackward ); + SwNodeIndex aEndIdx( aInsPos, 1 ); + pDoc->CorrAbs( aInsPos, aEndIdx, *aCorPam.GetPoint(), sal_True ); + + // Task 70995 - save and restore PageDesc and Break Attributes + if( pFirstEmptyNd->HasSwAttrSet() ) + { + if( GetTitle().Len() ) + aEndIdx = *pSectNd; + else + aEndIdx = *pFirstEmptyNd; + SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &aEndIdx ); + if( pCNd ) // Robust against defect documents, e.g. i60336 + pCNd->SetAttr( *pFirstEmptyNd->GetpSwAttrSet() ); + } + } + + // now create the new Frames + sal_uLong nIdx = pSectNd->GetIndex(); + // don't delete if index is empty + if(nIdx + 2 < pSectNd->EndOfSectionIndex()) + pDoc->GetNodes().Delete( aInsPos, 1 ); + + aN2L.RestoreUpperFrms( pDoc->GetNodes(), nIdx, nIdx + 1 ); + if(pDoc->GetRootFrm()) + SwFrm::CheckPageDescs( (SwPageFrm*)pDoc->GetRootFrm()->Lower() ); + + SetProtect( SwTOXBase::IsProtected() ); +} + +/*-------------------------------------------------------------------- + Beschreibung: AlphaDelimitter einfuegen + --------------------------------------------------------------------*/ + + +void SwTOXBaseSection::InsertAlphaDelimitter( const SwTOXInternational& rIntl ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + String sDeli, sLastDeli; + sal_uInt16 i = 0; + while( i < aSortArr.Count() ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + sal_uInt16 nLevel = aSortArr[i]->GetLevel(); + + // Alpha-Delimitter ueberlesen + if( nLevel == FORM_ALPHA_DELIMITTER ) + continue; + + String sMyString, sMyStringReading; + aSortArr[i]->GetTxt( sMyString, sMyStringReading ); + + sDeli = rIntl.GetIndexKey( sMyString, sMyStringReading, + aSortArr[i]->GetLocale() ); + + // Delimitter schon vorhanden ?? + if( sDeli.Len() && sLastDeli != sDeli ) + { + // alle kleiner Blank wollen wir nicht haben -> sind Sonderzeichen + if( ' ' <= sDeli.GetChar( 0 ) ) + { + SwTOXCustom* pCst = new SwTOXCustom( sDeli, aEmptyStr, FORM_ALPHA_DELIMITTER, + rIntl, aSortArr[i]->GetLocale() ); + aSortArr.Insert( pCst, i++ ); + } + sLastDeli = sDeli; + } + + // Skippen bis gleibhes oder kleineres Level erreicht ist + do { + i++; + } while (i < aSortArr.Count() && aSortArr[i]->GetLevel() > nLevel); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Template auswerten + --------------------------------------------------------------------*/ + +SwTxtFmtColl* SwTOXBaseSection::GetTxtFmtColl( sal_uInt16 nLevel ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + const String& rName = GetTOXForm().GetTemplate( nLevel ); + SwTxtFmtColl* pColl = rName.Len() ? pDoc->FindTxtFmtCollByName(rName) :0; + if( !pColl ) + { + sal_uInt16 nPoolFmt = 0; + const TOXTypes eMyType = SwTOXBase::GetType(); + switch( eMyType ) + { + case TOX_INDEX: nPoolFmt = RES_POOLCOLL_TOX_IDXH; break; + case TOX_USER: + if( nLevel < 6 ) + nPoolFmt = RES_POOLCOLL_TOX_USERH; + else + nPoolFmt = RES_POOLCOLL_TOX_USER6 - 6; + break; + case TOX_ILLUSTRATIONS: nPoolFmt = RES_POOLCOLL_TOX_ILLUSH; break; + case TOX_OBJECTS: nPoolFmt = RES_POOLCOLL_TOX_OBJECTH; break; + case TOX_TABLES: nPoolFmt = RES_POOLCOLL_TOX_TABLESH; break; + case TOX_AUTHORITIES: nPoolFmt = RES_POOLCOLL_TOX_AUTHORITIESH; break; + + case TOX_CONTENT: + // im Content Bereich gibt es einen Sprung! + if( nLevel < 6 ) + nPoolFmt = RES_POOLCOLL_TOX_CNTNTH; + else + nPoolFmt = RES_POOLCOLL_TOX_CNTNT6 - 6; + break; + } + + if(eMyType == TOX_AUTHORITIES && nLevel) + nPoolFmt = nPoolFmt + 1; + else if(eMyType == TOX_INDEX && nLevel) + { + //pool: Level 1,2,3, Delimiter + //SwForm: Delimiter, Level 1,2,3 + nPoolFmt += 1 == nLevel ? nLevel + 3 : nLevel - 1; + } + else + nPoolFmt = nPoolFmt + nLevel; + pColl = pDoc->GetTxtCollFromPool( nPoolFmt ); + } + return pColl; +} + + +/*-------------------------------------------------------------------- + Beschreibung: Aus Markierungen erzeugen + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::UpdateMarks( const SwTOXInternational& rIntl, + const SwTxtNode* pOwnChapterNode ) +{ + const SwModify* pType = SwTOXBase::GetRegisteredIn(); + if( !pType->GetDepends() ) + return; + + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + TOXTypes eTOXTyp = GetTOXType()->GetType(); + SwClientIter aIter( *(SwModify*)pType ); + + SwTxtTOXMark* pTxtMark; + SwTOXMark* pMark; + for( pMark = (SwTOXMark*)aIter.First( TYPE( SwTOXMark )); pMark; + pMark = (SwTOXMark*)aIter.Next() ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + if( pMark->GetTOXType()->GetType() == eTOXTyp && + 0 != ( pTxtMark = pMark->GetTxtTOXMark() ) ) + { + const SwTxtNode* pTOXSrc = pTxtMark->GetpTxtNd(); + // nur TOXMarks einfuegen die im Doc stehen + // nicht die, die im UNDO stehen + // + // if selected use marks from the same chapter only + if( pTOXSrc->GetNodes().IsDocNodes() && + pTOXSrc->GetTxt().Len() && pTOXSrc->GetDepends() && + pTOXSrc->GetFrm() && + (!IsFromChapter() || ::lcl_FindChapterNode( *pTOXSrc, 0 ) == pOwnChapterNode ) && + !pTOXSrc->HasHiddenParaField() && + !SwScriptInfo::IsInHiddenRange( *pTOXSrc, *pTxtMark->GetStart() ) ) + { + SwTOXSortTabBase* pBase = 0; + if(TOX_INDEX == eTOXTyp) + { + // Stichwortverzeichnismarkierung + lang::Locale aLocale; + if ( pBreakIt->GetBreakIter().is() ) + { + aLocale = pBreakIt->GetLocale( + pTOXSrc->GetLang( *pTxtMark->GetStart() ) ); + } + + pBase = new SwTOXIndex( *pTOXSrc, pTxtMark, + GetOptions(), FORM_ENTRY, rIntl, aLocale ); + InsertSorted(pBase); + if(GetOptions() & nsSwTOIOptions::TOI_KEY_AS_ENTRY && + pTxtMark->GetTOXMark().GetPrimaryKey().Len()) + { + pBase = new SwTOXIndex( *pTOXSrc, pTxtMark, + GetOptions(), FORM_PRIMARY_KEY, rIntl, aLocale ); + InsertSorted(pBase); + if(pTxtMark->GetTOXMark().GetSecondaryKey().Len()) + { + pBase = new SwTOXIndex( *pTOXSrc, pTxtMark, + GetOptions(), FORM_SECONDARY_KEY, rIntl, aLocale ); + InsertSorted(pBase); + } + } + } + else if( TOX_USER == eTOXTyp || + pMark->GetLevel() <= GetLevel()) + { // Inhaltsberzeichnismarkierung + // also used for user marks + pBase = new SwTOXContent( *pTOXSrc, pTxtMark, rIntl ); + InsertSorted(pBase); + } + } + } + } +} + + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnisinhalt aus Gliederungsebene generieren + --------------------------------------------------------------------*/ + + +void SwTOXBaseSection::UpdateOutline( const SwTxtNode* pOwnChapterNode ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + SwNodes& rNds = pDoc->GetNodes(); + + const SwOutlineNodes& rOutlNds = rNds.GetOutLineNds(); + for( sal_uInt16 n = 0; n < rOutlNds.Count(); ++n ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + SwTxtNode* pTxtNd = rOutlNds[ n ]->GetTxtNode(); + if( pTxtNd && pTxtNd->Len() && pTxtNd->GetDepends() && + //sal_uInt16(pTxtNd->GetTxtColl()->GetOutlineLevel()+1) <= GetLevel() && //#outline level,zhaojianwei + sal_uInt16( pTxtNd->GetAttrOutlineLevel()) <= GetLevel() && //<-end,zhaojianwei + pTxtNd->GetFrm() && + !pTxtNd->HasHiddenParaField() && + !pTxtNd->HasHiddenCharAttribute( true ) && + ( !IsFromChapter() || + ::lcl_FindChapterNode( *pTxtNd, 0 ) == pOwnChapterNode )) + { + SwTOXPara * pNew = new SwTOXPara( *pTxtNd, nsSwTOXElement::TOX_OUTLINELEVEL ); + InsertSorted( pNew ); + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Verzeichnisinhalt aus Vorlagenbereichen generieren + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::UpdateTemplate( const SwTxtNode* pOwnChapterNode ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + for(sal_uInt16 i = 0; i < MAXLEVEL; i++) + { + String sTmpStyleNames = GetStyleNames(i); + sal_uInt16 nTokenCount = sTmpStyleNames.GetTokenCount(TOX_STYLE_DELIMITER); + for( sal_uInt16 nStyle = 0; nStyle < nTokenCount; ++nStyle ) + { + SwTxtFmtColl* pColl = pDoc->FindTxtFmtCollByName( + sTmpStyleNames.GetToken( nStyle, + TOX_STYLE_DELIMITER )); + //TODO: no outline Collections in content indexes if OutlineLevels are already included + if( !pColl || + ( TOX_CONTENT == SwTOXBase::GetType() && + GetCreateType() & nsSwTOXElement::TOX_OUTLINELEVEL && + //NO_NUMBERING != pColl->GetOutlineLevel() ) )//#outline level,zhaojianwei + pColl->IsAssignedToListLevelOfOutlineStyle()) )//<-end,zhaojianwei + continue; + + SwClientIter aIter( *pColl ); + SwTxtNode* pTxtNd = (SwTxtNode*)aIter.First( TYPE( SwTxtNode )); + for( ; pTxtNd; pTxtNd = (SwTxtNode*)aIter.Next() ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + if( pTxtNd->GetTxt().Len() && pTxtNd->GetFrm() && + pTxtNd->GetNodes().IsDocNodes() && + ( !IsFromChapter() || pOwnChapterNode == + ::lcl_FindChapterNode( *pTxtNd, 0 ) ) ) + { + SwTOXPara * pNew = new SwTOXPara( *pTxtNd, nsSwTOXElement::TOX_TEMPLATE, i + 1 ); + InsertSorted(pNew); + } + } + } + } +} + +/* -----------------14.07.99 09:59------------------- + Description: generate content from sequence fields + --------------------------------------------------*/ +void SwTOXBaseSection::UpdateSequence( const SwTxtNode* pOwnChapterNode ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + SwFieldType* pSeqFld = pDoc->GetFldType(RES_SETEXPFLD, GetSequenceName(), false); + if(!pSeqFld) + return; + + SwClientIter aIter( *pSeqFld ); + SwFmtFld* pFmtFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + for( ; pFmtFld; pFmtFld = (SwFmtFld*)aIter.Next() ) + { + const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); + if(!pTxtFld) + continue; + const SwTxtNode& rTxtNode = pTxtFld->GetTxtNode(); + ::SetProgressState( 0, pDoc->GetDocShell() ); + + if( rTxtNode.GetTxt().Len() && rTxtNode.GetFrm() && + rTxtNode.GetNodes().IsDocNodes() && + ( !IsFromChapter() || + ::lcl_FindChapterNode( rTxtNode, 0 ) == pOwnChapterNode ) ) + { + SwTOXPara * pNew = new SwTOXPara( rTxtNode, nsSwTOXElement::TOX_SEQUENCE, 1 ); + //set indexes if the number or the reference text are to be displayed + if( GetCaptionDisplay() == CAPTION_TEXT ) + { + pNew->SetStartIndex( + SwGetExpField::GetReferenceTextPos( *pFmtFld, *pDoc )); + } + else if(GetCaptionDisplay() == CAPTION_NUMBER) + { + pNew->SetEndIndex(*pTxtFld->GetStart() + 1); + } + InsertSorted(pNew); + } + } +} +/* -----------------15.09.99 14:18------------------- + + --------------------------------------------------*/ +void SwTOXBaseSection::UpdateAuthorities( const SwTOXInternational& rIntl ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + SwFieldType* pAuthFld = pDoc->GetFldType(RES_AUTHORITY, aEmptyStr, false); + if(!pAuthFld) + return; + + SwClientIter aIter( *pAuthFld ); + SwFmtFld* pFmtFld = (SwFmtFld*)aIter.First( TYPE( SwFmtFld )); + for( ; pFmtFld; pFmtFld = (SwFmtFld*)aIter.Next() ) + { + const SwTxtFld* pTxtFld = pFmtFld->GetTxtFld(); + //undo + if(!pTxtFld) + continue; + const SwTxtNode& rTxtNode = pTxtFld->GetTxtNode(); + ::SetProgressState( 0, pDoc->GetDocShell() ); + +// const SwTxtNode* pChapterCompareNode = 0; + + if( rTxtNode.GetTxt().Len() && rTxtNode.GetFrm() && + rTxtNode.GetNodes().IsDocNodes() /*&& + (!IsFromChapter() || pChapterCompareNode == pOwnChapterNode) */) + { + //#106485# the body node has to be used! + SwCntntFrm *pFrm = rTxtNode.GetFrm(); + SwPosition aFldPos(rTxtNode); + const SwTxtNode* pTxtNode = 0; + if(pFrm && !pFrm->IsInDocBody()) + pTxtNode = GetBodyTxtNode( *pDoc, aFldPos, *pFrm ); + if(!pTxtNode) + pTxtNode = &rTxtNode; + SwTOXAuthority* pNew = new SwTOXAuthority( *pTxtNode, *pFmtFld, rIntl ); + + InsertSorted(pNew); + } + } +} + +long lcl_IsSOObject( const SvGlobalName& rFactoryNm ) +{ + static struct _SoObjType { + long nFlag; + // GlobalNameId + struct _GlobalNameIds { + sal_uInt32 n1; + sal_uInt16 n2, n3; + sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15; + } aGlNmIds[4]; + } aArr[] = { + { nsSwTOOElements::TOO_MATH, + { {SO3_SM_CLASSID_60},{SO3_SM_CLASSID_50}, + {SO3_SM_CLASSID_40},{SO3_SM_CLASSID_30} } }, + { nsSwTOOElements::TOO_CHART, + { {SO3_SCH_CLASSID_60},{SO3_SCH_CLASSID_50}, + {SO3_SCH_CLASSID_40},{SO3_SCH_CLASSID_30} } }, + { nsSwTOOElements::TOO_CALC, + { {SO3_SC_CLASSID_60},{SO3_SC_CLASSID_50}, + {SO3_SC_CLASSID_40},{SO3_SC_CLASSID_30} } }, + { nsSwTOOElements::TOO_DRAW_IMPRESS, + { {SO3_SIMPRESS_CLASSID_60},{SO3_SIMPRESS_CLASSID_50}, + {SO3_SIMPRESS_CLASSID_40},{SO3_SIMPRESS_CLASSID_30} } }, + { nsSwTOOElements::TOO_DRAW_IMPRESS, + { {SO3_SDRAW_CLASSID_60},{SO3_SDRAW_CLASSID_50}}}, + { 0,{{0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0} } } + }; + + long nRet = 0; + for( const _SoObjType* pArr = aArr; !nRet && pArr->nFlag; ++pArr ) + for ( int n = 0; n < 4; ++n ) + { + const _SoObjType::_GlobalNameIds& rId = pArr->aGlNmIds[ n ]; + if( !rId.n1 ) + break; + SvGlobalName aGlbNm( rId.n1, rId.n2, rId.n3, + rId.b8, rId.b9, rId.b10, rId.b11, + rId.b12, rId.b13, rId.b14, rId.b15 ); + if( rFactoryNm == aGlbNm ) + { + nRet = pArr->nFlag; + break; + } + } + + return nRet; +} + +void SwTOXBaseSection::UpdateCntnt( SwTOXElement eMyType, + const SwTxtNode* pOwnChapterNode ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + SwNodes& rNds = pDoc->GetNodes(); + // auf den 1. Node der 1. Section + sal_uLong nIdx = rNds.GetEndOfAutotext().StartOfSectionIndex() + 2, + nEndIdx = rNds.GetEndOfAutotext().GetIndex(); + + while( nIdx < nEndIdx ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + SwNode* pNd = rNds[ nIdx ]; + SwCntntNode* pCNd = 0; + switch( eMyType ) + { + case nsSwTOXElement::TOX_FRAME: + if( !pNd->IsNoTxtNode() ) + { + pCNd = pNd->GetCntntNode(); + if( !pCNd ) + { + SwNodeIndex aTmp( *pNd ); + pCNd = rNds.GoNext( &aTmp ); + } + } + break; + case nsSwTOXElement::TOX_GRAPHIC: + if( pNd->IsGrfNode() ) + pCNd = (SwCntntNode*)pNd; + break; + case nsSwTOXElement::TOX_OLE: + if( pNd->IsOLENode() ) + { + sal_Bool bInclude = sal_True; + if(TOX_OBJECTS == SwTOXBase::GetType()) + { + SwOLENode* pOLENode = pNd->GetOLENode(); + long nMyOLEOptions = GetOLEOptions(); + SwOLEObj& rOLEObj = pOLENode->GetOLEObj(); + + if( rOLEObj.IsOleRef() ) //Noch nicht geladen + { + SvGlobalName aTmpName = SvGlobalName( rOLEObj.GetOleRef()->getClassID() ); + long nObj = ::lcl_IsSOObject( aTmpName ); + bInclude = ( (nMyOLEOptions & nsSwTOOElements::TOO_OTHER) && 0 == nObj) + || (0 != (nMyOLEOptions & nObj)); + } + else + { + DBG_ERROR("OLE-object nicht geladen?"); + bInclude = sal_False; + } + } + + if(bInclude) + pCNd = (SwCntntNode*)pNd; + } + break; + default: break; + } + + if( pCNd ) + { + //find node in body text + int nSetLevel = USHRT_MAX; + + //#111105# tables of tables|illustrations|objects don't support hierarchies + if( IsLevelFromChapter() && + TOX_TABLES != SwTOXBase::GetType() && + TOX_ILLUSTRATIONS != SwTOXBase::GetType() && + TOX_OBJECTS != SwTOXBase::GetType() ) + { + const SwTxtNode* pOutlNd = ::lcl_FindChapterNode( *pCNd, + MAXLEVEL - 1 ); + if( pOutlNd ) + { + //sal_uInt16 nTmp = pOutlNd->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + //if( nTmp < NO_NUMBERING ) + // nSetLevel = nTmp + 1; + if( pOutlNd->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle()) + nSetLevel = pOutlNd->GetTxtColl()->GetAttrOutlineLevel() ;//<-end,zhaojianwei + } + } + + if( pCNd->GetFrm() && ( !IsFromChapter() || + ::lcl_FindChapterNode( *pCNd, 0 ) == pOwnChapterNode )) + { + SwTOXPara * pNew = new SwTOXPara( *pCNd, eMyType, + ( USHRT_MAX != nSetLevel ) + ? static_cast<sal_uInt16>(nSetLevel) + : FORM_ALPHA_DELIMITTER ); + InsertSorted( pNew ); + } + } + + nIdx = pNd->StartOfSectionNode()->EndOfSectionIndex() + 2; // 2 == End-/StartNode + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Tabelleneintraege zusammensuchen + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::UpdateTable( const SwTxtNode* pOwnChapterNode ) +{ + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + SwNodes& rNds = pDoc->GetNodes(); + const SwFrmFmts& rArr = *pDoc->GetTblFrmFmts(); + + for( sal_uInt16 n = 0; n < rArr.Count(); ++n ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + SwTable* pTmpTbl = SwTable::FindTable( rArr[ n ] ); + SwTableBox* pFBox; + if( pTmpTbl && 0 != (pFBox = pTmpTbl->GetTabSortBoxes()[0] ) && + pFBox->GetSttNd() && pFBox->GetSttNd()->GetNodes().IsDocNodes() ) + { + const SwTableNode* pTblNd = pFBox->GetSttNd()->FindTableNode(); + SwNodeIndex aCntntIdx( *pTblNd, 1 ); + + SwCntntNode* pCNd; + while( 0 != ( pCNd = rNds.GoNext( &aCntntIdx ) ) && + aCntntIdx.GetIndex() < pTblNd->EndOfSectionIndex() ) + { + if( pCNd->GetFrm() && (!IsFromChapter() || + ::lcl_FindChapterNode( *pCNd, 0 ) == pOwnChapterNode )) + { + SwTOXTable * pNew = new SwTOXTable( *pCNd ); + if( IsLevelFromChapter() && TOX_TABLES != SwTOXBase::GetType()) + { + const SwTxtNode* pOutlNd = + ::lcl_FindChapterNode( *pCNd, MAXLEVEL - 1 ); + if( pOutlNd ) + { + //sal_uInt16 nTmp = pOutlNd->GetTxtColl()->GetOutlineLevel();//#outline level,zhaojianwei + //if( nTmp < NO_NUMBERING ) + // pNew->SetLevel( nTmp + 1 ); + if( pOutlNd->GetTxtColl()->IsAssignedToListLevelOfOutlineStyle()) + { + const int nTmp = pOutlNd->GetTxtColl()->GetAttrOutlineLevel(); + pNew->SetLevel( static_cast<sal_uInt16>(nTmp) );//<-end ,zhaojianwei + } + } + } + InsertSorted(pNew); + break; + } + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: String generieren anhand der Form + SonderZeichen 0-31 und 255 entfernen + --------------------------------------------------------------------*/ + +String lcl_GetNumString( const SwTOXSortTabBase& rBase, sal_Bool bUsePrefix, sal_uInt8 nLevel ) +{ + String sRet; + + if( !rBase.pTxtMark && rBase.aTOXSources.Count() > 0 ) + { // nur wenn es keine Marke ist + const SwTxtNode* pNd = rBase.aTOXSources[0].pNd->GetTxtNode(); + if( pNd ) + { + const SwNumRule* pRule = pNd->GetNumRule(); + + if( pRule && pNd->GetActualListLevel() < MAXLEVEL ) + sRet = pNd->GetNumString(bUsePrefix, nLevel); + } + } + return sRet; +} + +// OD 18.03.2003 #106329# - add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> +// in order to control, which page description is used, no appropriate one is found. +void SwTOXBaseSection::GenerateText( sal_uInt16 nArrayIdx, + sal_uInt16 nCount, + SvStringsDtor& , + const sal_uInt32 _nTOXSectNdIdx, + const SwPageDesc* _pDefaultPageDesc ) +{ + LinkStructArr aLinkArr; + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + ::SetProgressState( 0, pDoc->GetDocShell() ); + + //pTOXNd is only set at the first mark + SwTxtNode* pTOXNd = (SwTxtNode*)aSortArr[nArrayIdx]->pTOXNd; + String& rTxt = (String&)pTOXNd->GetTxt(); + rTxt.Erase(); + for(sal_uInt16 nIndex = nArrayIdx; nIndex < nArrayIdx + nCount; nIndex++) + { + if(nIndex > nArrayIdx) + rTxt.AppendAscii( RTL_CONSTASCII_STRINGPARAM( ", " )); // comma separation + // String mit dem Pattern aus der Form initialisieren + const SwTOXSortTabBase& rBase = *aSortArr[nIndex]; + sal_uInt16 nLvl = rBase.GetLevel(); + ASSERT( nLvl < GetTOXForm().GetFormMax(), "ungueltiges FORM_LEVEL"); + + SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); + xub_StrLen nLinkStartPosition = STRING_NOTFOUND; + String sLinkCharacterStyle; //default to "Default" character style - which is none + String sURL; + // create an enumerator + // #i21237# + SwFormTokens aPattern = GetTOXForm().GetPattern(nLvl); + SwFormTokens::iterator aIt = aPattern.begin(); + // remove text from node + while(aIt != aPattern.end()) // #i21237# + { + SwFormToken aToken = *aIt; // #i21237# + xub_StrLen nStartCharStyle = rTxt.Len(); + switch( aToken.eTokenType ) + { + case TOKEN_ENTRY_NO: + // fuer Inhaltsverzeichnis Numerierung + rTxt.Insert( lcl_GetNumString( rBase, aToken.nChapterFormat == CF_NUMBER, static_cast<sal_uInt8>(aToken.nOutlineLevel - 1)) ); + break; + + case TOKEN_ENTRY_TEXT: + { + SwIndex aIdx( pTOXNd, rTxt.Len() ); + rBase.FillText( *pTOXNd, aIdx ); + } + break; + + case TOKEN_ENTRY: + { + // fuer Inhaltsverzeichnis Numerierung + rTxt.Insert( lcl_GetNumString( rBase, sal_True, MAXLEVEL )); + + SwIndex aIdx( pTOXNd, rTxt.Len() ); + rBase.FillText( *pTOXNd, aIdx ); + } + break; + + case TOKEN_TAB_STOP: + if (aToken.bWithTab) // #i21237# + rTxt.Append('\t'); + // + + if(SVX_TAB_ADJUST_END > aToken.eTabAlign) + { + const SvxLRSpaceItem& rLR = + (SvxLRSpaceItem&)pTOXNd-> + SwCntntNode::GetAttr( RES_LR_SPACE, sal_True ); + + long nTabPosition = aToken.nTabStopPosition; + if( !GetTOXForm().IsRelTabPos() && rLR.GetTxtLeft() ) + nTabPosition -= rLR.GetTxtLeft(); + aTStops.Insert( SvxTabStop( nTabPosition, + aToken.eTabAlign, + cDfltDecimalChar, + aToken.cTabFillChar )); + } + else + { + const SwPageDesc* pPageDesc = ((SwFmtPageDesc&)pTOXNd-> + SwCntntNode::GetAttr( RES_PAGEDESC )).GetPageDesc(); + + sal_Bool bCallFindRect = sal_True; + long nRightMargin; + if( pPageDesc ) + { + const SwFrm* pFrm = pTOXNd->GetFrm( 0, 0, sal_True ); + if( !pFrm || 0 == ( pFrm = pFrm->FindPageFrm() ) || + pPageDesc != ((SwPageFrm*)pFrm)->GetPageDesc() ) + // dann muss man ueber den PageDesc gehen + bCallFindRect = sal_False; + } + + SwRect aNdRect; + if( bCallFindRect ) + aNdRect = pTOXNd->FindLayoutRect( sal_True ); + + if( aNdRect.IsEmpty() ) + { + // dann hilft alles nichts, wir muessen ueber die Seiten- + // vorlage gehen. + // OD 18.03.2003 #106329# - call + sal_uInt32 nPgDescNdIdx = pTOXNd->GetIndex() + 1; + sal_uInt32* pPgDescNdIdx = &nPgDescNdIdx; + pPageDesc = pTOXNd->FindPageDesc( sal_False, pPgDescNdIdx ); + if ( !pPageDesc || + *pPgDescNdIdx < _nTOXSectNdIdx ) + { + // use default page description, if none is found + // or the found one is given by a node before the + // table-of-content section. + pPageDesc = _pDefaultPageDesc; + } + + const SwFrmFmt& rPgDscFmt = pPageDesc->GetMaster(); + nRightMargin = rPgDscFmt.GetFrmSize().GetWidth() - + rPgDscFmt.GetLRSpace().GetLeft() - + rPgDscFmt.GetLRSpace().GetRight(); + } + else + nRightMargin = aNdRect.Width(); + //#i24363# tab stops relative to indent + if( pDoc->get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) ) + { + //left margin of paragraph style + const SvxLRSpaceItem& rLRSpace = pTOXNd->GetTxtColl()->GetLRSpace(); + nRightMargin -= rLRSpace.GetLeft(); + nRightMargin -= rLRSpace.GetTxtFirstLineOfst(); + } + + aTStops.Insert( SvxTabStop( nRightMargin, SVX_TAB_ADJUST_RIGHT, + cDfltDecimalChar, + aToken.cTabFillChar )); + } + break; + + case TOKEN_TEXT: + rTxt.Append( aToken.sText ); + break; + + case TOKEN_PAGE_NUMS: + // Platzhalter fuer Seitennummer(n) es wird nur der erste beachtet + // + { + // Die Anzahl der gleichen Eintrage bestimmt die Seitennummern-Pattern + // + sal_uInt16 nSize = rBase.aTOXSources.Count(); + if( nSize > 0 ) + { + String aInsStr( cNumRepl ); + for(sal_uInt16 i=1; i < nSize; ++i) + { + aInsStr.AppendAscii( sPageDeli ); + aInsStr += cNumRepl; + } + aInsStr += cEndPageNum; + rTxt.Append( aInsStr ); + } +// // Tab entfernen, wenn keine Seitennummer +// else if( rTxt.Len() && '\t' == rTxt.GetChar( rTxt.Len() - 1 )) +// rTxt.Erase( rTxt.Len()-1, 1 ); + } + break; + + case TOKEN_CHAPTER_INFO: + { + // ein bischen trickreich: suche irgend einen Frame + const SwTOXSource* pTOXSource = 0; + if(rBase.aTOXSources.Count()) + pTOXSource = &rBase.aTOXSources[0]; + + // --> OD 2008-02-14 #i53420# +// if( pTOXSource && pTOXSource->pNd +// pTOXSource->pNd->IsTxtNode() ) + if ( pTOXSource && pTOXSource->pNd && + pTOXSource->pNd->IsCntntNode() ) + // <-- + { + const SwCntntFrm* pFrm = pTOXSource->pNd->GetFrm(); + if( pFrm ) + { + SwChapterFieldType aFldTyp; + SwChapterField aFld( &aFldTyp, aToken.nChapterFormat ); + aFld.SetLevel( static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ); + // --> OD 2008-02-14 #i53420# +// aFld.ChangeExpansion( pFrm, (SwTxtNode*)pTOXSource->pNd, sal_True ); + aFld.ChangeExpansion( pFrm, + dynamic_cast<const SwCntntNode*>(pTOXSource->pNd), + sal_True ); + // <-- + //---> i89791 + // OD 2008-06-26 - continue to support CF_NUMBER + // and CF_NUM_TITLE in order to handle ODF 1.0/1.1 + // written by OOo 3.x in the same way as OOo 2.x + // would handle them. + if ( CF_NUM_NOPREPST_TITLE == aToken.nChapterFormat || + CF_NUMBER == aToken.nChapterFormat ) + rTxt.Insert(aFld.GetNumber()); //get the string number without pre/postfix + else if ( CF_NUMBER_NOPREPST == aToken.nChapterFormat || + CF_NUM_TITLE == aToken.nChapterFormat ) + //<--- + { + rTxt += aFld.GetNumber(); + rTxt += ' '; + rTxt += aFld.GetTitle(); + } + else if(CF_TITLE == aToken.nChapterFormat) + rTxt += aFld.GetTitle(); + } + } + } + break; + + case TOKEN_LINK_START: + nLinkStartPosition = rTxt.Len(); + sLinkCharacterStyle = aToken.sCharStyleName; + break; + + case TOKEN_LINK_END: + //TODO: only paired start/end tokens are valid + if( STRING_NOTFOUND != nLinkStartPosition) + { + SwIndex aIdx( pTOXNd, nLinkStartPosition ); + //pTOXNd->Erase( aIdx, SwForm::nFormLinkSttLen ); + xub_StrLen nEnd = rTxt.Len(); + + if( !sURL.Len() ) + { + sURL = rBase.GetURL(); + if( !sURL.Len() ) + break; + } + LinkStruct* pNewLink = new LinkStruct(sURL, nLinkStartPosition, + nEnd); + pNewLink->aINetFmt.SetVisitedFmt(sLinkCharacterStyle); + pNewLink->aINetFmt.SetINetFmt(sLinkCharacterStyle); + if(sLinkCharacterStyle.Len()) + { + sal_uInt16 nPoolId = + SwStyleNameMapper::GetPoolIdFromUIName( sLinkCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); + pNewLink->aINetFmt.SetVisitedFmtId(nPoolId); + pNewLink->aINetFmt.SetINetFmtId(nPoolId); + } + else + { + pNewLink->aINetFmt.SetVisitedFmtId(USHRT_MAX); + pNewLink->aINetFmt.SetINetFmtId(USHRT_MAX); + } + aLinkArr.Insert( pNewLink, aLinkArr.Count() ); + nLinkStartPosition = STRING_NOTFOUND; + sLinkCharacterStyle.Erase(); + } + break; + + case TOKEN_AUTHORITY: + { + ToxAuthorityField eField = (ToxAuthorityField)aToken.nAuthorityField; + SwIndex aIdx( pTOXNd, rTxt.Len() ); + rBase.FillText( *pTOXNd, aIdx, static_cast<sal_uInt16>(eField) ); + } + break; + case TOKEN_END: break; + } + + if( aToken.sCharStyleName.Len() ) + { + SwCharFmt* pCharFmt; + if( USHRT_MAX != aToken.nPoolId ) + pCharFmt = pDoc->GetCharFmtFromPool( aToken.nPoolId ); + else + pCharFmt = pDoc->FindCharFmtByName( aToken.sCharStyleName); + + if (pCharFmt) + { + SwFmtCharFmt aFmt( pCharFmt ); + pTOXNd->InsertItem( aFmt, nStartCharStyle, + rTxt.Len(), nsSetAttrMode::SETATTR_DONTEXPAND ); + } + } + + aIt++; // #i21237# + } + + pTOXNd->SetAttr( aTStops ); + } + + if(aLinkArr.Count()) + for(sal_uInt16 i = 0; i < aLinkArr.Count(); ++i ) + { + LinkStruct* pTmp = aLinkArr.GetObject(i); + pTOXNd->InsertItem( pTmp->aINetFmt, pTmp->nStartTextPos, + pTmp->nEndTextPos); + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Seitennummer errechnen und nach dem Formatieren + eintragen + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::UpdatePageNum() +{ + if( !aSortArr.Count() ) + return ; + + // die aktuellen Seitennummern ins Verzeichnis eintragen + SwPageFrm* pAktPage = 0; + sal_uInt16 nPage = 0; + SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); + + SwTOXInternational aIntl( GetLanguage(), + TOX_INDEX == GetTOXType()->GetType() ? + GetOptions() : 0, + GetSortAlgorithm() ); + + for( sal_uInt16 nCnt = 0; nCnt < aSortArr.Count(); ++nCnt ) + { + // Schleife ueber alle SourceNodes + SvUShorts aNums; //Die Seitennummern + SvPtrarr aDescs; //Die PageDescriptoren passend zu den Seitennummern. + SvUShorts* pMainNums = 0; // contains page numbers of main entries + + // process run in lines + sal_uInt16 nRange = 0; + if(GetTOXForm().IsCommaSeparated() && + aSortArr[nCnt]->GetType() == TOX_SORT_INDEX) + { + const SwTOXMark& rMark = aSortArr[nCnt]->pTxtMark->GetTOXMark(); + const String sPrimKey = rMark.GetPrimaryKey(); + const String sSecKey = rMark.GetSecondaryKey(); + const SwTOXMark* pNextMark = 0; + while(aSortArr.Count() > (nCnt + nRange)&& + aSortArr[nCnt + nRange]->GetType() == TOX_SORT_INDEX && + 0 != (pNextMark = &(aSortArr[nCnt + nRange]->pTxtMark->GetTOXMark())) && + pNextMark->GetPrimaryKey() == sPrimKey && + pNextMark->GetSecondaryKey() == sSecKey) + nRange++; + } + else + nRange = 1; + + for(sal_uInt16 nRunInEntry = nCnt; nRunInEntry < nCnt + nRange; nRunInEntry++) + { + SwTOXSortTabBase* pSortBase = aSortArr[nRunInEntry]; + sal_uInt16 nSize = pSortBase->aTOXSources.Count(); + sal_uInt16 i; + for( sal_uInt16 j = 0; j < nSize; ++j ) + { + ::SetProgressState( 0, pDoc->GetDocShell() ); + + SwTOXSource& rTOXSource = pSortBase->aTOXSources[j]; + if( rTOXSource.pNd ) + { + SwCntntFrm* pFrm = rTOXSource.pNd->GetFrm(); + ASSERT( pFrm || pDoc->IsUpdateTOX(), "TOX, no Frame found"); + if( !pFrm ) + continue; + if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->HasFollow() ) + { + // dann suche den richtigen heraus + SwTxtFrm* pNext = (SwTxtFrm*)pFrm; + while( 0 != ( pNext = (SwTxtFrm*)pFrm->GetFollow() ) + && rTOXSource.nPos >= pNext->GetOfst() ) + pFrm = pNext; + } + + SwPageFrm* pTmpPage = pFrm->FindPageFrm(); + if( pTmpPage != pAktPage ) + { + nPage = pTmpPage->GetVirtPageNum(); + pAktPage = pTmpPage; + } + + // sortiert einfuegen + for( i = 0; i < aNums.Count() && aNums[i] < nPage; ++i ) + ; + + if( i >= aNums.Count() || aNums[ i ] != nPage ) + { + aNums.Insert( nPage, i ); + aDescs.Insert( (void*)pAktPage->GetPageDesc(), i ); + } + // is it a main entry? + if(TOX_SORT_INDEX == pSortBase->GetType() && + rTOXSource.bMainEntry) + { + if(!pMainNums) + pMainNums = new SvUShorts; + pMainNums->Insert(nPage, pMainNums->Count()); + } + } + } + // einfuegen der Seitennummer in den Verzeichnis-Text-Node + const SwTOXSortTabBase* pBase = aSortArr[ nCnt ]; + if(pBase->pTOXNd) + { + const SwTxtNode* pTxtNd = pBase->pTOXNd->GetTxtNode(); + ASSERT( pTxtNd, "kein TextNode, falsches Verzeichnis" ); + + _UpdatePageNum( (SwTxtNode*)pTxtNd, aNums, aDescs, pMainNums, + aIntl ); + } + DELETEZ(pMainNums); + aNums.Remove(0, aNums.Count()); + } + } + // nach dem Setzen der richtigen Seitennummer, das Mapping-Array + // wieder loeschen !! + aSortArr.DeleteAndDestroy( 0, aSortArr.Count() ); +} + + +/*-------------------------------------------------------------------- + Beschreibung: Austausch der Seitennummer-Platzhalter + --------------------------------------------------------------------*/ + +// search for the page no in the array of main entry page numbers +sal_Bool lcl_HasMainEntry( const SvUShorts* pMainEntryNums, sal_uInt16 nToFind ) +{ + for(sal_uInt16 i = 0; pMainEntryNums && i < pMainEntryNums->Count(); ++i) + if(nToFind == (*pMainEntryNums)[i]) + return sal_True; + return sal_False; +} + +void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, + const SvUShorts& rNums, + const SvPtrarr & rDescs, + const SvUShorts* pMainEntryNums, + const SwTOXInternational& rIntl ) +{ + //collect starts end ends of main entry character style + SvUShorts* pCharStyleIdx = pMainEntryNums ? new SvUShorts : 0; + + String sSrchStr( cNumRepl ); + sSrchStr.AppendAscii( sPageDeli ) += cNumRepl; + xub_StrLen nStartPos = pNd->GetTxt().Search( sSrchStr ); + ( sSrchStr = cNumRepl ) += cEndPageNum; + xub_StrLen nEndPos = pNd->GetTxt().Search( sSrchStr ); + sal_uInt16 i; + + if( STRING_NOTFOUND == nEndPos || !rNums.Count() ) + return; + + if( STRING_NOTFOUND == nStartPos || nStartPos > nEndPos) + nStartPos = nEndPos; + + sal_uInt16 nOld = rNums[0], + nBeg = nOld, + nCount = 0; + String aNumStr( SvxNumberType( ((SwPageDesc*)rDescs[0])->GetNumType() ). + GetNumStr( nBeg ) ); + if( pCharStyleIdx && lcl_HasMainEntry( pMainEntryNums, nBeg )) + { + sal_uInt16 nTemp = 0; + pCharStyleIdx->Insert( nTemp, pCharStyleIdx->Count()); + } + + // Platzhalter loeschen + SwIndex aPos(pNd, nStartPos); + SwCharFmt* pPageNoCharFmt = 0; + SwpHints* pHints = pNd->GetpSwpHints(); + if(pHints) + for(sal_uInt16 nHintIdx = 0; nHintIdx < pHints->GetStartCount(); nHintIdx++) + { + SwTxtAttr* pAttr = pHints->GetStart(nHintIdx); + xub_StrLen nTmpEnd = pAttr->GetEnd() ? *pAttr->GetEnd() : 0; + if( nStartPos >= *pAttr->GetStart() && + (nStartPos + 2) <= nTmpEnd && + pAttr->Which() == RES_TXTATR_CHARFMT) + { + pPageNoCharFmt = pAttr->GetCharFmt().GetCharFmt(); + break; + } + } + pNd->EraseText(aPos, nEndPos - nStartPos + 2); + + for( i = 1; i < rNums.Count(); ++i) + { + SvxNumberType aType( ((SwPageDesc*)rDescs[i])->GetNumType() ); + if( TOX_INDEX == SwTOXBase::GetType() ) + { // Zusammenfassen f. ff. + // Alle folgenden aufaddieren + // break up if main entry starts or ends and + // insert a char style index + sal_Bool bMainEntryChanges = lcl_HasMainEntry(pMainEntryNums, nOld) + != lcl_HasMainEntry(pMainEntryNums, rNums[i]); + + if(nOld == rNums[i]-1 && !bMainEntryChanges && + 0 != (GetOptions() & (nsSwTOIOptions::TOI_FF|nsSwTOIOptions::TOI_DASH))) + nCount++; + else + { + // ff. f. alten Wert flushen + if(GetOptions() & nsSwTOIOptions::TOI_FF) + { + if ( nCount >= 1 ) + aNumStr += rIntl.GetFollowingText( nCount > 1 ); + } + else + { + if(nCount >= 2 ) + aNumStr += '-'; + else if(nCount == 1 ) + aNumStr.AppendAscii( sPageDeli ); +//#58127# Wenn nCount == 0, dann steht die einzige Seitenzahl schon im aNumStr! + if(nCount) + aNumStr += aType.GetNumStr( nBeg + nCount ); + } + + // neuen String anlegen + nBeg = rNums[i]; + aNumStr.AppendAscii( sPageDeli ); + //the change of the character style must apply after sPageDeli is appended + if(pCharStyleIdx && bMainEntryChanges) + pCharStyleIdx->Insert(aNumStr.Len(), + pCharStyleIdx->Count()); + aNumStr += aType.GetNumStr( nBeg ); + nCount = 0; + } + nOld = rNums[i]; + } + else + { // Alle Nummern eintragen + aNumStr += aType.GetNumStr( sal_uInt16(rNums[i]) ); + if(i != (rNums.Count()-1)) + aNumStr.AppendAscii( sPageDeli ); + } + } + // Bei Ende und ff. alten Wert flushen + if( TOX_INDEX == SwTOXBase::GetType() ) + { + if(GetOptions() & nsSwTOIOptions::TOI_FF) + { + if( nCount >= 1 ) + aNumStr += rIntl.GetFollowingText( nCount > 1 ); + } + else + { + if(nCount >= 2) + aNumStr +='-'; + else if(nCount == 1) + aNumStr.AppendAscii( sPageDeli ); +//#58127# Wenn nCount == 0, dann steht die einzige Seitenzahl schon im aNumStr! + if(nCount) + aNumStr += SvxNumberType( ((SwPageDesc*)rDescs[i-1])-> + GetNumType() ).GetNumStr( nBeg+nCount ); + } + } + pNd->InsertText( aNumStr, aPos, + static_cast<IDocumentContentOperations::InsertFlags>( + IDocumentContentOperations::INS_EMPTYEXPAND | + IDocumentContentOperations::INS_FORCEHINTEXPAND) ); + if(pPageNoCharFmt) + { + SwFmtCharFmt aCharFmt( pPageNoCharFmt ); + pNd->InsertItem(aCharFmt, nStartPos, nStartPos + aNumStr.Len(), nsSetAttrMode::SETATTR_DONTEXPAND); + } + + //now the main entries should get there character style + if(pCharStyleIdx && pCharStyleIdx->Count() && GetMainEntryCharStyle().Len()) + { + // eventually the last index must me appended + if(pCharStyleIdx->Count()&0x01) + pCharStyleIdx->Insert(aNumStr.Len(), pCharStyleIdx->Count()); + + //search by name + SwDoc* pDoc = pNd->GetDoc(); + sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( GetMainEntryCharStyle(), nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); + SwCharFmt* pCharFmt = 0; + if(USHRT_MAX != nPoolId) + pCharFmt = pDoc->GetCharFmtFromPool(nPoolId); + else + pCharFmt = pDoc->FindCharFmtByName( GetMainEntryCharStyle() ); + if(!pCharFmt) + pCharFmt = pDoc->MakeCharFmt(GetMainEntryCharStyle(), 0); + + //find the page numbers in aNumStr and set the character style + xub_StrLen nOffset = pNd->GetTxt().Len() - aNumStr.Len(); + SwFmtCharFmt aCharFmt(pCharFmt); + for(sal_uInt16 j = 0; j < pCharStyleIdx->Count(); j += 2) + { + xub_StrLen nStartIdx = (*pCharStyleIdx)[j] + nOffset; + xub_StrLen nEndIdx = (*pCharStyleIdx)[j + 1] + nOffset; + pNd->InsertItem(aCharFmt, nStartIdx, nEndIdx, nsSetAttrMode::SETATTR_DONTEXPAND); + } + + } + delete pCharStyleIdx; +} + + +/*-------------------------------------------------------------------- + Beschreibung: Sortiert einfuegen in das SortArr + --------------------------------------------------------------------*/ + +void SwTOXBaseSection::InsertSorted(SwTOXSortTabBase* pNew) +{ + Range aRange(0, aSortArr.Count()); + if( TOX_INDEX == SwTOXBase::GetType() && pNew->pTxtMark ) + { + const SwTOXMark& rMark = pNew->pTxtMark->GetTOXMark(); + // Schluessel auswerten + // Den Bereich ermitteln, in dem einzufuegen ist + if( 0 == (GetOptions() & nsSwTOIOptions::TOI_KEY_AS_ENTRY) && + rMark.GetPrimaryKey().Len() ) + { + aRange = GetKeyRange( rMark.GetPrimaryKey(), + rMark.GetPrimaryKeyReading(), + *pNew, FORM_PRIMARY_KEY, aRange ); + + if( rMark.GetSecondaryKey().Len() ) + aRange = GetKeyRange( rMark.GetSecondaryKey(), + rMark.GetSecondaryKeyReading(), + *pNew, FORM_SECONDARY_KEY, aRange ); + } + } + //search for identical entries and remove the trailing one + if(TOX_AUTHORITIES == SwTOXBase::GetType()) + { + for(short i = (short)aRange.Min(); i < (short)aRange.Max(); ++i) + { + SwTOXSortTabBase* pOld = aSortArr[i]; + if(*pOld == *pNew) + { + if(*pOld < *pNew) + { + delete pNew; + return; + } + else + { + // remove the old content + aSortArr.DeleteAndDestroy( i, 1 ); + aRange.Max()--; + break; + } + } + } + } + + // find position and insert + // + short i; + + for( i = (short)aRange.Min(); i < (short)aRange.Max(); ++i) + { // nur auf gleicher Ebene pruefen + // + SwTOXSortTabBase* pOld = aSortArr[i]; + if(*pOld == *pNew) + { + if(TOX_AUTHORITIES != SwTOXBase::GetType()) + { + // Eigener Eintrag fuer Doppelte oder Keywords + // + if( pOld->GetType() == TOX_SORT_CUSTOM && + pNew->GetOptions() & nsSwTOIOptions::TOI_KEY_AS_ENTRY) + continue; + + if(!(pNew->GetOptions() & nsSwTOIOptions::TOI_SAME_ENTRY)) + { // Eigener Eintrag + aSortArr.Insert(pNew, i ); + return; + } + // Eintrag schon vorhanden in Referenzliste aufnehmen + pOld->aTOXSources.Insert( pNew->aTOXSources[0], + pOld->aTOXSources.Count() ); + + delete pNew; + return; + } +#ifdef DBG_UTIL + else + DBG_ERROR("Bibliography entries cannot be found here"); +#endif + } + if(*pNew < *pOld) + break; + } + // SubLevel Skippen + while( TOX_INDEX == SwTOXBase::GetType() && i < aRange.Max() && + aSortArr[i]->GetLevel() > pNew->GetLevel() ) + i++; + + // An Position i wird eingefuegt + aSortArr.Insert(pNew, i ); +} + +/*-------------------------------------------------------------------- + Beschreibung: Schluessel-Bereich suchen und evtl einfuegen + --------------------------------------------------------------------*/ + +Range SwTOXBaseSection::GetKeyRange(const String& rStr, const String& rStrReading, + const SwTOXSortTabBase& rNew, + sal_uInt16 nLevel, const Range& rRange ) +{ + const SwTOXInternational& rIntl = *rNew.pTOXIntl; + String sToCompare(rStr); + String sToCompareReading(rStrReading); + + if( 0 != (nsSwTOIOptions::TOI_INITIAL_CAPS & GetOptions()) ) + { + String sUpper( rIntl.ToUpper( sToCompare, 0 )); + sToCompare.Erase( 0, 1 ).Insert( sUpper, 0 ); + } + + ASSERT(rRange.Min() >= 0 && rRange.Max() >= 0, "Min Max < 0"); + + const sal_uInt16 nMin = (sal_uInt16)rRange.Min(); + const sal_uInt16 nMax = (sal_uInt16)rRange.Max(); + + sal_uInt16 i; + + for( i = nMin; i < nMax; ++i) + { + SwTOXSortTabBase* pBase = aSortArr[i]; + + String sMyString, sMyStringReading; + pBase->GetTxt( sMyString, sMyStringReading ); + + if( rIntl.IsEqual( sMyString, sMyStringReading, pBase->GetLocale(), + sToCompare, sToCompareReading, rNew.GetLocale() ) && + pBase->GetLevel() == nLevel ) + break; + } + if(i == nMax) + { // Falls nicht vorhanden erzeugen und einfuegen + // + SwTOXCustom* pKey = new SwTOXCustom( sToCompare, sToCompareReading, nLevel, rIntl, + rNew.GetLocale() ); + for(i = nMin; i < nMax; ++i) + { + if(nLevel == aSortArr[i]->GetLevel() && *pKey < *(aSortArr[i])) + break; + } + aSortArr.Insert(pKey, i ); + } + sal_uInt16 nStart = i+1; + sal_uInt16 nEnd = aSortArr.Count(); + + // Ende des Bereiches suchen + for(i = nStart; i < aSortArr.Count(); ++i) + { + if(aSortArr[i]->GetLevel() <= nLevel) + { nEnd = i; + break; + } + } + return Range(nStart, nEnd); +} + + +sal_Bool SwTOXBase::IsTOXBaseInReadonly() const +{ + const SwTOXBaseSection *pSect = PTR_CAST(SwTOXBaseSection, this); + sal_Bool bRet = sal_False; + const SwSectionNode* pSectNode; + if(pSect && pSect->GetFmt() && + 0 != (pSectNode = pSect->GetFmt()->GetSectionNode())) + { + const SwDocShell* pDocSh; + bRet = (0 != (pDocSh = pSectNode->GetDoc()->GetDocShell()) && + pDocSh->IsReadOnly()) || + (0 != (pSectNode = pSectNode->StartOfSectionNode()->FindSectionNode())&& + pSectNode->GetSection().IsProtectFlag()); + + } + return bRet; +} +/* -----------------17.08.99 13:29------------------- + + --------------------------------------------------*/ +const SfxItemSet* SwTOXBase::GetAttrSet() const +{ + const SwTOXBaseSection *pSect = PTR_CAST(SwTOXBaseSection, this); + if(pSect && pSect->GetFmt()) + return &pSect->GetFmt()->GetAttrSet(); + return 0; +} + +void SwTOXBase::SetAttrSet( const SfxItemSet& rSet ) +{ + SwTOXBaseSection *pSect = PTR_CAST(SwTOXBaseSection, this); + if( pSect && pSect->GetFmt() ) + pSect->GetFmt()->SetFmtAttr( rSet ); +} + +sal_Bool SwTOXBase::GetInfo( SfxPoolItem& rInfo ) const +{ + switch( rInfo.Which() ) + { + case RES_CONTENT_VISIBLE: + { + SwTOXBaseSection *pSect = PTR_CAST(SwTOXBaseSection, this); + if( pSect && pSect->GetFmt() ) + pSect->GetFmt()->GetInfo( rInfo ); + } + return sal_False; + } + return sal_True; +} + +/* */ + + diff --git a/sw/source/core/doc/docxforms.cxx b/sw/source/core/doc/docxforms.cxx new file mode 100644 index 000000000000..febab662a8fa --- /dev/null +++ b/sw/source/core/doc/docxforms.cxx @@ -0,0 +1,123 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + + +#include <doc.hxx> +#include <docsh.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XModule.hpp> +#include <com/sun/star/xforms/XModel.hpp> +#include <com/sun/star/xforms/XFormsUIHelper1.hpp> +#include <unotools/processfactory.hxx> +#include <tools/diagnose_ex.h> + + +using namespace ::com::sun::star; + +using uno::Reference; +using uno::XInterface; +using uno::UNO_QUERY; +using uno::makeAny; +using uno::Exception; +using container::XNameContainer; +using xforms::XModel; +using frame::XModule; +using xforms::XFormsUIHelper1; +using rtl::OUString; + + +Reference<XNameContainer> SwDoc::getXForms() const +{ + return xXForms; +} + +bool SwDoc::isXForms() const +{ + return xXForms.is(); +} + +Reference<XInterface> lcl_createInstance( const sal_Char* pServiceName ) +{ + DBG_ASSERT( pServiceName != NULL, "no service name" ); + return utl::getProcessServiceFactory()->createInstance( + OUString::createFromAscii( pServiceName ) ); +} + +void SwDoc::initXForms( bool bCreateDefaultModel ) +{ + DBG_ASSERT( ! isXForms(), "please initialize only once" ); + + try + { + // create XForms components + xXForms.set( lcl_createInstance( "com.sun.star.xforms.XForms" ), + UNO_QUERY ); + DBG_ASSERT( xXForms.is(), "can't create XForms container" ); + + // change our module identifier, to be able to have a dedicated UI + Reference< XModule > xModule; + SwDocShell* pShell( GetDocShell() ); + if ( pShell ) + xModule = xModule.query( pShell->GetModel() ); + DBG_ASSERT( xModule.is(), "SwDoc::initXForms: no XModule at the document!" ); + if ( xModule.is() ) + xModule->setIdentifier( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xforms.XMLFormDocument" ) ) ); + + // create default model + if( bCreateDefaultModel && xXForms.is() ) + { + OUString sName(RTL_CONSTASCII_USTRINGPARAM("Model 1")); + Reference<XModel> xModel( + lcl_createInstance( "com.sun.star.xforms.Model" ), + UNO_QUERY ); + DBG_ASSERT( xModel.is(), "no model?" ); + if( xModel.is() ) + { + xModel->setID( sName ); + Reference<XFormsUIHelper1>( xModel, UNO_QUERY )->newInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("Instance 1")), + OUString(), sal_True ); + xModel->initialize(); + xXForms->insertByName( sName, makeAny( xModel ) ); + } + DBG_ASSERT( xXForms->hasElements(), "can't create XForms model" ); + } + + DBG_ASSERT( isXForms(), "initialization failed" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} diff --git a/sw/source/core/doc/extinput.cxx b/sw/source/core/doc/extinput.cxx new file mode 100644 index 000000000000..93d177aed548 --- /dev/null +++ b/sw/source/core/doc/extinput.cxx @@ -0,0 +1,300 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/i18n/ScriptType.hpp> + +#include <editeng/langitem.hxx> +#include <editeng/scripttypeitem.hxx> + +#include <vcl/keycodes.hxx> +#include <vcl/cmdevt.hxx> + +#include <hintids.hxx> +#include <extinput.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <index.hxx> +#include <ndtxt.hxx> +#include <txtfrm.hxx> +#include <swundo.hxx> + + +using namespace ::com::sun::star; + +SwExtTextInput::SwExtTextInput( const SwPaM& rPam, Ring* pRing ) + : SwPaM( *rPam.GetPoint(), (SwPaM*)pRing ), + eInputLanguage(LANGUAGE_DONTKNOW) +{ + bIsOverwriteCursor = sal_False; + bInsText = sal_True; +} + +SwExtTextInput::~SwExtTextInput() +{ + SwDoc *const pDoc = GetDoc(); + if (pDoc->IsInDtor()) { return; /* #i58606# */ } + + SwTxtNode* pTNd = GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTNd ) + { + SwIndex& rIdx = GetPoint()->nContent; + xub_StrLen nSttCnt = rIdx.GetIndex(), + nEndCnt = GetMark()->nContent.GetIndex(); + if( nEndCnt != nSttCnt ) + { + if( nEndCnt < nSttCnt ) + { + xub_StrLen n = nEndCnt; nEndCnt = nSttCnt; nSttCnt = n; + } + + // damit Undo / Redlining usw. richtig funktioniert, + // muss ueber die Doc-Schnittstellen gegangen werden !!! + if(eInputLanguage != LANGUAGE_DONTKNOW) + { + // --> FME 2005-02-11 #i41974# Only set language attribute + // for CJK/CTL scripts. + bool bLang = true; + // <-- + sal_uInt16 nWhich = RES_CHRATR_LANGUAGE; + switch(GetI18NScriptTypeOfLanguage(eInputLanguage)) + { + case i18n::ScriptType::ASIAN: nWhich = RES_CHRATR_CJK_LANGUAGE; break; + case i18n::ScriptType::COMPLEX: nWhich = RES_CHRATR_CTL_LANGUAGE; break; + default: bLang = false; + } + if ( bLang ) + { + SvxLanguageItem aLangItem( eInputLanguage, nWhich ); + pDoc->InsertPoolItem(*this, aLangItem, 0 ); + } + } + rIdx = nSttCnt; + String sTxt( pTNd->GetTxt().Copy( nSttCnt, nEndCnt - nSttCnt )); + if( bIsOverwriteCursor && sOverwriteText.Len() ) + { + xub_StrLen nLen = sTxt.Len(); + if( nLen > sOverwriteText.Len() ) + { + rIdx += sOverwriteText.Len(); + pTNd->EraseText( rIdx, nLen - sOverwriteText.Len() ); + rIdx = nSttCnt; + pTNd->ReplaceText( rIdx, sOverwriteText.Len(), + sOverwriteText ); + if( bInsText ) + { + rIdx = nSttCnt; + pDoc->GetIDocumentUndoRedo().StartUndo( + UNDO_OVERWRITE, NULL ); + pDoc->Overwrite( *this, sTxt.Copy( 0, + sOverwriteText.Len() )); + pDoc->InsertString( *this, + sTxt.Copy( sOverwriteText.Len() ) ); + pDoc->GetIDocumentUndoRedo().EndUndo( + UNDO_OVERWRITE, NULL ); + } + } + else + { + pTNd->ReplaceText( rIdx, nLen, + sOverwriteText.Copy( 0, nLen )); + if( bInsText ) + { + rIdx = nSttCnt; + pDoc->Overwrite( *this, sTxt ); + } + } + } + else + { + pTNd->EraseText( rIdx, nEndCnt - nSttCnt ); + + if( bInsText ) + { + pDoc->InsertString( *this, sTxt ); + } + } + } + } +} + +void SwExtTextInput::SetInputData( const CommandExtTextInputData& rData ) +{ + SwTxtNode* pTNd = GetPoint()->nNode.GetNode().GetTxtNode(); + if( pTNd ) + { + xub_StrLen nSttCnt = GetPoint()->nContent.GetIndex(), + nEndCnt = GetMark()->nContent.GetIndex(); + if( nEndCnt < nSttCnt ) + { + xub_StrLen n = nEndCnt; nEndCnt = nSttCnt; nSttCnt = n; + } + + SwIndex aIdx( pTNd, nSttCnt ); + const String& rNewStr = rData.GetText(); + + if( bIsOverwriteCursor && sOverwriteText.Len() ) + { + xub_StrLen nReplace = nEndCnt - nSttCnt; + if( rNewStr.Len() < nReplace ) + { + // then we must insert from the saved original text + // some characters + nReplace = nReplace - rNewStr.Len(); + aIdx += rNewStr.Len(); + pTNd->ReplaceText( aIdx, nReplace, + sOverwriteText.Copy( rNewStr.Len(), nReplace )); + aIdx = nSttCnt; + nReplace = rNewStr.Len(); + } + else if( sOverwriteText.Len() < nReplace ) + { + nReplace = nReplace - sOverwriteText.Len(); + aIdx += sOverwriteText.Len(); + pTNd->EraseText( aIdx, nReplace ); + aIdx = nSttCnt; + nReplace = sOverwriteText.Len(); + } + else if( (nReplace = sOverwriteText.Len()) > rNewStr.Len() ) + nReplace = rNewStr.Len(); + + pTNd->ReplaceText( aIdx, nReplace, rNewStr ); + if( !HasMark() ) + SetMark(); + GetMark()->nContent = aIdx; + } + else + { + if( nSttCnt < nEndCnt ) + { + pTNd->EraseText( aIdx, nEndCnt - nSttCnt ); + } + + pTNd->InsertText( rNewStr, aIdx, + IDocumentContentOperations::INS_EMPTYEXPAND ); + if( !HasMark() ) + SetMark(); + } + + GetPoint()->nContent = nSttCnt; + + if( aAttrs.Count() ) + aAttrs.Remove( 0, aAttrs.Count() ); + if( rData.GetTextAttr() ) + aAttrs.Insert( rData.GetTextAttr(), rData.GetText().Len(), 0 ); + } +} + +void SwExtTextInput::SetOverwriteCursor( sal_Bool bFlag ) +{ + bIsOverwriteCursor = bFlag; + + SwTxtNode* pTNd; + if( bIsOverwriteCursor && + 0 != (pTNd = GetPoint()->nNode.GetNode().GetTxtNode()) ) + { + xub_StrLen nSttCnt = GetPoint()->nContent.GetIndex(), + nEndCnt = GetMark()->nContent.GetIndex(); + sOverwriteText = pTNd->GetTxt().Copy( nEndCnt < nSttCnt ? nEndCnt + : nSttCnt ); + if( sOverwriteText.Len() ) + { + xub_StrLen nInWrdAttrPos = sOverwriteText.Search( CH_TXTATR_INWORD ), + nWrdAttrPos = sOverwriteText.Search( CH_TXTATR_BREAKWORD ); + if( nWrdAttrPos < nInWrdAttrPos ) + nInWrdAttrPos = nWrdAttrPos; + if( STRING_NOTFOUND != nInWrdAttrPos ) + sOverwriteText.Erase( nInWrdAttrPos ); + } + } +} + +// die Doc Schnittstellen: + +SwExtTextInput* SwDoc::CreateExtTextInput( const SwPaM& rPam ) +{ + SwExtTextInput* pNew = new SwExtTextInput( rPam, pExtInputRing ); + if( !pExtInputRing ) + pExtInputRing = pNew; + pNew->SetMark(); + return pNew; +} + +void SwDoc::DeleteExtTextInput( SwExtTextInput* pDel ) +{ + if( pDel == pExtInputRing ) + { + if( pDel->GetNext() != pExtInputRing ) + pExtInputRing = (SwPaM*)pDel->GetNext(); + else + pExtInputRing = 0; + } + delete pDel; +} + +SwExtTextInput* SwDoc::GetExtTextInput( const SwNode& rNd, + xub_StrLen nCntntPos ) const +{ + SwExtTextInput* pRet = 0; + if( pExtInputRing ) + { + sal_uLong nNdIdx = rNd.GetIndex(); + SwExtTextInput* pTmp = (SwExtTextInput*)pExtInputRing; + do { + sal_uLong nPt = pTmp->GetPoint()->nNode.GetIndex(), + nMk = pTmp->GetMark()->nNode.GetIndex(); + xub_StrLen nPtCnt = pTmp->GetPoint()->nContent.GetIndex(), + nMkCnt = pTmp->GetMark()->nContent.GetIndex(); + + if( nPt < nMk || ( nPt == nMk && nPtCnt < nMkCnt )) + { + sal_uLong nTmp = nMk; nMk = nPt; nPt = nTmp; + nTmp = nMkCnt; nMkCnt = nPtCnt; nPtCnt = (xub_StrLen)nTmp; + } + + if( nMk <= nNdIdx && nNdIdx <= nPt && + ( STRING_NOTFOUND == nCntntPos || + ( nMkCnt <= nCntntPos && nCntntPos <= nPtCnt ))) + { + pRet = pTmp; + break; + } + } while( pExtInputRing != (pTmp = (SwExtTextInput*)pExtInputRing ) ); + } + return pRet; +} + +SwExtTextInput* SwDoc::GetExtTextInput() const +{ + ASSERT( !pExtInputRing || pExtInputRing == pExtInputRing->GetNext(), + "more then one InputEngine available" ); + return (SwExtTextInput*)pExtInputRing; +} + + diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx new file mode 100644 index 000000000000..c43e363e3a72 --- /dev/null +++ b/sw/source/core/doc/fmtcol.cxx @@ -0,0 +1,717 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <hintids.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <doc.hxx> // fuer GetAttrPool +#include <errhdl.hxx> +#include <fmtcol.hxx> +// --> OD 2006-11-22 #i71574# +#include <fmtcolfunc.hxx> +// <-- +#include <hints.hxx> +#include <calc.hxx> +#include <node.hxx> +#include <numrule.hxx> +#include <paratr.hxx> + +//--> #outlinelevel added by zhaojianwei +#ifndef _SFXINTITEM_HXX +#include <svl/intitem.hxx> +#endif +//<--end + +TYPEINIT1( SwTxtFmtColl, SwFmtColl ); +TYPEINIT1( SwGrfFmtColl, SwFmtColl ); +TYPEINIT1( SwConditionTxtFmtColl, SwTxtFmtColl ); +TYPEINIT1( SwCollCondition, SwClient ); + +SV_IMPL_PTRARR( SwFmtCollConditions, SwCollConditionPtr ); + +// --> OD 2008-03-04 #refactorlists# +namespace TxtFmtCollFunc +{ + + // --> OD 2006-11-22 #i71574# + void CheckTxtFmtCollForDeletionOfAssignmentToOutlineStyle( + SwFmt* pFmt, + const SwNumRuleItem* pNewNumRuleItem ) + { + SwTxtFmtColl* pTxtFmtColl = dynamic_cast<SwTxtFmtColl*>(pFmt); + if ( !pTxtFmtColl ) + { + #if OSL_DEBUG_LEVEL > 1 + ASSERT( false, + "<TxtFmtCollFunc::CheckTxtFmtCollFuncForDeletionOfAssignmentToOutlineStyle> - misuse of method - it's only for instances of <SwTxtFmtColl>" ); + #endif + return; + } + + // --> OD 2007-01-24 #i73790# + // if ( pTxtFmtColl->AssignedToListLevelOfOutlineStyle() ) + if ( !pTxtFmtColl->StayAssignedToListLevelOfOutlineStyle() && + pTxtFmtColl->IsAssignedToListLevelOfOutlineStyle() ) + // <-- + { + if ( !pNewNumRuleItem ) + { + pTxtFmtColl->GetItemState( RES_PARATR_NUMRULE, sal_False, (const SfxPoolItem**)&pNewNumRuleItem ); + } + if ( pNewNumRuleItem ) + { + String sNumRuleName = pNewNumRuleItem->GetValue(); + if ( sNumRuleName.Len() == 0 || + sNumRuleName != pTxtFmtColl->GetDoc()->GetOutlineNumRule()->GetName() ) + { + // delete assignment of paragraph style to list level of outline style. + pTxtFmtColl->DeleteAssignmentToListLevelOfOutlineStyle(); + } + } + } + } + // <-- + + SwNumRule* GetNumRule( SwTxtFmtColl& rTxtFmtColl ) + { + SwNumRule* pNumRule( 0 ); + + const SwNumRuleItem* pNumRuleItem( 0 ); + rTxtFmtColl.GetItemState( RES_PARATR_NUMRULE, sal_False, (const SfxPoolItem**)&pNumRuleItem ); + if ( pNumRuleItem ) + { + const String sNumRuleName = pNumRuleItem->GetValue(); + if ( sNumRuleName.Len() > 0 ) + { + pNumRule = rTxtFmtColl.GetDoc()->FindNumRulePtr( sNumRuleName ); + } + } + + return pNumRule; + } + + void AddToNumRule( SwTxtFmtColl& rTxtFmtColl ) + { + SwNumRule* pNumRule = GetNumRule( rTxtFmtColl ); + if ( pNumRule ) + { + pNumRule->AddParagraphStyle( rTxtFmtColl ); + } + } + + void RemoveFromNumRule( SwTxtFmtColl& rTxtFmtColl ) + { + SwNumRule* pNumRule = GetNumRule( rTxtFmtColl ); + if ( pNumRule ) + { + pNumRule->RemoveParagraphStyle( rTxtFmtColl ); + } + } +} // end of namespace TxtFmtCollFunc +// <-- + +/* + * SwTxtFmtColl TXT + */ + +void SwTxtFmtColl::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + if( GetDoc()->IsInDtor() ) + { + SwFmtColl::Modify( pOld, pNew ); + return; + } + + // --> OD 2006-06-16 #i66431# - adjust type of <bNewParent> + bool bNewParent( false ); + // <-- + SvxULSpaceItem *pNewULSpace = 0, *pOldULSpace = 0; + SvxLRSpaceItem *pNewLRSpace = 0, *pOldLRSpace = 0; + SvxFontHeightItem* aFontSizeArr[3] = {0,0,0}; + // --> OD 2006-10-17 #i70223# + const bool bAssignedToListLevelOfOutlineStyle(IsAssignedToListLevelOfOutlineStyle());//#outline level ,zhaojianwei + const SwNumRuleItem* pNewNumRuleItem( 0L ); + // <-- + + SwAttrSetChg *pNewChgSet = 0, *pOldChgSet = 0; + + switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ) + { + case RES_ATTRSET_CHG: + // nur neu berechnen, wenn nicht wir der "Versender" sind !!! + pNewChgSet = (SwAttrSetChg*)pNew; + pOldChgSet = (SwAttrSetChg*)pOld; + pNewChgSet->GetChgSet()->GetItemState( + RES_LR_SPACE, sal_False, (const SfxPoolItem**)&pNewLRSpace ); + pNewChgSet->GetChgSet()->GetItemState( + RES_UL_SPACE, sal_False, (const SfxPoolItem**)&pNewULSpace ); + pNewChgSet->GetChgSet()->GetItemState( RES_CHRATR_FONTSIZE, + sal_False, (const SfxPoolItem**)&(aFontSizeArr[0]) ); + pNewChgSet->GetChgSet()->GetItemState( RES_CHRATR_CJK_FONTSIZE, + sal_False, (const SfxPoolItem**)&(aFontSizeArr[1]) ); + pNewChgSet->GetChgSet()->GetItemState( RES_CHRATR_CTL_FONTSIZE, + sal_False, (const SfxPoolItem**)&(aFontSizeArr[2]) ); + // --> OD 2006-10-17 #i70223# + // --> OD 2007-12-19 #i84745# + // check, if attribute set is applied to this paragraph style + if ( bAssignedToListLevelOfOutlineStyle && + pNewChgSet->GetTheChgdSet() == &GetAttrSet() ) + { + pNewChgSet->GetChgSet()->GetItemState( RES_PARATR_NUMRULE, sal_False, + (const SfxPoolItem**)&pNewNumRuleItem ); + } + // <-- + + break; + + case RES_FMT_CHG: + if( GetAttrSet().GetParent() ) + { + const SfxItemSet* pParent = GetAttrSet().GetParent(); + pNewLRSpace = (SvxLRSpaceItem*)&pParent->Get( RES_LR_SPACE ); + pNewULSpace = (SvxULSpaceItem*)&pParent->Get( RES_UL_SPACE ); + aFontSizeArr[0] = (SvxFontHeightItem*)&pParent->Get( RES_CHRATR_FONTSIZE ); + aFontSizeArr[1] = (SvxFontHeightItem*)&pParent->Get( RES_CHRATR_CJK_FONTSIZE ); + aFontSizeArr[2] = (SvxFontHeightItem*)&pParent->Get( RES_CHRATR_CTL_FONTSIZE ); + // --> OD 2006-06-16 #i66431# + // modify has to be propagated, because of new parent format. + bNewParent = true; + // <-- + } + break; + + case RES_LR_SPACE: + pNewLRSpace = (SvxLRSpaceItem*)pNew; + break; + case RES_UL_SPACE: + pNewULSpace = (SvxULSpaceItem*)pNew; + break; + case RES_CHRATR_FONTSIZE: + aFontSizeArr[0] = (SvxFontHeightItem*)pNew; + break; + case RES_CHRATR_CJK_FONTSIZE: + aFontSizeArr[1] = (SvxFontHeightItem*)pNew; + break; + case RES_CHRATR_CTL_FONTSIZE: + aFontSizeArr[2] = (SvxFontHeightItem*)pNew; + break; + // --> OD 2006-10-17 #i70223# + case RES_PARATR_NUMRULE: + { + if ( bAssignedToListLevelOfOutlineStyle ) + { + pNewNumRuleItem = (SwNumRuleItem*)pNew; + } + } + default: + break; + } + + // --> OD 2006-10-17 #i70223# + if ( bAssignedToListLevelOfOutlineStyle && pNewNumRuleItem ) + { + TxtFmtCollFunc::CheckTxtFmtCollForDeletionOfAssignmentToOutlineStyle( + this, pNewNumRuleItem ); + } + // <-- + + int bWeiter = sal_True; + + // dann pruefe doch mal gegen die eigenen Attribute + if( pNewLRSpace && SFX_ITEM_SET == GetItemState( RES_LR_SPACE, sal_False, + (const SfxPoolItem**)&pOldLRSpace )) + { + int bChg = sal_False; + if( pOldLRSpace != pNewLRSpace ) // verhinder Rekursion (SetAttr!!) + { + SvxLRSpaceItem aNew( *pOldLRSpace ); + // wir hatten eine relative Angabe -> neu berechnen + if( 100 != aNew.GetPropLeft() ) + { + long nTmp = aNew.GetLeft(); // alten zum Vergleichen + aNew.SetLeft( pNewLRSpace->GetLeft(), aNew.GetPropLeft() ); + bChg |= nTmp != aNew.GetLeft(); + } + // wir hatten eine relative Angabe -> neu berechnen + if( 100 != aNew.GetPropRight() ) + { + long nTmp = aNew.GetRight(); // alten zum Vergleichen + aNew.SetRight( pNewLRSpace->GetRight(), aNew.GetPropRight() ); + bChg |= nTmp != aNew.GetRight(); + } + // wir hatten eine relative Angabe -> neu berechnen + if( 100 != aNew.GetPropTxtFirstLineOfst() ) + { + short nTmp = aNew.GetTxtFirstLineOfst(); // alten zum Vergleichen + aNew.SetTxtFirstLineOfst( pNewLRSpace->GetTxtFirstLineOfst(), + aNew.GetPropTxtFirstLineOfst() ); + bChg |= nTmp != aNew.GetTxtFirstLineOfst(); + } + if( bChg ) + { + SetFmtAttr( aNew ); + bWeiter = 0 != pOldChgSet || bNewParent; + } + // bei uns absolut gesetzt -> nicht weiter propagieren, es sei + // denn es wird bei uns gesetzt! + else if( pNewChgSet ) + bWeiter = pNewChgSet->GetTheChgdSet() == &GetAttrSet(); + } + } + + if( pNewULSpace && SFX_ITEM_SET == GetItemState( + RES_UL_SPACE, sal_False, (const SfxPoolItem**)&pOldULSpace ) && + pOldULSpace != pNewULSpace ) // verhinder Rekursion (SetAttr!!) + { + SvxULSpaceItem aNew( *pOldULSpace ); + int bChg = sal_False; + // wir hatten eine relative Angabe -> neu berechnen + if( 100 != aNew.GetPropUpper() ) + { + sal_uInt16 nTmp = aNew.GetUpper(); // alten zum Vergleichen + aNew.SetUpper( pNewULSpace->GetUpper(), aNew.GetPropUpper() ); + bChg |= nTmp != aNew.GetUpper(); + } + // wir hatten eine relative Angabe -> neu berechnen + if( 100 != aNew.GetPropLower() ) + { + sal_uInt16 nTmp = aNew.GetLower(); // alten zum Vergleichen + aNew.SetLower( pNewULSpace->GetLower(), aNew.GetPropLower() ); + bChg |= nTmp != aNew.GetLower(); + } + if( bChg ) + { + SetFmtAttr( aNew ); + bWeiter = 0 != pOldChgSet || bNewParent; + } + // bei uns absolut gesetzt -> nicht weiter propagieren, es sei + // denn es wird bei uns gesetzt! + else if( pNewChgSet ) + bWeiter = pNewChgSet->GetTheChgdSet() == &GetAttrSet(); + } + + + for( int nC = 0, nArrLen = sizeof(aFontSizeArr) / sizeof( aFontSizeArr[0]); + nC < nArrLen; ++nC ) + { + SvxFontHeightItem *pFSize = aFontSizeArr[ nC ], *pOldFSize; + if( pFSize && SFX_ITEM_SET == GetItemState( + pFSize->Which(), sal_False, (const SfxPoolItem**)&pOldFSize ) && + // verhinder Rekursion (SetAttr!!) + pFSize != pOldFSize ) + { + if( 100 == pOldFSize->GetProp() && + SFX_MAPUNIT_RELATIVE == pOldFSize->GetPropUnit() ) + { + // bei uns absolut gesetzt -> nicht weiter propagieren, es sei + // denn es wird bei uns gesetzt! + if( pNewChgSet ) + bWeiter = pNewChgSet->GetTheChgdSet() == &GetAttrSet(); + } + else + { + // wir hatten eine relative Angabe -> neu berechnen + sal_uInt32 nTmp = pOldFSize->GetHeight(); // alten zum Vergleichen + SvxFontHeightItem aNew(240 , 100, pFSize->Which()); + aNew.SetHeight( pFSize->GetHeight(), pOldFSize->GetProp(), + pOldFSize->GetPropUnit() ); + if( nTmp != aNew.GetHeight() ) + { + SetFmtAttr( aNew ); + bWeiter = 0 != pOldChgSet || bNewParent; + } + // bei uns absolut gesetzt -> nicht weiter propagieren, es sei + // denn es wird bei uns gesetzt! + else if( pNewChgSet ) + bWeiter = pNewChgSet->GetTheChgdSet() == &GetAttrSet(); + } + } + } + + if( bWeiter ) + SwFmtColl::Modify( pOld, pNew ); +} + +sal_Bool SwTxtFmtColl::IsAtDocNodeSet() const +{ + SwClientIter aIter( *(SwModify*)this ); + const SwNodes& rNds = GetDoc()->GetNodes(); + for( SwClient* pC = aIter.First(TYPE(SwCntntNode)); pC; pC = aIter.Next() ) + if( &((SwCntntNode*)pC)->GetNodes() == &rNds ) + return sal_True; + + return sal_False; +} + +// --> OD 2008-03-04 #refactorlists# +sal_Bool SwTxtFmtColl::SetFmtAttr( const SfxPoolItem& rAttr ) +{ + const bool bIsNumRuleItem = rAttr.Which() == RES_PARATR_NUMRULE; + if ( bIsNumRuleItem ) + { + TxtFmtCollFunc::RemoveFromNumRule( *this ); + } + + const sal_Bool bRet = SwFmtColl::SetFmtAttr( rAttr ); + + if ( bIsNumRuleItem ) + { + TxtFmtCollFunc::AddToNumRule( *this ); + } + + return bRet; +} + +sal_Bool SwTxtFmtColl::SetFmtAttr( const SfxItemSet& rSet ) +{ + const bool bIsNumRuleItemAffected = + rSet.GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET; + if ( bIsNumRuleItemAffected ) + { + TxtFmtCollFunc::RemoveFromNumRule( *this ); + } + + const sal_Bool bRet = SwFmtColl::SetFmtAttr( rSet ); + + if ( bIsNumRuleItemAffected ) + { + TxtFmtCollFunc::AddToNumRule( *this ); + } + + return bRet; +} + +sal_Bool SwTxtFmtColl::ResetFmtAttr( sal_uInt16 nWhich1, sal_uInt16 nWhich2 ) +{ + const bool bIsNumRuleItemAffected = + ( nWhich2 != 0 && nWhich2 > nWhich1 ) + ? ( nWhich1 <= RES_PARATR_NUMRULE && + RES_PARATR_NUMRULE <= nWhich2 ) + : nWhich1 == RES_PARATR_NUMRULE; + if ( bIsNumRuleItemAffected ) + { + TxtFmtCollFunc::RemoveFromNumRule( *this ); + } + + const sal_Bool bRet = SwFmtColl::ResetFmtAttr( nWhich1, nWhich2 ); + + return bRet; +} +// <-- + +// --> OD 2007-01-24 #i73790# +sal_uInt16 SwTxtFmtColl::ResetAllFmtAttr() +{ + const bool bOldState( mbStayAssignedToListLevelOfOutlineStyle ); + mbStayAssignedToListLevelOfOutlineStyle = true; + // --> OD 2008-12-16 #i70748# + // Outline level is no longer a member, it is a attribute now. + // Thus, it needs to be restored, if the paragraph style is assigned + // to the outline style + const int nAssignedOutlineStyleLevel = IsAssignedToListLevelOfOutlineStyle() + ? GetAssignedOutlineStyleLevel() + : -1; + // <-- + + sal_uInt16 nRet = SwFmtColl::ResetAllFmtAttr(); + + // --> OD 2008-12-16 #i70748# + if ( nAssignedOutlineStyleLevel != -1 ) + { + AssignToListLevelOfOutlineStyle( nAssignedOutlineStyleLevel ); + } + // <-- + + mbStayAssignedToListLevelOfOutlineStyle = bOldState; + + return nRet; +} +// <-- + +// --> OD 2008-02-13 #newlistlevelattrs# +bool SwTxtFmtColl::AreListLevelIndentsApplicable() const +{ + bool bAreListLevelIndentsApplicable( true ); + + if ( GetItemState( RES_PARATR_NUMRULE ) != SFX_ITEM_SET ) + { + // no list style applied to paragraph style + bAreListLevelIndentsApplicable = false; + } + else if ( GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET ) + { + // paragraph style has hard-set indent attributes + bAreListLevelIndentsApplicable = false; + } + else if ( GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET ) + { + // list style is directly applied to paragraph style and paragraph + // style has no hard-set indent attributes + bAreListLevelIndentsApplicable = true; + } + else + { + // list style is applied through one of the parent paragraph styles and + // paragraph style has no hard-set indent attributes + + // check parent paragraph styles + const SwTxtFmtColl* pColl = dynamic_cast<const SwTxtFmtColl*>(DerivedFrom()); + while ( pColl ) + { + if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, sal_False ) == SFX_ITEM_SET ) + { + // indent attributes found in the paragraph style hierarchy. + bAreListLevelIndentsApplicable = false; + break; + } + + if ( pColl->GetAttrSet().GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_SET ) + { + // paragraph style with the list style found and until now no + // indent attributes are found in the paragraph style hierarchy. + bAreListLevelIndentsApplicable = true; + break; + } + + pColl = dynamic_cast<const SwTxtFmtColl*>(pColl->DerivedFrom()); + ASSERT( pColl, + "<SwTxtFmtColl::AreListLevelIndentsApplicable()> - something wrong in paragraph style hierarchy. The applied list style is not found." ); + } + } + + return bAreListLevelIndentsApplicable; +} +// <-- + +//FEATURE::CONDCOLL + +SwCollCondition::SwCollCondition( SwTxtFmtColl* pColl, sal_uLong nMasterCond, + sal_uLong nSubCond ) + : SwClient( pColl ), nCondition( nMasterCond ) +{ + aSubCondition.nSubCondition = nSubCond; +} + + +SwCollCondition::SwCollCondition( SwTxtFmtColl* pColl, sal_uLong nMasterCond, + const String& rSubExp ) + : SwClient( pColl ), nCondition( nMasterCond ) +{ + if( USRFLD_EXPRESSION & nCondition ) + aSubCondition.pFldExpression = new String( rSubExp ); + else + aSubCondition.nSubCondition = 0; +} + + +SwCollCondition::SwCollCondition( const SwCollCondition& rCopy ) + : SwClient( (SwModify*)rCopy.GetRegisteredIn() ), nCondition( rCopy.nCondition ) +{ + if( USRFLD_EXPRESSION & rCopy.nCondition ) + aSubCondition.pFldExpression = new String( *rCopy.GetFldExpression() ); + else + aSubCondition.nSubCondition = rCopy.aSubCondition.nSubCondition; +} + + +SwCollCondition::~SwCollCondition() +{ + if( USRFLD_EXPRESSION & nCondition ) + delete aSubCondition.pFldExpression; +} + + +int SwCollCondition::operator==( const SwCollCondition& rCmp ) const +{ + int nRet = 0; + if( nCondition == rCmp.nCondition ) + { + if( USRFLD_EXPRESSION & nCondition ) + { + // in der SubCondition steht die Expression fuer das UserFeld + const String* pTmp = aSubCondition.pFldExpression; + if( !pTmp ) + pTmp = rCmp.aSubCondition.pFldExpression; + if( pTmp ) + { + SwTxtFmtColl* pColl = GetTxtFmtColl(); + if( !pColl ) + pColl = rCmp.GetTxtFmtColl(); + + if( pColl ) + { + SwCalc aCalc( *pColl->GetDoc() ); + nRet = 0 != aCalc.Calculate( *pTmp ).GetBool(); + } + } + } + else if( aSubCondition.nSubCondition == + rCmp.aSubCondition.nSubCondition ) + nRet = 1; + } + return nRet; +} + + +void SwCollCondition::SetCondition( sal_uLong nCond, sal_uLong nSubCond ) +{ + if( USRFLD_EXPRESSION & nCondition ) + delete aSubCondition.pFldExpression; + nCondition = nCond; + aSubCondition.nSubCondition = nSubCond; +} + + +SwConditionTxtFmtColl::~SwConditionTxtFmtColl() +{ +} + +const SwCollCondition* SwConditionTxtFmtColl::HasCondition( + const SwCollCondition& rCond ) const +{ + const SwCollCondition* pFnd = 0; + sal_uInt16 n; + + for( n = 0; n < aCondColls.Count(); ++n ) + if( *( pFnd = aCondColls[ n ]) == rCond ) + break; + + return n < aCondColls.Count() ? pFnd : 0; +} + + +void SwConditionTxtFmtColl::InsertCondition( const SwCollCondition& rCond ) +{ + for( sal_uInt16 n = 0; n < aCondColls.Count(); ++n ) + if( *aCondColls[ n ] == rCond ) + { + aCondColls.DeleteAndDestroy( n ); + break; + } + + // nicht gefunden -> als einfuegen + SwCollCondition* pNew = new SwCollCondition( rCond ); + aCondColls.Insert( pNew, aCondColls.Count() ); +} + + +sal_Bool SwConditionTxtFmtColl::RemoveCondition( const SwCollCondition& rCond ) +{ + sal_Bool bRet = sal_False; + for( sal_uInt16 n = 0; n < aCondColls.Count(); ++n ) + if( *aCondColls[ n ] == rCond ) + { + aCondColls.DeleteAndDestroy( n ); + bRet = sal_True; + } + + return bRet; +} + +void SwConditionTxtFmtColl::SetConditions( const SwFmtCollConditions& rCndClls ) +{ + // Kopiere noch die Bedingungen + // aber erst die alten loeschen! + if( aCondColls.Count() ) + aCondColls.DeleteAndDestroy( 0, aCondColls.Count() ); + SwDoc& rDoc = *GetDoc(); + for( sal_uInt16 n = 0; n < rCndClls.Count(); ++n ) + { + SwCollCondition* pFnd = rCndClls[ n ]; + SwTxtFmtColl* pTmpColl = pFnd->GetTxtFmtColl() + ? rDoc.CopyTxtColl( *pFnd->GetTxtFmtColl() ) + : 0; + SwCollCondition* pNew; + if( USRFLD_EXPRESSION & pFnd->GetCondition() ) + pNew = new SwCollCondition( pTmpColl, pFnd->GetCondition(), + *pFnd->GetFldExpression() ); + else + pNew = new SwCollCondition( pTmpColl, pFnd->GetCondition(), + pFnd->GetSubCondition() ); + aCondColls.Insert( pNew, n ); + } +} +//#outline level, zhaojianwei +void SwTxtFmtColl::SetAttrOutlineLevel( int nLevel) +{ + ASSERT( 0 <= nLevel && nLevel <= MAXLEVEL ,"SwTxtFmtColl: Level Out Of Range" ); + SetFmtAttr( SfxUInt16Item( RES_PARATR_OUTLINELEVEL, + static_cast<sal_uInt16>(nLevel) ) ); +} + +int SwTxtFmtColl::GetAttrOutlineLevel() const +{ + return ((const SfxUInt16Item &)GetFmtAttr(RES_PARATR_OUTLINELEVEL)).GetValue(); +} + +int SwTxtFmtColl::GetAssignedOutlineStyleLevel() const +{ + ASSERT( IsAssignedToListLevelOfOutlineStyle(), + "<SwTxtFmtColl::GetAssignedOutlineStyleLevel()> - misuse of method"); + return GetAttrOutlineLevel() - 1; +} + +void SwTxtFmtColl::AssignToListLevelOfOutlineStyle(const int nAssignedListLevel) +{ + mbAssignedToOutlineStyle = true; + SetAttrOutlineLevel(nAssignedListLevel+1); + + // --> OD 2009-03-18 #i100277# + SwClientIter aIter( *this ); + SwTxtFmtColl* pDerivedTxtFmtColl = + dynamic_cast<SwTxtFmtColl*>(aIter.First( TYPE( SwTxtFmtColl ) )); + while ( pDerivedTxtFmtColl != 0 ) + { + if ( !pDerivedTxtFmtColl->IsAssignedToListLevelOfOutlineStyle() ) + { + if ( pDerivedTxtFmtColl->GetItemState( RES_PARATR_NUMRULE, sal_False ) == SFX_ITEM_DEFAULT ) + { + SwNumRuleItem aItem(aEmptyStr); + pDerivedTxtFmtColl->SetFmtAttr( aItem ); + } + if ( pDerivedTxtFmtColl->GetItemState( RES_PARATR_OUTLINELEVEL, sal_False ) == SFX_ITEM_DEFAULT ) + { + pDerivedTxtFmtColl->SetAttrOutlineLevel( 0 ); + } + } + + pDerivedTxtFmtColl = dynamic_cast<SwTxtFmtColl*>(aIter.Next()); + } + // <-- +} + +void SwTxtFmtColl::DeleteAssignmentToListLevelOfOutlineStyle() +{ + mbAssignedToOutlineStyle = false; + ResetFmtAttr(RES_PARATR_OUTLINELEVEL); +} +//<-end,zhaojianwei + +//FEATURE::CONDCOLL diff --git a/sw/source/core/doc/ftnidx.cxx b/sw/source/core/doc/ftnidx.cxx new file mode 100644 index 000000000000..7395e7ae7449 --- /dev/null +++ b/sw/source/core/doc/ftnidx.cxx @@ -0,0 +1,398 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <txtftn.hxx> +#include <fmtftn.hxx> +#include <ftninfo.hxx> +#include <doc.hxx> +#include <ftnidx.hxx> +#include <ndtxt.hxx> +#include <ndindex.hxx> +#include <section.hxx> +#include <fmtftntx.hxx> +#include <rootfrm.hxx> + + +_SV_IMPL_SORTAR_ALG( _SwFtnIdxs, SwTxtFtnPtr ) +sal_Bool _SwFtnIdxs::Seek_Entry( const SwTxtFtnPtr rSrch, sal_uInt16* pFndPos ) const +{ + sal_uLong nIdx = _SwTxtFtn_GetIndex( rSrch ); + xub_StrLen nCntIdx = *rSrch->GetStart(); + + sal_uInt16 nO = Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + sal_uLong nFndIdx = _SwTxtFtn_GetIndex( (*this)[ nM ] ); + if( nFndIdx == nIdx && *(*this)[ nM ]->GetStart() == nCntIdx ) + { + if( pFndPos ) + *pFndPos = nM; + return sal_True; + } + else if( nFndIdx < nIdx || + (nFndIdx == nIdx && *(*this)[ nM ]->GetStart() < nCntIdx )) + nU = nM + 1; + else if( nM == 0 ) + { + if( pFndPos ) + *pFndPos = nU; + return sal_False; + } + else + nO = nM - 1; + } + } + if( pFndPos ) + *pFndPos = nU; + return sal_False; +} + + +void SwFtnIdxs::UpdateFtn( const SwNodeIndex& rStt ) +{ + if( !Count() ) + return; + + // besorge erstmal das Nodes-Array ueber den StartIndex der ersten Fussnote + SwDoc* pDoc = rStt.GetNode().GetDoc(); + if( pDoc->IsInReading() ) + return ; + SwTxtFtn* pTxtFtn; + + const SwEndNoteInfo& rEndInfo = pDoc->GetEndNoteInfo(); + const SwFtnInfo& rFtnInfo = pDoc->GetFtnInfo(); + + //Fuer normale Fussnoten werden Chapter- und Dokumentweise Nummerierung + //getrennt behandelt. Fuer Endnoten gibt es nur die Dokumentweise + //Nummerierung. + if( FTNNUM_CHAPTER == rFtnInfo.eNum ) + { + const SwOutlineNodes& rOutlNds = pDoc->GetNodes().GetOutLineNds(); + const SwNode* pCapStt = &pDoc->GetNodes().GetEndOfExtras(); + sal_uLong nCapEnd = pDoc->GetNodes().GetEndOfContent().GetIndex(); + if( rOutlNds.Count() ) + { + // suche den Start des Kapitels, in den rStt steht. + sal_uInt16 n; + + for( n = 0; n < rOutlNds.Count(); ++n ) + if( rOutlNds[ n ]->GetIndex() > rStt.GetIndex() ) + break; // gefunden + //else if( !rOutlNds[ n ]->GetTxtNode()->GetTxtColl()->GetOutlineLevel() ) //#outline level,zhaojianwei + else if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 ) //<-end,zhaojianwei + pCapStt = rOutlNds[ n ]; // Start eines neuen Kapitels + // dann suche jetzt noch das Ende vom Bereich + for( ; n < rOutlNds.Count(); ++n ) + //if( !rOutlNds[ n ]->GetTxtNode()->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei + if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 )//<-end,zhaojianwei + { + nCapEnd = rOutlNds[ n ]->GetIndex(); // Ende des gefundenen Kapitels + break; + } + } + + sal_uInt16 nPos, nFtnNo = 1; + if( SeekEntry( *pCapStt, &nPos ) && nPos ) + { + // gehe nach vorne bis der Index nicht mehr gleich ist + const SwNode* pCmpNd = &rStt.GetNode(); + while( nPos && pCmpNd == &((*this)[ --nPos ]->GetTxtNode()) ) + ; + ++nPos; + } + + if( nPos == Count() ) // nichts gefunden + return; + + if( !rOutlNds.Count() ) + nFtnNo = nPos+1; + + for( ; nPos < Count(); ++nPos ) + { + pTxtFtn = (*this)[ nPos ]; + if( pTxtFtn->GetTxtNode().GetIndex() >= nCapEnd ) + break; + + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.GetNumStr().Len() && !rFtn.IsEndNote() && + !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn )) + pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nFtnNo++, + &rFtn.GetNumStr() ); + } + } + + SwUpdFtnEndNtAtEnd aNumArr; + + // sal_Bool, damit hier auch bei Chapter-Einstellung die Endnoten + // durchlaufen. + const sal_Bool bEndNoteOnly = FTNNUM_DOC != rFtnInfo.eNum; + + sal_uInt16 nPos, nFtnNo = 1, nEndNo = 1; + sal_uLong nUpdNdIdx = rStt.GetIndex(); + for( nPos = 0; nPos < Count(); ++nPos ) + { + pTxtFtn = (*this)[ nPos ]; + if( nUpdNdIdx <= pTxtFtn->GetTxtNode().GetIndex() ) + break; + + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.GetNumStr().Len() ) + { + if( !aNumArr.ChkNumber( *pTxtFtn ) ) + { + if( pTxtFtn->GetFtn().IsEndNote() ) + nEndNo++; + else + nFtnNo++; + } + } + } + + // ab nPos bei allen FootNotes die Array-Nummer setzen + for( ; nPos < Count(); ++nPos ) + { + pTxtFtn = (*this)[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.GetNumStr().Len() ) + { + sal_uInt16 nSectNo = aNumArr.ChkNumber( *pTxtFtn ); + if( !nSectNo && ( rFtn.IsEndNote() || !bEndNoteOnly )) + nSectNo = rFtn.IsEndNote() + ? rEndInfo.nFtnOffset + nEndNo++ + : rFtnInfo.nFtnOffset + nFtnNo++; + + if( nSectNo ) + { + if( rFtn.IsEndNote() ) + pTxtFtn->SetNumber( nSectNo, &rFtn.GetNumStr() ); + else + pTxtFtn->SetNumber( nSectNo, &rFtn.GetNumStr() ); + } + } + } + // Pageweise wird vom MA erfuellt !! +} + + +void SwFtnIdxs::UpdateAllFtn() +{ + if( !Count() ) + return; + + // besorge erstmal das Nodes-Array ueber den StartIndex der + // ersten Fussnote + SwDoc* pDoc = (SwDoc*) (*this)[ 0 ]->GetTxtNode().GetDoc(); + SwTxtFtn* pTxtFtn; + const SwEndNoteInfo& rEndInfo = pDoc->GetEndNoteInfo(); + const SwFtnInfo& rFtnInfo = pDoc->GetFtnInfo(); + + SwUpdFtnEndNtAtEnd aNumArr; + + //Fuer normale Fussnoten werden Chapter- und Dokumentweise Nummerierung + //getrennt behandelt. Fuer Endnoten gibt es nur die Dokumentweise + //Nummerierung. + if( FTNNUM_CHAPTER == rFtnInfo.eNum ) + { + const SwOutlineNodes& rOutlNds = pDoc->GetNodes().GetOutLineNds(); + sal_uInt16 nNo = 1, // Nummer fuer die Fussnoten + nFtnIdx = 0; // Index in das FtnIdx-Array + for( sal_uInt16 n = 0; n < rOutlNds.Count(); ++n ) + { + //if( !rOutlNds[ n ]->GetTxtNode()->GetTxtColl()->GetOutlineLevel() )//#outline level,zhaojianwei + if ( rOutlNds[ n ]->GetTxtNode()->GetAttrOutlineLevel() == 1 )//<-end,zhaojianwei + { + sal_uLong nCapStt = rOutlNds[ n ]->GetIndex(); // Start eines neuen Kapitels + for( ; nFtnIdx < Count(); ++nFtnIdx ) + { + pTxtFtn = (*this)[ nFtnIdx ]; + if( pTxtFtn->GetTxtNode().GetIndex() >= nCapStt ) + break; + + // Endnoten nur Dokumentweise + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.IsEndNote() && !rFtn.GetNumStr().Len() && + !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn )) + pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nNo++, + &rFtn.GetNumStr() ); + } + if( nFtnIdx >= Count() ) + break; // ok alles geupdatet + nNo = 1; + } + } + + for( nNo = 1; nFtnIdx < Count(); ++nFtnIdx ) + { + //Endnoten nur Dokumentweise + pTxtFtn = (*this)[ nFtnIdx ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.IsEndNote() && !rFtn.GetNumStr().Len() && + !SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( *pTxtFtn )) + pTxtFtn->SetNumber( rFtnInfo.nFtnOffset + nNo++, + &rFtn.GetNumStr() ); + } + + } + + // sal_Bool, damit hier auch bei Chapter-Einstellung die Endnoten + // durchlaufen. + const sal_Bool bEndNoteOnly = FTNNUM_DOC != rFtnInfo.eNum; + sal_uInt16 nFtnNo = 0, nEndNo = 0; + for( sal_uInt16 nPos = 0; nPos < Count(); ++nPos ) + { + pTxtFtn = (*this)[ nPos ]; + const SwFmtFtn &rFtn = pTxtFtn->GetFtn(); + if( !rFtn.GetNumStr().Len() ) + { + sal_uInt16 nSectNo = aNumArr.ChkNumber( *pTxtFtn ); + if( !nSectNo && ( rFtn.IsEndNote() || !bEndNoteOnly )) + nSectNo = rFtn.IsEndNote() + ? rEndInfo.nFtnOffset + (++nEndNo) + : rFtnInfo.nFtnOffset + (++nFtnNo); + + if( nSectNo ) + { + if( rFtn.IsEndNote() ) + pTxtFtn->SetNumber( nSectNo, &rFtn.GetNumStr() ); + else + pTxtFtn->SetNumber( nSectNo, &rFtn.GetNumStr() ); + } + } + } + + if( pDoc->GetRootFrm() && FTNNUM_PAGE == rFtnInfo.eNum ) + pDoc->GetRootFrm()->UpdateFtnNums(); +} + +SwTxtFtn* SwFtnIdxs::SeekEntry( const SwNodeIndex& rPos, sal_uInt16* pFndPos ) const +{ + sal_uLong nIdx = rPos.GetIndex(); + + sal_uInt16 nO = Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + sal_uLong nNdIdx = _SwTxtFtn_GetIndex( (*this)[ nM ] ); + if( nNdIdx == nIdx ) + { + if( pFndPos ) + *pFndPos = nM; + return (*this)[ nM ]; + } + else if( nNdIdx < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pFndPos ) + *pFndPos = nU; + return 0; + } + else + nO = nM - 1; + } + } + if( pFndPos ) + *pFndPos = nU; + return 0; +} + +/* */ + +const SwSectionNode* SwUpdFtnEndNtAtEnd::FindSectNdWithEndAttr( + const SwTxtFtn& rTxtFtn ) +{ + sal_uInt16 nWh = static_cast<sal_uInt16>( rTxtFtn.GetFtn().IsEndNote() ? + RES_END_AT_TXTEND : RES_FTN_AT_TXTEND ); + sal_uInt16 nVal; + const SwSectionNode* pNd = rTxtFtn.GetTxtNode().FindSectionNode(); + while( pNd && FTNEND_ATTXTEND_OWNNUMSEQ != ( nVal = + ((const SwFmtFtnAtTxtEnd&)pNd->GetSection().GetFmt()-> + GetFmtAttr( nWh, sal_True )).GetValue() ) && + FTNEND_ATTXTEND_OWNNUMANDFMT != nVal ) + pNd = pNd->StartOfSectionNode()->FindSectionNode(); + + return pNd; +} + +sal_uInt16 SwUpdFtnEndNtAtEnd::GetNumber( const SwTxtFtn& rTxtFtn, + const SwSectionNode& rNd ) +{ + sal_uInt16 nRet = 0, nWh; + SvPtrarr* pArr; + SvUShorts* pNum; + if( rTxtFtn.GetFtn().IsEndNote() ) + { + pArr = &aEndSects; + pNum = &aEndNums; + nWh = RES_END_AT_TXTEND; + } + else + { + pArr = &aFtnSects; + pNum = &aFtnNums; + nWh = RES_FTN_AT_TXTEND; + } + void* pNd = (void*)&rNd; + + for( sal_uInt16 n = pArr->Count(); n; ) + if( pArr->GetObject( --n ) == pNd ) + { + nRet = ++pNum->GetObject( n ); + break; + } + + if( !nRet ) + { + pArr->Insert( pNd, pArr->Count() ); + nRet = ((SwFmtFtnEndAtTxtEnd&)rNd.GetSection().GetFmt()-> + GetFmtAttr( nWh )).GetOffset(); + ++nRet; + pNum->Insert( nRet, pNum->Count() ); + } + return nRet; +} + +sal_uInt16 SwUpdFtnEndNtAtEnd::ChkNumber( const SwTxtFtn& rTxtFtn ) +{ + const SwSectionNode* pSectNd = FindSectNdWithEndAttr( rTxtFtn ); + return pSectNd ? GetNumber( rTxtFtn, *pSectNd ) : 0; +} + + + + diff --git a/sw/source/core/doc/gctable.cxx b/sw/source/core/doc/gctable.cxx new file mode 100644 index 000000000000..607bb4f79c2e --- /dev/null +++ b/sw/source/core/doc/gctable.cxx @@ -0,0 +1,451 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <editeng/boxitem.hxx> +#include <tblrwcl.hxx> +#include <swtblfmt.hxx> + + +inline const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, sal_Bool bTop ) +{ + return bTop ? pBox->GetTop() : pBox->GetBottom(); +} + + +sal_Bool _SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrmFmt& rFmt ) +{ + const SvxBorderLine* pBrd; + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rFmt.GetItemState( RES_BOX, sal_True, &pItem ) && + 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetLeft() ) ) + { + if( *pBrdLn == *pBrd ) + bAnyBorderFnd = sal_True; + return sal_True; + } + return sal_False; +} + + + +sal_Bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine*& rpLine, void* pPara ) +{ + const SwTableBox* pBox = rpLine->GetTabBoxes()[ 0 ]; + return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara ); +} + +sal_Bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox*& rpBox, void* pPara ) +{ + sal_Bool bRet = sal_True; + if( rpBox->GetTabLines().Count() ) + { + for( sal_uInt16 n = 0, nLines = rpBox->GetTabLines().Count(); + n < nLines && bRet; ++n ) + { + const SwTableLine* pLine = rpBox->GetTabLines()[ n ]; + bRet = lcl_GCBorder_ChkBoxBrd_L( pLine, pPara ); + } + } + else + { + _SwGCBorder_BoxBrd* pBPara = (_SwGCBorder_BoxBrd*)pPara; + bRet = pBPara->CheckLeftBorderOfFormat( *rpBox->GetFrmFmt() ); + } + return bRet; +} + +sal_Bool lcl_GCBorder_GetLastBox_L( const SwTableLine*& rpLine, void* pPara ) +{ + const SwTableBoxes& rBoxes = rpLine->GetTabBoxes(); + const SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ]; + ::lcl_GCBorder_GetLastBox_B( pBox, pPara ); + return sal_True; +} + +sal_Bool lcl_GCBorder_GetLastBox_B( const SwTableBox*& rpBox, void* pPara ) +{ + SwTableLines& rLines = (SwTableLines&)rpBox->GetTabLines(); + if( rLines.Count() ) + rLines.ForEach( &lcl_GCBorder_GetLastBox_L, pPara ); + else + ((SwTableBoxes*)pPara)->Insert( rpBox, ((SwTableBoxes*)pPara)->Count() ); + return sal_True; +} + +// suche das "Ende" der vorgegebene BorderLine. Returnt wird die "Layout"Pos! +sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTblLineBoxes& rCollTLB, + const SvxBorderLine& rBrdLn, sal_uInt16& rStt, sal_Bool bTop ) +{ + sal_uInt16 nPos, nLastPos = 0; + for( sal_uInt16 nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt ) + { + const SfxPoolItem* pItem; + const SvxBorderLine* pBrd; + const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos ); + + if( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(RES_BOX,sal_True, &pItem ) + || 0 == ( pBrd = GetLineTB( (SvxBoxItem*)pItem, bTop )) + || !( *pBrd == rBrdLn )) + break; + nLastPos = nPos; + } + return nLastPos; +} + +inline const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox, + sal_Bool bTop, + const SfxPoolItem** ppItem ) +{ + return SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOX, sal_True, ppItem ) + ? GetLineTB( (SvxBoxItem*)*ppItem, bTop ) + : 0; +} + +void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes& rCollTLB, + sal_uInt16& rStt, sal_Bool bTop, + const SvxBorderLine& rLine, + const SfxPoolItem* pItem, + sal_uInt16 nEndPos, + SwShareBoxFmts* pShareFmts ) +{ + SwTableBox* pBox = (SwTableBox*)&rCollTLB.GetBox( rStt ); + sal_uInt16 nNextPos; + const SvxBorderLine* pLn = &rLine; + + do { + if( pLn && *pLn == rLine ) + { + SvxBoxItem aBox( *(SvxBoxItem*)pItem ); + if( bTop ) + aBox.SetLine( 0, BOX_LINE_TOP ); + else + aBox.SetLine( 0, BOX_LINE_BOTTOM ); + + if( pShareFmts ) + pShareFmts->SetAttr( *pBox, aBox ); + else + pBox->ClaimFrmFmt()->SetFmtAttr( aBox ); + } + + if( ++rStt >= rCollTLB.Count() ) + break; + + pBox = (SwTableBox*)&rCollTLB.GetBox( rStt, &nNextPos ); + if( nNextPos > nEndPos ) + break; + + pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem ); + + } while( sal_True ); +} + + +sal_Bool lcl_GC_Line_Border( const SwTableLine*& rpLine, void* pPara ) +{ + _SwGCLineBorder* pGCPara = (_SwGCLineBorder*)pPara; + + // zuerst die rechte Kante mit der linken Kante der naechsten Box + // innerhalb dieser Line + { + _SwGCBorder_BoxBrd aBPara; + const SvxBorderLine* pBrd; + const SfxPoolItem* pItem; + const SwTableBoxes& rBoxes = rpLine->GetTabBoxes(); + for( sal_uInt16 n = 0, nBoxes = rBoxes.Count() - 1; n < nBoxes; ++n ) + { + SwTableBoxes aBoxes; + { + const SwTableBox* pBox = rBoxes[ n ]; + if( pBox->GetSttNd() ) + aBoxes.Insert( pBox, 0 ); + else + lcl_GCBorder_GetLastBox_B( pBox, &aBoxes ); + } + + SwTableBox* pBox; + for( sal_uInt16 i = aBoxes.Count(); i; ) + if( SFX_ITEM_SET == (pBox = aBoxes[ --i ])->GetFrmFmt()-> + GetItemState( RES_BOX, sal_True, &pItem ) && + 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetRight() ) ) + { + aBPara.SetBorder( *pBrd ); + const SwTableBox* pNextBox = rBoxes[n+1]; + if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) && + aBPara.IsAnyBorderFound() ) + { + SvxBoxItem aBox( *(SvxBoxItem*)pItem ); + aBox.SetLine( 0, BOX_LINE_RIGHT ); + if( pGCPara->pShareFmts ) + pGCPara->pShareFmts->SetAttr( *pBox, aBox ); + else + pBox->ClaimFrmFmt()->SetFmtAttr( aBox ); + } + } + + aBoxes.Remove( 0, aBoxes.Count() ); + } + } + + // und jetzt die eigene untere Kante mit der nachfolgenden oberen Kante + if( !pGCPara->IsLastLine() ) + { + SwCollectTblLineBoxes aBottom( sal_False ); + SwCollectTblLineBoxes aTop( sal_True ); + + ::lcl_Line_CollectBox( rpLine, &aBottom ); + + const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ]; + ::lcl_Line_CollectBox( pNextLine, &aTop ); + + // dann entferne mal alle "doppelten" gleichen Lines + sal_uInt16 nBtmPos, nTopPos, + nSttBtm = 0, nSttTop = 0, + nEndBtm = aBottom.Count(), nEndTop = aTop.Count(); + + const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ), + *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); + const SfxPoolItem *pBtmItem = 0, *pTopItem = 0; + const SvxBorderLine *pBtmLine(0), *pTopLine(0); + sal_Bool bGetTopItem = sal_True, bGetBtmItem = sal_True; + + do { + if( bGetBtmItem ) + pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, sal_False, &pBtmItem ); + if( bGetTopItem ) + pTopLine = lcl_GCBorder_GetBorder( *pTopBox, sal_True, &pTopItem ); + + if( pTopLine && pBtmLine && *pTopLine == *pBtmLine ) + { + // dann kann einer entfernt werden, aber welche? + sal_uInt16 nSavSttBtm = nSttBtm, nSavSttTop = nSttTop; + sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom, + *pTopLine, nSttBtm, sal_False ); + if( !nBtmEndPos ) nBtmEndPos = nBtmPos; + sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop, + *pTopLine, nSttTop, sal_True ); + if( !nTopEndPos ) nTopEndPos = nTopPos; + + + if( nTopEndPos <= nBtmEndPos ) + { + // dann die TopBorder bis zur BottomEndPos loeschen + nSttTop = nSavSttTop; + if( nTopPos <= nBtmEndPos ) + lcl_GCBorder_DelBorder( aTop, --nSttTop, sal_True, + *pBtmLine, pTopItem, nBtmEndPos, + pGCPara->pShareFmts ); + else + nSttBtm = nSavSttBtm; + } + else + { + // sonst die BottomBorder bis zur TopEndPos loeschen + nSttBtm = nSavSttBtm; + if( nBtmPos <= nTopEndPos ) + lcl_GCBorder_DelBorder( aBottom, --nSttBtm, sal_False, + *pTopLine, pBtmItem, nTopEndPos, + pGCPara->pShareFmts ); + else + nSttTop = nSavSttTop; + } + nTopPos = nBtmPos; + } + + if( nTopPos == nBtmPos ) + { + if( nSttBtm >= nEndBtm || nSttTop >= nEndTop ) + break; + + pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ); + pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); + bGetTopItem = bGetBtmItem = sal_True; + } + else if( nTopPos < nBtmPos ) + { + if( nSttTop >= nEndTop ) + break; + pTopBox = &aTop.GetBox( nSttTop++, &nTopPos ); + bGetTopItem = sal_True; + bGetBtmItem = sal_False; + } + else + { + if( nSttBtm >= nEndBtm ) + break; + pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ); + bGetTopItem = sal_False; + bGetBtmItem = sal_True; + } + + } while( sal_True ); + } + + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_GC_Box_Border, pPara ); + + ++pGCPara->nLinePos; + + return sal_True; +} + +sal_Bool lcl_GC_Box_Border( const SwTableBox*& rpBox, void* pPara ) +{ + if( rpBox->GetTabLines().Count() ) + { + _SwGCLineBorder aPara( *rpBox ); + aPara.pShareFmts = ((_SwGCLineBorder*)pPara)->pShareFmts; + ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_GC_Line_Border, &aPara ); + } + return sal_True; +} + +struct _GCLinePara +{ + SwTableLines* pLns; + SwShareBoxFmts* pShareFmts; + + _GCLinePara( SwTableLines& rLns, _GCLinePara* pPara = 0 ) + : pLns( &rLns ), pShareFmts( pPara ? pPara->pShareFmts : 0 ) + {} +}; + +sal_Bool lcl_MergeGCBox( const SwTableBox*& rpTblBox, void* pPara ) +{ + SwTableBox*& rpBox = (SwTableBox*&)rpTblBox; + sal_uInt16 n, nLen = rpBox->GetTabLines().Count(); + if( nLen ) + { + // ACHTUNG: die Anzahl der Lines kann sich aendern! + _GCLinePara aPara( rpBox->GetTabLines(), (_GCLinePara*)pPara ); + for( n = 0; n < rpBox->GetTabLines().Count() && + lcl_MergeGCLine( *(rpBox->GetTabLines().GetData() + n), &aPara ); + ++n ) + ; + + if( 1 == rpBox->GetTabLines().Count() ) + { + // Box mit einer Line, dann verschiebe alle Boxen der Line + // hinter diese Box in der Parent-Line und loesche diese Box + SwTableLine* pInsLine = rpBox->GetUpper(); + SwTableLine* pCpyLine = rpBox->GetTabLines()[0]; + sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, rpBox ); + for( n = 0; n < pCpyLine->GetTabBoxes().Count(); ++n ) + pCpyLine->GetTabBoxes()[n]->SetUpper( pInsLine ); + + pInsLine->GetTabBoxes().Insert( &pCpyLine->GetTabBoxes(), nInsPos+1 ); + pCpyLine->GetTabBoxes().Remove( 0, n ); + // loesche alte die Box mit der Line + pInsLine->GetTabBoxes().DeleteAndDestroy( nInsPos ); + + return sal_False; // neu aufsetzen + } + } + return sal_True; +} + +sal_Bool lcl_MergeGCLine( const SwTableLine*& rpLine, void* pPara ) +{ + SwTableLine* pLn = (SwTableLine*)rpLine; + sal_uInt16 nLen = pLn->GetTabBoxes().Count(); + if( nLen ) + { + _GCLinePara* pGCPara = (_GCLinePara*)pPara; + while( 1 == nLen ) + { + // es gibt eine Box mit Lines + SwTableBox* pBox = pLn->GetTabBoxes()[0]; + if( !pBox->GetTabLines().Count() ) + break; + + SwTableLine* pLine = pBox->GetTabLines()[0]; + + // pLine wird zu der aktuellen, also der rpLine, + // die restlichen werden ins LinesArray hinter der akt. + // verschoben. + // Das LinesArray ist im pPara! + nLen = pBox->GetTabLines().Count(); + + SwTableLines& rLns = *pGCPara->pLns; + const SwTableLine* pTmp = pLn; + sal_uInt16 nInsPos = rLns.GetPos( pTmp ); + ASSERT( USHRT_MAX != nInsPos, "Line nicht gefunden!" ); + + SwTableBox* pUpper = pLn->GetUpper(); + + rLns.Remove( nInsPos, 1 ); // die Line dem aus Array loeschen + rLns.Insert( &pBox->GetTabLines(), nInsPos ); + + // JP 31.03.99: Bug 60000 - die Attribute der zu loeschenden + // Line an die "eingefuegten" uebertragen + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pLn->GetFrmFmt()->GetItemState( + RES_BACKGROUND, sal_True, &pItem )) + { + SwTableLines& rBoxLns = pBox->GetTabLines(); + for( sal_uInt16 nLns = 0; nLns < nLen; ++nLns ) + if( SFX_ITEM_SET != rBoxLns[ nLns ]->GetFrmFmt()-> + GetItemState( RES_BACKGROUND, sal_True )) + pGCPara->pShareFmts->SetAttr( *rBoxLns[ nLns ], *pItem ); + } + + pBox->GetTabLines().Remove( 0, nLen ); // Lines aus Array loeschen + + delete pLn; + + // Abhaengigkeit neu setzen + while( nLen-- ) + rLns[ nInsPos++ ]->SetUpper( pUpper ); + + pLn = pLine; // und neu setzen + nLen = pLn->GetTabBoxes().Count(); + } + + // ACHTUNG: die Anzahl der Boxen kann sich aendern! + for( nLen = 0; nLen < pLn->GetTabBoxes().Count(); ++nLen ) + if( !lcl_MergeGCBox( *(pLn->GetTabBoxes().GetData() + nLen ), pPara )) + --nLen; + } + return sal_True; +} + + // Struktur ein wenig aufraeumen +void SwTable::GCLines() +{ + // ACHTUNG: die Anzahl der Lines kann sich aendern! + _GCLinePara aPara( GetTabLines() ); + SwShareBoxFmts aShareFmts; + aPara.pShareFmts = &aShareFmts; + for( sal_uInt16 n = 0; n < GetTabLines().Count() && + lcl_MergeGCLine( *(GetTabLines().GetData() + n ), &aPara ); ++n ) + ; +} + + diff --git a/sw/source/core/doc/htmltbl.cxx b/sw/source/core/doc/htmltbl.cxx new file mode 100644 index 000000000000..9cef646cffce --- /dev/null +++ b/sw/source/core/doc/htmltbl.cxx @@ -0,0 +1,1903 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include "hintids.hxx" + +//#define TEST_DELAYED_RESIZE + +#ifdef TEST_DELAYED_RESIZE +#include <vcl/sound.hxx> +#endif +#ifndef _WRKWIN_HXX //autogen +#include <vcl/wrkwin.hxx> +#endif +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#include <sot/storage.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <frmfmt.hxx> +#include <docary.hxx> +#include "ndtxt.hxx" +#include "doc.hxx" +#include "swtable.hxx" +#include "rootfrm.hxx" +#include "docsh.hxx" +#include "flyfrm.hxx" +#include "poolfmt.hxx" +#include "viewsh.hxx" +#include "tabfrm.hxx" + +#include "htmltbl.hxx" +#include "ndindex.hxx" + +using namespace ::com::sun::star; + + +#define COLFUZZY 20 +#define MAX_TABWIDTH (USHRT_MAX - 2001) + + +/* */ + +class SwHTMLTableLayoutConstraints +{ + sal_uInt16 nRow; // Start-Zeile + sal_uInt16 nCol; // Start-Spalte + sal_uInt16 nColSpan; // COLSPAN der Zelle + + SwHTMLTableLayoutConstraints *pNext; // die naechste Bedingung + + sal_uLong nMinNoAlign, nMaxNoAlign; // Zwischenergebnisse AL-Pass 1 + +public: + + SwHTMLTableLayoutConstraints( sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRow, + sal_uInt16 nCol, sal_uInt16 nColSp ); + ~SwHTMLTableLayoutConstraints(); + + sal_uLong GetMinNoAlign() const { return nMinNoAlign; } + sal_uLong GetMaxNoAlign() const { return nMaxNoAlign; } + + SwHTMLTableLayoutConstraints *InsertNext( SwHTMLTableLayoutConstraints *pNxt ); + SwHTMLTableLayoutConstraints* GetNext() const { return pNext; } + + sal_uInt16 GetRow() const { return nRow; } + + sal_uInt16 GetColSpan() const { return nColSpan; } + sal_uInt16 GetColumn() const { return nCol; } +}; + +/* */ + +SwHTMLTableLayoutCnts::SwHTMLTableLayoutCnts( const SwStartNode *pSttNd, + SwHTMLTableLayout* pTab, + sal_Bool bNoBrTag, + SwHTMLTableLayoutCnts* pNxt ) : + pNext( pNxt ), pBox( 0 ), pTable( pTab ), pStartNode( pSttNd ), + nPass1Done( 0 ), nWidthSet( 0 ), bNoBreakTag( bNoBrTag ) +{} + +SwHTMLTableLayoutCnts::~SwHTMLTableLayoutCnts() +{ + delete pNext; + delete pTable; +} + +const SwStartNode *SwHTMLTableLayoutCnts::GetStartNode() const +{ + return pBox ? pBox->GetSttNd() : pStartNode; +} + + +/* */ + +SwHTMLTableLayoutCell::SwHTMLTableLayoutCell( SwHTMLTableLayoutCnts *pCnts, + sal_uInt16 nRSpan, sal_uInt16 nCSpan, + sal_uInt16 nWidth, sal_Bool bPrcWidth, + sal_Bool bNWrapOpt ) : + pContents( pCnts ), + nRowSpan( nRSpan ), nColSpan( nCSpan ), + nWidthOption( nWidth ), bPrcWidthOption( bPrcWidth ), + bNoWrapOption( bNWrapOpt ) +{} + +SwHTMLTableLayoutCell::~SwHTMLTableLayoutCell() +{ + if( nRowSpan==1 && nColSpan==1 ) + { + delete pContents; + } +} + +/* */ + +SwHTMLTableLayoutColumn::SwHTMLTableLayoutColumn( sal_uInt16 nWidth, + sal_Bool bRelWidth, + sal_Bool bLBorder ) : + nMinNoAlign(MINLAY), nMaxNoAlign(MINLAY), nAbsMinNoAlign(MINLAY), + nMin(0), nMax(0), + nAbsColWidth(0), nRelColWidth(0), + nWidthOption( nWidth ), bRelWidthOption( bRelWidth ), + bLeftBorder( bLBorder ) +{} + + +/* */ + +SwHTMLTableLayoutConstraints::SwHTMLTableLayoutConstraints( + sal_uLong nMin, sal_uLong nMax, sal_uInt16 nRw, sal_uInt16 nColumn, sal_uInt16 nColSp ): + nRow( nRw ), nCol( nColumn ), nColSpan( nColSp ), + pNext( 0 ), + nMinNoAlign( nMin ), nMaxNoAlign( nMax ) +{} + +SwHTMLTableLayoutConstraints::~SwHTMLTableLayoutConstraints() +{ + delete pNext; +} + +SwHTMLTableLayoutConstraints *SwHTMLTableLayoutConstraints::InsertNext( + SwHTMLTableLayoutConstraints *pNxt ) +{ + SwHTMLTableLayoutConstraints *pPrev = 0; + SwHTMLTableLayoutConstraints *pConstr = this; + while( pConstr ) + { + if( pConstr->GetRow() > pNxt->GetRow() || + pConstr->GetColumn() > pNxt->GetColumn() ) + break; + pPrev = pConstr; + pConstr = pConstr->GetNext(); + } + + if( pPrev ) + { + pNxt->pNext = pPrev->GetNext(); + pPrev->pNext = pNxt; + pConstr = this; + } + else + { + pNxt->pNext = this; + pConstr = pNxt; + } + + return pConstr; +} + +/* */ + +typedef SwHTMLTableLayoutColumn *SwHTMLTableLayoutColumnPtr; +typedef SwHTMLTableLayoutCell *SwHTMLTableLayoutCellPtr; + +SwHTMLTableLayout::SwHTMLTableLayout( + const SwTable * pSwTbl, + sal_uInt16 nRws, sal_uInt16 nCls, sal_Bool bColsOpt, sal_Bool bColTgs, + sal_uInt16 nWdth, sal_Bool bPrcWdth, sal_uInt16 nBorderOpt, + sal_uInt16 nCellPad, sal_uInt16 nCellSp, SvxAdjust eAdjust, + sal_uInt16 nLMargin, sal_uInt16 nRMargin, + sal_uInt16 nBWidth, sal_uInt16 nLeftBWidth, + sal_uInt16 nRightBWidth, + sal_uInt16 nInhLeftBWidth, sal_uInt16 nInhRightBWidth ) : + aColumns( new SwHTMLTableLayoutColumnPtr[nCls] ), + aCells( new SwHTMLTableLayoutCellPtr[nRws*nCls] ), + pSwTable( pSwTbl ), pLeftFillerBox( 0 ), pRightFillerBox( 0 ), + nMin( 0 ), nMax( 0 ), + nRows( nRws ), nCols( nCls ), + nLeftMargin( nLMargin ), nRightMargin( nRMargin ), + nInhAbsLeftSpace( 0 ), nInhAbsRightSpace( 0 ), + nRelLeftFill( 0 ), nRelRightFill( 0 ), + nRelTabWidth( 0 ), nWidthOption( nWdth ), + nCellPadding( nCellPad ), nCellSpacing( nCellSp ), nBorder( nBorderOpt ), + nLeftBorderWidth( nLeftBWidth ), nRightBorderWidth( nRightBWidth ), + nInhLeftBorderWidth( nInhLeftBWidth ), + nInhRightBorderWidth( nInhRightBWidth ), + nBorderWidth( nBWidth ), + nDelayedResizeAbsAvail( 0 ), nLastResizeAbsAvail( 0 ), + nPass1Done( 0 ), nWidthSet( 0 ), eTableAdjust( eAdjust ), + bColsOption( bColsOpt ), bColTags( bColTgs ), + bPrcWidthOption( bPrcWdth ), bUseRelWidth( sal_False ), + bMustResize( sal_True ), bExportable( sal_True ), bBordersChanged( sal_False ), + bMustNotResize( sal_False ), bMustNotRecalc( sal_False ) +{ + aResizeTimer.SetTimeoutHdl( STATIC_LINK( this, SwHTMLTableLayout, + DelayedResize_Impl ) ); +} + +SwHTMLTableLayout::~SwHTMLTableLayout() +{ + sal_uInt16 i; + + for( i = 0; i < nCols; i++ ) + delete aColumns[i]; + delete[] aColumns; + + sal_uInt16 nCount = nRows*nCols; + for( i=0; i<nCount; i++ ) + delete aCells[i]; + delete[] aCells; +} + +// Die Breiten der Umrandung werden zunaechst wie in Netscape berechnet: +// Aussere Umrandung: BORDER + CELLSPACING + CELLPADDING +// Innere Umrandung: CELLSPACING + CELLPADDING +// Allerdings wird die Breite der Umrandung im SW trotzdem beachtet, wenn +// bSwBorders gesetzt ist, damit nicht faellschlich umgebrochen wird. +// MIB 27.6.97: Dabei muss auch der Abstand zum Inhalt berueckichtigt werden, +// und zwar auch dann, wenn wenn nur die gegenueberliegende Seite +// eine Umrandung hat. +sal_uInt16 SwHTMLTableLayout::GetLeftCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, + sal_Bool bSwBorders ) const +{ + sal_uInt16 nSpace = nCellSpacing + nCellPadding; + + if( nCol == 0 ) + { + nSpace = nSpace + nBorder; + + if( bSwBorders && nSpace < nLeftBorderWidth ) + nSpace = nLeftBorderWidth; + } + else if( bSwBorders ) + { + if( GetColumn(nCol)->HasLeftBorder() ) + { + if( nSpace < nBorderWidth ) + nSpace = nBorderWidth; + } + else if( nCol+nColSpan == nCols && nRightBorderWidth && + nSpace < MIN_BORDER_DIST ) + { + ASSERT( !nCellPadding, "GetLeftCellSpace: CELLPADDING!=0" ); + // Wenn die Gegenueberliegende Seite umrandet ist muessen + // wir zumindest den minimalen Abstand zum Inhalt + // beruecksichtigen. (Koennte man zusaetzlich auch an + // nCellPadding festmachen.) + nSpace = MIN_BORDER_DIST; + } + } + + return nSpace; +} + +sal_uInt16 SwHTMLTableLayout::GetRightCellSpace( sal_uInt16 nCol, sal_uInt16 nColSpan, + sal_Bool bSwBorders ) const +{ + sal_uInt16 nSpace = nCellPadding; + + if( nCol+nColSpan == nCols ) + { + nSpace += nBorder + nCellSpacing; + if( bSwBorders && nSpace < nRightBorderWidth ) + nSpace = nRightBorderWidth; + } + else if( bSwBorders && GetColumn(nCol)->HasLeftBorder() && + nSpace < MIN_BORDER_DIST ) + { + ASSERT( !nCellPadding, "GetRightCellSpace: CELLPADDING!=0" ); + // Wenn die Gegenueberliegende Seite umrandet ist muessen + // wir zumindest den minimalen Abstand zum Inhalt + // beruecksichtigen. (Koennte man zusaetzlich auch an + // nCellPadding festmachen.) + nSpace = MIN_BORDER_DIST; + } + + return nSpace; +} + +void SwHTMLTableLayout::AddBorderWidth( sal_uLong &rMin, sal_uLong &rMax, + sal_uLong &rAbsMin, + sal_uInt16 nCol, sal_uInt16 nColSpan, + sal_Bool bSwBorders ) const +{ + sal_uLong nAdd = GetLeftCellSpace( nCol, nColSpan, bSwBorders ) + + GetRightCellSpace( nCol, nColSpan, bSwBorders ); + + rMin += nAdd; + rMax += nAdd; + rAbsMin += nAdd; +} + +void SwHTMLTableLayout::SetBoxWidth( SwTableBox *pBox, sal_uInt16 nCol, + sal_uInt16 nColSpan ) const +{ + SwFrmFmt *pFrmFmt = pBox->GetFrmFmt(); + + // die Breite der Box berechnen + SwTwips nFrmWidth = 0; + while( nColSpan-- ) + nFrmWidth += GetColumn( nCol++ )->GetRelColWidth(); + + // und neu setzen + + pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nFrmWidth, 0 )); +} + +void SwHTMLTableLayout::GetAvail( sal_uInt16 nCol, sal_uInt16 nColSpan, + sal_uInt16& rAbsAvail, sal_uInt16& rRelAvail ) const +{ + rAbsAvail = 0; + rRelAvail = 0; + for( sal_uInt16 i=nCol; i<nCol+nColSpan;i++ ) + { + const SwHTMLTableLayoutColumn *pColumn = GetColumn(i); + rAbsAvail = rAbsAvail + pColumn->GetAbsColWidth(); + rRelAvail = rRelAvail + pColumn->GetRelColWidth(); + } +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByVisArea( const SwDoc& rDoc ) +{ + ViewShell *pVSh = 0; + rDoc.GetEditShell( &pVSh ); + if( pVSh ) + { + return (sal_uInt16)pVSh->GetBrowseWidth(); + } + + return 0; +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidth( const SwDoc& rDoc ) +{ + // Wenn ein Layout da ist, koennen wir die Breite dort herholen. + const SwRootFrm *pRootFrm = rDoc.GetRootFrm(); + if( pRootFrm ) + { + const SwFrm *pPageFrm = pRootFrm->GetLower(); + if( pPageFrm ) + return (sal_uInt16)pPageFrm->Prt().Width(); + } + + // --> OD 2010-05-12 #i91658# + // Assertion removed which state that no browse width is available. + // Investigation reveals that all calls can handle the case that no browse + // width is provided. + return GetBrowseWidthByVisArea( rDoc ); + // <-- +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTabFrm( + const SwTabFrm& rTabFrm ) const +{ + SwTwips nWidth = 0; + + const SwFrm *pUpper = rTabFrm.GetUpper(); + if( MayBeInFlyFrame() && pUpper->IsFlyFrm() && + ((const SwFlyFrm *)pUpper)->GetAnchorFrm() ) + { + // Wenn die Tabelle in einem selbst angelegten Rahmen steht, dann ist + // die Breite Ankers und nicht die Breite Rahmens von Bedeutung. + // Bei Absatz-gebundenen Rahmen werden Absatz-Einzuege nicht beachtet. + const SwFrm *pAnchor = ((const SwFlyFrm *)pUpper)->GetAnchorFrm(); + if( pAnchor->IsTxtFrm() ) + nWidth = pAnchor->Frm().Width(); + else + nWidth = pAnchor->Prt().Width(); + } + else + { + nWidth = pUpper->Prt().Width(); + } + + SwTwips nUpperDummy = 0; + long nRightOffset = 0, + nLeftOffset = 0; + rTabFrm.CalcFlyOffsets( nUpperDummy, nLeftOffset, nRightOffset ); + nWidth -= (nLeftOffset + nRightOffset); + + return nWidth < USHRT_MAX ? static_cast<sal_uInt16>(nWidth) : USHRT_MAX; +} + +sal_uInt16 SwHTMLTableLayout::GetBrowseWidthByTable( const SwDoc& rDoc ) const +{ + sal_uInt16 nBrowseWidth = 0; + SwClientIter aIter( *(SwModify*)pSwTable->GetFrmFmt() ); + SwClient* pCli = aIter.First( TYPE( SwTabFrm )); + if( pCli ) + { + nBrowseWidth = GetBrowseWidthByTabFrm( *(SwTabFrm*)pCli ); + } + else + { + nBrowseWidth = SwHTMLTableLayout::GetBrowseWidth( rDoc ); + } + + return nBrowseWidth; +} + +const SwStartNode *SwHTMLTableLayout::GetAnyBoxStartNode() const +{ + const SwStartNode *pBoxSttNd; + + const SwTableBox* pBox = pSwTable->GetTabLines()[0]->GetTabBoxes()[0]; + while( 0 == (pBoxSttNd = pBox->GetSttNd()) ) + { + ASSERT( pBox->GetTabLines().Count() > 0, + "Box ohne Start-Node und Lines" ); + ASSERT( pBox->GetTabLines()[0]->GetTabBoxes().Count() > 0, + "Line ohne Boxen" ); + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + } + + return pBoxSttNd; +} + +SwFrmFmt *SwHTMLTableLayout::FindFlyFrmFmt() const +{ + const SwTableNode *pTblNd = GetAnyBoxStartNode()->FindTableNode(); + ASSERT( pTblNd, "Kein Table-Node?" ); + return pTblNd->GetFlyFmt(); +} + +static void lcl_GetMinMaxSize( sal_uLong& rMinNoAlignCnts, sal_uLong& rMaxNoAlignCnts, + sal_uLong& rAbsMinNoAlignCnts, +#ifdef FIX41370 + sal_Bool& rHR, +#endif + SwTxtNode *pTxtNd, sal_uLong nIdx, sal_Bool bNoBreak ) +{ + pTxtNd->GetMinMaxSize( nIdx, rMinNoAlignCnts, rMaxNoAlignCnts, + rAbsMinNoAlignCnts ); + ASSERT( rAbsMinNoAlignCnts <= rMinNoAlignCnts, + "GetMinMaxSize: absmin > min" ); + ASSERT( rMinNoAlignCnts <= rMaxNoAlignCnts, + "GetMinMaxSize: max > min" ); + + //Bei einen <PRE>-Absatz entspricht die maximale Breite der + // minimalen breite + const SwFmtColl *pColl = &pTxtNd->GetAnyFmtColl(); + while( pColl && !pColl->IsDefault() && + (USER_FMT & pColl->GetPoolFmtId()) ) + { + pColl = (const SwFmtColl *)pColl->DerivedFrom(); + } + + // <NOBR> in der gesamten Zelle bezieht sich auf Text, aber nicht + // auf Tabellen. Netscape beruecksichtigt dies nur fuer Grafiken. + if( (pColl && RES_POOLCOLL_HTML_PRE==pColl->GetPoolFmtId()) || bNoBreak ) + { + rMinNoAlignCnts = rMaxNoAlignCnts; + rAbsMinNoAlignCnts = rMaxNoAlignCnts; + } +#ifdef FIX41370 + else if( pColl && RES_POOLCOLL_HTML_HR==pColl->GetPoolFmtId() ) + { + rHR |= !pTxtNd->HasSwAttrSet() || + SFX_ITEM_SET != pTxtNd->GetpSwAttrSet() + ->GetItemState( RES_LR_SPACE, sal_False ); + } +#endif +} + +void SwHTMLTableLayout::AutoLayoutPass1() +{ + nPass1Done++; + + ClearPass1Info(); + + sal_Bool bFixRelWidths = sal_False; + sal_uInt16 i; + + SwHTMLTableLayoutConstraints *pConstraints = 0; + + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + pColumn->ClearPass1Info( !HasColTags() ); + sal_uInt16 nMinColSpan = USHRT_MAX; // Spaltenzahl, auf die sich dir + // berechnete Breite bezieht + sal_uInt16 nColSkip = USHRT_MAX; // Wie viele Spalten muessen + // uebersprungen werden + + for( sal_uInt16 j=0; j<nRows; j++ ) + { + SwHTMLTableLayoutCell *pCell = GetCell(j,i); + SwHTMLTableLayoutCnts *pCnts = pCell->GetContents(); + + // fix #31488#: Zum Ermitteln der naechsten zu berechnenden + // Spalte muessen alle Zeilen herangezogen werden + sal_uInt16 nColSpan = pCell->GetColSpan(); + if( nColSpan < nColSkip ) + nColSkip = nColSpan; + + if( !pCnts || (pCnts && !pCnts->IsPass1Done(nPass1Done)) ) + { + // die Zelle ist leer oder ihr Inhalt wurde nich nicht + // bearbeitet + if( nColSpan < nMinColSpan ) + nMinColSpan = nColSpan; + + sal_uLong nMinNoAlignCell = 0; + sal_uLong nMaxNoAlignCell = 0; + sal_uLong nAbsMinNoAlignCell = 0; + sal_uLong nMaxTableCell = 0; + sal_uLong nAbsMinTableCell = 0; +#ifdef FIX41370 + sal_Bool bHR = sal_False; +#endif + + while( pCnts ) + { + const SwStartNode *pSttNd = pCnts->GetStartNode(); + if( pSttNd ) + { + const SwDoc *pDoc = pSttNd->GetDoc(); + sal_uLong nIdx = pSttNd->GetIndex(); + while( !(pDoc->GetNodes()[nIdx])->IsEndNode() ) + { + SwTxtNode *pTxtNd = (pDoc->GetNodes()[nIdx])->GetTxtNode(); + if( pTxtNd ) + { + sal_uLong nMinNoAlignCnts = 0; + sal_uLong nMaxNoAlignCnts = 0; + sal_uLong nAbsMinNoAlignCnts = 0; + + lcl_GetMinMaxSize( nMinNoAlignCnts, + nMaxNoAlignCnts, + nAbsMinNoAlignCnts, +#ifdef FIX41370 + bHR, +#endif + pTxtNd, nIdx, + pCnts->HasNoBreakTag() ); + + if( nMinNoAlignCnts > nMinNoAlignCell ) + nMinNoAlignCell = nMinNoAlignCnts; + if( nMaxNoAlignCnts > nMaxNoAlignCell ) + nMaxNoAlignCell = nMaxNoAlignCnts; + if( nAbsMinNoAlignCnts > nAbsMinNoAlignCell ) + nAbsMinNoAlignCell = nAbsMinNoAlignCnts; + } + else + { + SwTableNode *pTabNd = (pDoc->GetNodes()[nIdx])->GetTableNode(); + if( pTabNd ) + { + SwHTMLTableLayout *pChild = pTabNd->GetTable().GetHTMLTableLayout(); + if( pChild ) + { + pChild->AutoLayoutPass1(); + sal_uLong nMaxTableCnts = pChild->nMax; + sal_uLong nAbsMinTableCnts = pChild->nMin; + + // Eine feste Tabellen-Breite wird als Minimum + // und Maximum gleichzeitig uebernommen + if( !pChild->bPrcWidthOption && pChild->nWidthOption ) + { + sal_uLong nTabWidth = pChild->nWidthOption; + if( nTabWidth >= nAbsMinTableCnts ) + { + nMaxTableCnts = nTabWidth; + nAbsMinTableCnts = nTabWidth; + } + else + { + nMaxTableCnts = nAbsMinTableCnts; + } + } + + if( nMaxTableCnts > nMaxTableCell ) + nMaxTableCell = nMaxTableCnts; + if( nAbsMinTableCnts > nAbsMinTableCell ) + nAbsMinTableCell = nAbsMinTableCnts; + } + nIdx = pTabNd->EndOfSectionNode()->GetIndex(); + } + } + nIdx++; + } + } + else + { + ASSERT( !this, "Sub tables in HTML import?" ) + SwHTMLTableLayout *pChild = pCnts->GetTable(); + pChild->AutoLayoutPass1(); + sal_uLong nMaxTableCnts = pChild->nMax; + sal_uLong nAbsMinTableCnts = pChild->nMin; + + // Eine feste Tabellen-Breite wird als Minimum + // und Maximum gleichzeitig uebernommen + if( !pChild->bPrcWidthOption && pChild->nWidthOption ) + { + sal_uLong nTabWidth = pChild->nWidthOption; + if( nTabWidth >= nAbsMinTableCnts ) + { + nMaxTableCnts = nTabWidth; + nAbsMinTableCnts = nTabWidth; + } + else + { + nMaxTableCnts = nAbsMinTableCnts; + } + } + + if( nMaxTableCnts > nMaxTableCell ) + nMaxTableCell = nMaxTableCnts; + if( nAbsMinTableCnts > nAbsMinTableCell ) + nAbsMinTableCell = nAbsMinTableCnts; + } + pCnts->SetPass1Done( nPass1Done ); + pCnts = pCnts->GetNext(); + } + +// War frueher hinter AddBorderWidth + // Wenn die Breite einer Tabelle in der Zelle breiter ist als + // das, was wir fuer sonstigen Inhalt berechnet haben, mussen + // wir die Breite der Tabelle nutzen + if( nMaxTableCell > nMaxNoAlignCell ) + nMaxNoAlignCell = nMaxTableCell; + if( nAbsMinTableCell > nAbsMinNoAlignCell ) + { + nAbsMinNoAlignCell = nAbsMinTableCell; + if( nMinNoAlignCell < nAbsMinNoAlignCell ) + nMinNoAlignCell = nAbsMinNoAlignCell; + if( nMaxNoAlignCell < nMinNoAlignCell ) + nMaxNoAlignCell = nMinNoAlignCell; + } +// War frueher hinter AddBorderWidth + + sal_Bool bRelWidth = pCell->IsPrcWidthOption(); + sal_uInt16 nWidth = pCell->GetWidthOption(); + + // Eine NOWRAP-Option bezieht sich auf Text und auf + // Tabellen, wird aber bei fester Zellenbreite + // nicht uebernommen. Stattdessen wirkt die angegebene + // Zellenbreite wie eine Mindestbreite. + if( pCell->HasNoWrapOption() ) + { + if( nWidth==0 || bRelWidth ) + { + nMinNoAlignCell = nMaxNoAlignCell; + nAbsMinNoAlignCell = nMaxNoAlignCell; + } + else + { + if( nWidth>nMinNoAlignCell ) + nMinNoAlignCell = nWidth; + if( nWidth>nAbsMinNoAlignCell ) + nAbsMinNoAlignCell = nWidth; + } + } +#ifdef FIX41370 + else if( bHR && nWidth>0 && !bRelWidth ) + { + // Ein kleiner Hack, um einen Bug in Netscape 4.0 + // nachzubilden (siehe #41370#). Wenn eine Zelle eine + // fixe Breite besitzt und gleichzeitig ein HR, wird + // sie nie schmaler als die angegebene Breite. + // (Genaugenomen scheint die Zelle nie schmaler zu werden + // als die HR-Linie, denn wenn man fuer die Linie eine + // Breite angibt, die breiter ist als die der Zelle, dann + // wird die Zelle so breit wie die Linie. Das bekommen wir + // natuerlich nicht hin.) + if( nWidth>nMinNoAlignCell ) + nMinNoAlignCell = nWidth; + if( nWidth>nAbsMinNoAlignCell ) + nAbsMinNoAlignCell = nWidth; + } +#endif + + // Mindestbreite fuer Inhalt einhalten + if( nMinNoAlignCell < MINLAY ) + nMinNoAlignCell = MINLAY; + if( nMaxNoAlignCell < MINLAY ) + nMaxNoAlignCell = MINLAY; + if( nAbsMinNoAlignCell < MINLAY ) + nAbsMinNoAlignCell = MINLAY; + + // Umrandung und Abstand zum Inhalt beachten. + AddBorderWidth( nMinNoAlignCell, nMaxNoAlignCell, + nAbsMinNoAlignCell, i, nColSpan ); + + if( 1==nColSpan ) + { + // die Werte direkt uebernehmen + pColumn->MergeMinMaxNoAlign( nMinNoAlignCell, + nMaxNoAlignCell, + nAbsMinNoAlignCell ); + + // bei den WIDTH angaben gewinnt die breiteste + if( !HasColTags() ) + pColumn->MergeCellWidthOption( nWidth, bRelWidth ); + } + else + { + // die Angaben erst am Ende, und zwar zeilenweise von + // links nach rechts bearbeiten + + // Wann welche Werte wie uebernommen werden ist weiter + // unten erklaert. + if( !HasColTags() && nWidth && !bRelWidth ) + { + sal_uLong nAbsWidth = nWidth, nDummy = 0, nDummy2 = 0; + AddBorderWidth( nAbsWidth, nDummy, nDummy2, + i, nColSpan, sal_False ); + + if( nAbsWidth >= nMinNoAlignCell ) + { + nMaxNoAlignCell = nAbsWidth; + if( HasColsOption() ) + nMinNoAlignCell = nAbsWidth; + } + else if( nAbsWidth >= nAbsMinNoAlignCell ) + { + nMaxNoAlignCell = nAbsWidth; + nMinNoAlignCell = nAbsWidth; + } + else + { + nMaxNoAlignCell = nAbsMinNoAlignCell; + nMinNoAlignCell = nAbsMinNoAlignCell; + } + } + else if( HasColsOption() || HasColTags() ) + nMinNoAlignCell = nAbsMinNoAlignCell; + + SwHTMLTableLayoutConstraints *pConstr = + new SwHTMLTableLayoutConstraints( nMinNoAlignCell, + nMaxNoAlignCell, j, i, nColSpan ); + if( pConstraints ) + pConstraints = pConstraints->InsertNext( pConstr ); + else + pConstraints = pConstr; + } + } + } + + ASSERT( nMinColSpan>0 && nColSkip>0 && nColSkip <= nMinColSpan, + "Layout Pass 1: Da werden Spalten vergessen!" ); + ASSERT( nMinColSpan!=USHRT_MAX, + "Layout Pass 1: unnoetiger Schleifendurchlauf oder Bug" ); + + if( 1==nMinColSpan ) + { + // es gibt Zellen mit COLSPAN 1 und demnach auch sinnvolle + // Werte in pColumn + + // Werte anhand folgender Tabelle (Netscape 4.0 pv 3) uebernehmen: + // + // WIDTH: kein COLS COLS + // + // keine min = min min = absmin + // max = max max = max + // + // >= min min = min min = width + // max = width max = width + // + // >= absmin min = wdith(*) min = width + // max = width max = width + // + // < absmin min = absmin min = absmin + // max = absmin max = absmin + // + // (*) Netscape benutzt hier die Mindestbreite ohne einen + // Umbruch vor der letzten Grafik. Haben wir (noch?) nicht, + // also belassen wir es bei width.^ + + if( pColumn->GetWidthOption() && !pColumn->IsRelWidthOption() ) + { + // absolute Breiten als Minimal- und Maximalbreite + // uebernehmen. + sal_uLong nAbsWidth = pColumn->GetWidthOption(); + sal_uLong nDummy = 0, nDummy2 = 0; + AddBorderWidth( nAbsWidth, nDummy, nDummy2, i, 1, sal_False ); + + if( nAbsWidth >= pColumn->GetMinNoAlign() ) + { + pColumn->SetMinMax( HasColsOption() ? nAbsWidth + : pColumn->GetMinNoAlign(), + nAbsWidth ); + } + else if( nAbsWidth >= pColumn->GetAbsMinNoAlign() ) + { + pColumn->SetMinMax( nAbsWidth, nAbsWidth ); + } + else + { + pColumn->SetMinMax( pColumn->GetAbsMinNoAlign(), + pColumn->GetAbsMinNoAlign() ); + } + } + else + { + pColumn->SetMinMax( HasColsOption() ? pColumn->GetAbsMinNoAlign() + : pColumn->GetMinNoAlign(), + pColumn->GetMaxNoAlign() ); + } + } + else if( USHRT_MAX!=nMinColSpan ) + { + // kann irgendwas !=0 sein, weil es durch die Constraints + // angepasst wird. + pColumn->SetMinMax( MINLAY, MINLAY ); + + // die naechsten Spalten muessen nicht bearbeitet werden + i += (nColSkip-1); + } + + nMin += pColumn->GetMin(); + nMax += pColumn->GetMax(); + bFixRelWidths |= pColumn->IsRelWidthOption(); + } + + // jetzt noch die Constrains verarbeiten + SwHTMLTableLayoutConstraints *pConstr = pConstraints; + while( pConstr ) + { + // Erstmal muss die Breite analog zu den den Spaltenbreiten + // aufbereitet werden + sal_uInt16 nCol = pConstr->GetColumn(); + sal_uInt16 nColSpan = pConstr->GetColSpan(); + sal_uLong nConstrMin = pConstr->GetMinNoAlign(); + sal_uLong nConstrMax = pConstr->GetMaxNoAlign(); + + // jetzt holen wir uns die bisherige Breite der ueberspannten + // Spalten + sal_uLong nColsMin = 0; + sal_uLong nColsMax = 0; + for( sal_uInt16 j=nCol; j<nCol+nColSpan; j++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( j ); + nColsMin += pColumn->GetMin(); + nColsMax += pColumn->GetMax(); + } + + if( nColsMin<nConstrMin ) + { + // den Minimalwert anteilig auf die Spalten verteilen + sal_uLong nMinD = nConstrMin-nColsMin; + + if( nConstrMin > nColsMax ) + { + // Anteilig anhand der Mindestbreiten + sal_uInt16 nEndCol = nCol+nColSpan; + sal_uLong nDiff = nMinD; + for( sal_uInt16 ic=nCol; ic<nEndCol; ic++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); + + sal_uLong nColMin = pColumn->GetMin(); + sal_uLong nColMax = pColumn->GetMax(); + + nMin -= nColMin; + sal_uLong nAdd = ic<nEndCol-1 ? (nColMin * nMinD) / nColsMin + : nDiff; + nColMin += nAdd; + nMin += nColMin; + ASSERT( nDiff >= nAdd, "Ooops: nDiff stimmt nicht mehr" ); + nDiff -= nAdd; + + if( nColMax < nColMin ) + { + nMax -= nColMax; + nColsMax -= nColMax; + nColMax = nColMin; + nMax += nColMax; + nColsMax += nColMax; + } + + pColumn->SetMinMax( nColMin, nColMax ); + } + } + else + { + // Anteilig anhand der Differenz zwischen Max und Min + for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); + + sal_uLong nDiff = pColumn->GetMax()-pColumn->GetMin(); + if( nMinD < nDiff ) + nDiff = nMinD; + + pColumn->AddToMin( nDiff ); + + ASSERT( pColumn->GetMax() >= pColumn->GetMin(), + "Wieso ist die SPalte auf einmal zu schmal?" ) + + nMin += nDiff; + nMinD -= nDiff; + } + } + } + + if( !HasColTags() && nColsMax<nConstrMax ) + { + sal_uLong nMaxD = nConstrMax-nColsMax; + + for( sal_uInt16 ic=nCol; ic<nCol+nColSpan; ic++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( ic ); + + nMax -= pColumn->GetMax(); + + pColumn->AddToMax( (pColumn->GetMax() * nMaxD) / nColsMax ); + + nMax += pColumn->GetMax(); + } + } + + pConstr = pConstr->GetNext(); + } + + + if( bFixRelWidths ) + { + if( HasColTags() ) + { + // Zum Anpassen der relativen Breiten werden im 1. Schritt die + // Minmalbreiten aller anzupassenden Zellen jeweils mit der + // relativen Breite einer Spalte multipliziert. Dadurch stimmen + // dann die Breitenverhaeltnisse der Spalten untereinander. + // Ausserdem wird der Faktor berechnet, um den die Zelle dadurch + // breiter gworden ist als die Minmalbreite. + // Im 2. Schritt werden dann die berechneten Breiten durch diesen + // Faktor geteilt. Dadurch bleibt die Breite (nimd.) einer Zelle + // erhalten und dient als Ausgangsbasis fuer die andern Breiten. + // Es werden auch hier nur die Maximalbreiten beeinflusst! + + sal_uLong nAbsMin = 0; // absolte Min-Breite alter Spalten mit + // relativer Breite + sal_uLong nRel = 0; // Summe der relativen Breiten aller Spalten + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) + { + nAbsMin += pColumn->GetMin(); + nRel += pColumn->GetWidthOption(); + } + } + + sal_uLong nQuot = ULONG_MAX; + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() ) + { + nMax -= pColumn->GetMax(); + if( pColumn->GetWidthOption() && pColumn->GetMin() ) + { + pColumn->SetMax( nAbsMin * pColumn->GetWidthOption() ); + sal_uLong nColQuot = pColumn->GetMax() / pColumn->GetMin(); + if( nColQuot<nQuot ) + nQuot = nColQuot; + } + } + } + ASSERT( 0==nRel || nQuot!=ULONG_MAX, + "Wo sind die relativen Spalten geblieben?" ); + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() ) + { + if( pColumn->GetWidthOption() ) + pColumn->SetMax( pColumn->GetMax() / nQuot ); + else + pColumn->SetMax( pColumn->GetMin() ); + ASSERT( pColumn->GetMax() >= pColumn->GetMin(), + "Maximale Spaltenbreite kleiner als Minimale" ); + nMax += pColumn->GetMax(); + } + } + } + else + { + sal_uInt16 nRel = 0; // Summe der relativen Breiten aller Spalten + sal_uInt16 nRelCols = 0; // Anzahl Spalten mit relativer Angabe + sal_uLong nRelMax = 0; // Anteil am Maximum dieser Spalten + for( i=0; i<nCols; i++ ) + { + ASSERT( nRel<=100, "relative Breite aller Spalten>100%" ); + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) + { + // Sicherstellen, dass die relativen breiten nicht + // ueber 100% landen + sal_uInt16 nColWidth = pColumn->GetWidthOption(); + if( nRel+nColWidth > 100 ) + { + nColWidth = 100 - nRel; + pColumn->SetWidthOption( nColWidth, sal_True, sal_False ); + } + nRelMax += pColumn->GetMax(); + nRel = nRel + nColWidth; + nRelCols++; + } + else if( !pColumn->GetMin() ) + { + // Die Spalte ist leer (wurde also auschliesslich + // durch COLSPAN erzeugt) und darf deshalb auch + // keine %-Breite zugewiesen bekommen. + nRelCols++; + } + } + + // Eventuell noch vorhandene Prozente werden auf die Spalten ohne + // eine Breiten-Angabe verteilt. Wie in Netscape werden die + // verbleibenden Prozente enstprechend der Verhaeltnisse + // der Maximalbreiten der in Frage kommenden Spalten + // untereinander verteilt. + // ??? Wie beruecksichtigen bei den Maximalbreiten auch Spalten + // mit fester Breite. Ist das richtig??? + if( nRel < 100 && nRelCols < nCols ) + { + sal_uInt16 nRelLeft = 100 - nRel; + sal_uLong nFixMax = nMax - nRelMax; + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( !pColumn->IsRelWidthOption() && + !pColumn->GetWidthOption() && + pColumn->GetMin() ) + { + // den Rest bekommt die naechste Spalte + sal_uInt16 nColWidth = + (sal_uInt16)((pColumn->GetMax() * nRelLeft) / nFixMax); + pColumn->SetWidthOption( nColWidth, sal_True, sal_False ); + } + } + } + + // nun die Maximalbreiten entsprechend anpassen + sal_uLong nQuotMax = ULONG_MAX; + sal_uLong nOldMax = nMax; + nMax = 0; + for( i=0; i<nCols; i++ ) + { + // Spalten mit %-Angaben werden enstprechend angepasst. + // Spalten, die + // - keine %-Angabe besitzen und in einer Tabelle mit COLS + // oder WIDTH vorkommen, oder + // - als Breite 0% angegeben haben erhalten die Minimalbreite + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) + { + sal_uLong nNewMax; + sal_uLong nColQuotMax; + if( !nWidthOption ) + { + nNewMax = nOldMax * pColumn->GetWidthOption(); + nColQuotMax = nNewMax / pColumn->GetMax(); + } + else + { + nNewMax = nMin * pColumn->GetWidthOption(); + nColQuotMax = nNewMax / pColumn->GetMin(); + } + pColumn->SetMax( nNewMax ); + if( nColQuotMax < nQuotMax ) + nQuotMax = nColQuotMax; + } + else if( HasColsOption() || nWidthOption || + (pColumn->IsRelWidthOption() && + !pColumn->GetWidthOption()) ) + pColumn->SetMax( pColumn->GetMin() ); + } + // und durch den Quotienten teilen + ASSERT( nQuotMax!=ULONG_MAX, "Wo sind die relativen Spalten geblieben?" ); + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() ) + { + if( pColumn->GetWidthOption() ) + { + pColumn->SetMax( pColumn->GetMax() / nQuotMax ); + ASSERT( pColumn->GetMax() >= pColumn->GetMin(), + "Minimalbreite ein Spalte Groesser Maximum" ); + if( pColumn->GetMax() < pColumn->GetMin() ) + pColumn->SetMax( pColumn->GetMin() ); + } + } + nMax += pColumn->GetMax(); + } + } + } + + delete pConstraints; +} + +// nAbsAvail ist der verfuegbare Platz in TWIPS. +// nRelAvail ist der auf USHRT_MAX bezogene verfuegbare Platz oder 0 +// nAbsSpace ist der Anteil von nAbsAvail, der durch der umgebende Zelle +// fur die Umrandung und den Abstand zum Inhalt reserviert ist. +void SwHTMLTableLayout::AutoLayoutPass2( sal_uInt16 nAbsAvail, sal_uInt16 nRelAvail, + sal_uInt16 nAbsLeftSpace, + sal_uInt16 nAbsRightSpace, + sal_uInt16 nParentInhAbsSpace ) +{ + // Erstmal fuehren wie jede Menge Plausibilaets-Test durch + + // Eine abolute zur Verfuegung stehende Breite muss immer uebergeben + // werden. + ASSERT( nAbsAvail, "AutoLayout Pass 2: Keine absolute Breite gegeben" ); + + // Eine realtive zur Verfuegung stehende Breite darf nur und muss fuer + // Tabellen in Tabellen uebergeben + ASSERT( IsTopTable() == (nRelAvail==0), + "AutoLayout Pass 2: Rel. Breite bei Tab in Tab oder umgekehrt" ); + + // Die Minimalbreite der Tabelle darf natuerlich nie groesser sein + // als das die Maximalbreite. + ASSERT( nMin<=nMax, "AutoLayout Pass2: nMin > nMax" ); + + // Die verfuegbare Breite, fuer die die Tabelle berechnet wurde, merken. + // (Dies ist ein guter Ort, denn hier kommer wir bei der Erstberechnung + // der Tabelle aus dem Parser und bei jedem _Resize-Aufruf vorbei.) + nLastResizeAbsAvail = nAbsAvail; + + // Schritt 1: Der verfuegbar Platz wird an linke/rechte Raender, + // vorhandene Filler-Zellen und Abstande angepasst + + // Abstand zum Inhalt und Unrandung + sal_uInt16 nAbsLeftFill = 0, nAbsRightFill = 0; + if( !IsTopTable() && + GetMin() + nAbsLeftSpace + nAbsRightSpace <= nAbsAvail ) + { + nAbsLeftFill = nAbsLeftSpace; + nAbsRightFill = nAbsRightSpace; + } + + // Linker und rechter Abstand + if( nLeftMargin || nRightMargin ) + { + if( IsTopTable() ) + { + // fuer die Top-Table beruecksichtigen wir die Raender immer, + // den die Minimalbreite der Tabelle wird hier nie unterschritten + nAbsAvail -= (nLeftMargin + nRightMargin); + } + else if( GetMin() + nLeftMargin + nRightMargin <= nAbsAvail ) + { + // sonst beruecksichtigen wir die Raender nur, wenn auch Platz + // fuer sie da ist (nMin ist hier bereits berechnet!) + nAbsLeftFill = nAbsLeftFill + nLeftMargin; + nAbsRightFill = nAbsRightFill + nRightMargin; + } + } + + // Filler-Zellen + if( !IsTopTable() ) + { + if( pLeftFillerBox && nAbsLeftFill<MINLAY+nInhLeftBorderWidth ) + nAbsLeftFill = MINLAY+nInhLeftBorderWidth; + if( pRightFillerBox && nAbsRightFill<MINLAY+nInhRightBorderWidth ) + nAbsRightFill = MINLAY+nInhRightBorderWidth; + } + + // Anpassen des verfuegbaren Platzes. + nRelLeftFill = 0; + nRelRightFill = 0; + if( !IsTopTable() && (nAbsLeftFill>0 || nAbsRightFill) ) + { + sal_uLong nAbsLeftFillL = nAbsLeftFill, nAbsRightFillL = nAbsRightFill; + + nRelLeftFill = (sal_uInt16)((nAbsLeftFillL * nRelAvail) / nAbsAvail); + nRelRightFill = (sal_uInt16)((nAbsRightFillL * nRelAvail) / nAbsAvail); + + nAbsAvail -= (nAbsLeftFill + nAbsRightFill); + if( nRelAvail ) + nRelAvail -= (nRelLeftFill + nRelRightFill); + } + + + // Schritt 2: Die absolute Tabellenbreite wird berechnet. + sal_uInt16 nAbsTabWidth = 0; + bUseRelWidth = sal_False; + if( nWidthOption ) + { + if( bPrcWidthOption ) + { + ASSERT( nWidthOption<=100, "Prozentangabe zu gross" ); + if( nWidthOption > 100 ) + nWidthOption = 100; + + // Die absolute Breite entspricht den angegeben Prozent der + // zur Verfuegung stehenden Breite. + // Top-Tabellen bekommen nur eine relative Breite, wenn der + // verfuegbare Platz *echt groesser* ist als die Minimalbreite. + // ACHTUNG: Das "echte groesser" ist noetig, weil der Wechsel + // von einer relativen Breite zu einer absoluten Breite durch + // Resize sonst zu einer Endlosschleife fuehrt. + // Weil bei Tabellen in Rahmen kein Resize aufgerufen wird, + // wenn der Rahmen eine nicht-relative Breite besitzt, koennen + // wir da solche Spielchen nicht spielen + // MIB 19.2.98: Wegen fix #47394# spielen wir solche Spielchen + // jetzt doch. Dort war eine Grafik in einer 1%-breiten + // Tabelle und hat da natuerlich nicht hineingepasst. + nAbsTabWidth = (sal_uInt16)( ((sal_uLong)nAbsAvail * nWidthOption) / 100 ); + if( IsTopTable() && + ( /*MayBeInFlyFrame() ||*/ (sal_uLong)nAbsTabWidth > nMin ) ) + { + nRelAvail = USHRT_MAX; + bUseRelWidth = sal_True; + } + } + else + { + nAbsTabWidth = nWidthOption; + if( nAbsTabWidth > MAX_TABWIDTH ) + nAbsTabWidth = MAX_TABWIDTH; + + // Tabellen in Tabellen duerfen niemals breiter werden als der + // verfuegbare Platz. + if( !IsTopTable() && nAbsTabWidth > nAbsAvail ) + nAbsTabWidth = nAbsAvail; + } + } + + ASSERT( IsTopTable() || nAbsTabWidth<=nAbsAvail, + "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer Tab in Tab" ); + ASSERT( !nRelAvail || nAbsTabWidth<=nAbsAvail, + "AutoLayout Pass2: nAbsTabWidth > nAbsAvail fuer relative Breite" ); + + // Catch fuer die beiden Asserts von oben (man weiss ja nie!) + if( (!IsTopTable() || nRelAvail>0) && nAbsTabWidth>nAbsAvail ) + nAbsTabWidth = nAbsAvail; + + + // Schritt 3: Bestimmen der Spaltenbreiten und ggf. auch der + // absoluten und relativen Tabellenbreiten. + if( (!IsTopTable() && nMin > (sal_uLong)nAbsAvail) || + nMin > MAX_TABWIDTH ) + { + // Wenn + // - das Minumum einer inneren Tabelle groesser ist als der + // verfuegbare Platz, oder + // - das Minumum einer Top-Table groesser ist als USHRT_MAX + // muss die Tabelle an den verfuegbaren Platz bzw. USHRT_MAX + // abgepasst werden. Dabei bleiben die Verhaeltnisse der Breiten + // untereinander erhalten. + + nAbsTabWidth = IsTopTable() ? MAX_TABWIDTH : nAbsAvail; + nRelTabWidth = (nRelAvail ? nRelAvail : nAbsTabWidth ); + + // First of all, we check wether we can fit the layout constrains, + // that are: Every cell's width excluding the borders must be at least + // MINLAY: + + sal_uLong nRealMin = 0; + for( sal_uInt16 i=0; i<nCols; i++ ) + { + sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2; + AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 ); + nRealMin += nRealColMin; + } + if( (nRealMin >= nAbsTabWidth) || (nRealMin >= nMin) ) + { + // "Nichts geht mehr". We cannot get the minimum column widths + // the layout wants to have. + + sal_uInt16 nAbs = 0, nRel = 0; + SwHTMLTableLayoutColumn *pColumn; + for( sal_uInt16 i=0; i<nCols-1; i++ ) + { + pColumn = GetColumn( i ); + sal_uLong nColMin = pColumn->GetMin(); + if( nColMin <= USHRT_MAX ) + { + pColumn->SetAbsColWidth( + (sal_uInt16)((nColMin * nAbsTabWidth) / nMin) ); + pColumn->SetRelColWidth( + (sal_uInt16)((nColMin * nRelTabWidth) / nMin) ); + } + else + { + double nColMinD = nColMin; + pColumn->SetAbsColWidth( + (sal_uInt16)((nColMinD * nAbsTabWidth) / nMin) ); + pColumn->SetRelColWidth( + (sal_uInt16)((nColMinD * nRelTabWidth) / nMin) ); + } + + nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); + nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); + } + pColumn = GetColumn( nCols-1 ); + pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); + pColumn->SetRelColWidth( nRelTabWidth - nRel ); + } + else + { + sal_uLong nDistAbs = nAbsTabWidth - nRealMin; + sal_uLong nDistRel = nRelTabWidth - nRealMin; + sal_uLong nDistMin = nMin - nRealMin; + sal_uInt16 nAbs = 0, nRel = 0; + SwHTMLTableLayoutColumn *pColumn; + for( sal_uInt16 i=0; i<nCols-1; i++ ) + { + pColumn = GetColumn( i ); + sal_uLong nColMin = pColumn->GetMin(); + sal_uLong nRealColMin = MINLAY, nDummy1, nDummy2; + AddBorderWidth( nRealColMin, nDummy1, nDummy2, i, 1 ); + + if( nColMin <= USHRT_MAX ) + { + pColumn->SetAbsColWidth( + (sal_uInt16)((((nColMin-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); + pColumn->SetRelColWidth( + (sal_uInt16)((((nColMin-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); + } + else + { + double nColMinD = nColMin; + pColumn->SetAbsColWidth( + (sal_uInt16)((((nColMinD-nRealColMin) * nDistAbs) / nDistMin) + nRealColMin) ); + pColumn->SetRelColWidth( + (sal_uInt16)((((nColMinD-nRealColMin) * nDistRel) / nDistMin) + nRealColMin) ); + } + + nAbs = nAbs + (sal_uInt16)pColumn->GetAbsColWidth(); + nRel = nRel + (sal_uInt16)pColumn->GetRelColWidth(); + } + pColumn = GetColumn( nCols-1 ); + pColumn->SetAbsColWidth( nAbsTabWidth - nAbs ); + pColumn->SetRelColWidth( nRelTabWidth - nRel ); + } + } + else if( nMax <= (sal_uLong)(nAbsTabWidth ? nAbsTabWidth : nAbsAvail) ) + { + // Wenn + // - die Tabelle eine fixe Breite besitzt und das Maximum der + // Tabelle kleiner ist, oder + // - das Maximum kleiner ist als der verfuegbare Platz + // kann das Maximum direkt uebernommen werden bzw. die Tabelle nur + // unter Beruecksichtigung des Maxumums an die fixe Breite + // angepasst werden. + + // Keine fixe Breite, dann das Maximum nehmen. + if( !nAbsTabWidth ) + nAbsTabWidth = (sal_uInt16)nMax; + + // Eine Top-Table darf auch beriter werden als der verfuegbare Platz. + if( nAbsTabWidth > nAbsAvail ) + { + ASSERT( IsTopTable(), + "Tabelle in Tabelle soll breiter werden als umgebende Zelle" ); + nAbsAvail = nAbsTabWidth; + } + + // Nur den Anteil der relativen Breite verwenden, der auch fuer + // die absolute Breite verwendet wuerde. + sal_uLong nAbsTabWidthL = nAbsTabWidth; + nRelTabWidth = + ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) + : nAbsTabWidth ); + + // Gibt es Spalten mit und Spalten ohne %-Angabe? + sal_uLong nFixMax = nMax; + for( sal_uInt16 i=0; i<nCols; i++ ) + { + const SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption()>0 ) + nFixMax -= pColumn->GetMax(); + } + + if( nFixMax > 0 && nFixMax < nMax ) + { + // ja, dann den zu verteilenden Platz nur auf die Spalten + // mit %-Angabe verteilen. + + // In diesem (und nur in diesem) Fall gibt es Spalten, + // die ihre Maximalbreite genau einhalten, also weder + // schmaler noch breiter werden. Beim zurueckrechnen der + // absoluten Breite aus der relativen Breite kann es + // zu Rundungsfehlern kommen (bug #45598#). Um die auszugeleichen + // werden zuerst die fixen Breiten entsprechend korrigiert + // eingestellt und erst danach die relativen. + + sal_uInt16 nAbs = 0, nRel = 0; + sal_uInt16 nFixedCols = 0; + sal_uInt16 i; + + for( i = 0; i < nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( !pColumn->IsRelWidthOption() || !pColumn->GetWidthOption() ) + { + // Die Spalte behaelt ihre Breite bei. + nFixedCols++; + sal_uLong nColMax = pColumn->GetMax(); + pColumn->SetAbsColWidth( (sal_uInt16)nColMax ); + + sal_uLong nRelColWidth = + (nColMax * nRelTabWidth) / nAbsTabWidth; + sal_uLong nChkWidth = + (nRelColWidth * nAbsTabWidth) / nRelTabWidth; + if( nChkWidth < nColMax ) + nRelColWidth++; + else if( nChkWidth > nColMax ) + nRelColWidth--; + pColumn->SetRelColWidth( (sal_uInt16)nRelColWidth ); + + nAbs = nAbs + (sal_uInt16)nColMax; + nRel = nRel + (sal_uInt16)nRelColWidth; + } + } + + // Zu verteilende Anteile des Maximums und der relativen und + // absoluten Breiten. nFixMax entspricht an dieser Stelle + // nAbs, so dass man gleich nFixMax haette nehmen koennen. + // Der Code ist so aber verstaendlicher. + ASSERT( nFixMax == nAbs, "Zwei Schleifen, zwei Summen?" ) + sal_uLong nDistMax = nMax - nFixMax; + sal_uInt16 nDistAbsTabWidth = nAbsTabWidth - nAbs; + sal_uInt16 nDistRelTabWidth = nRelTabWidth - nRel; + + for( i=0; i<nCols; i++ ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( i ); + if( pColumn->IsRelWidthOption() && pColumn->GetWidthOption() > 0 ) + { + // Die Spalte wird anteilig breiter. + nFixedCols++; + if( nFixedCols == nCols ) + { + pColumn->SetAbsColWidth( nAbsTabWidth-nAbs ); + pColumn->SetRelColWidth( nRelTabWidth-nRel ); + } + else + { + sal_uLong nColMax = pColumn->GetMax(); + pColumn->SetAbsColWidth( + (sal_uInt16)((nColMax * nDistAbsTabWidth) / nDistMax) ); + pColumn->SetRelColWidth( + (sal_uInt16)((nColMax * nDistRelTabWidth) / nDistMax) ); + } + nAbs = nAbs + pColumn->GetAbsColWidth(); + nRel = nRel + pColumn->GetRelColWidth(); + } + } + ASSERT( nCols==nFixedCols, "Spalte vergessen!" ); + } + else + { + // nein, dann den zu verteilenden Platz auf alle Spalten + // gleichmaessig vertilen. + for( sal_uInt16 i=0; i<nCols; i++ ) + { + sal_uLong nColMax = GetColumn( i )->GetMax(); + GetColumn( i )->SetAbsColWidth( + (sal_uInt16)((nColMax * nAbsTabWidth) / nMax) ); + GetColumn( i )->SetRelColWidth( + (sal_uInt16)((nColMax * nRelTabWidth) / nMax) ); + } + } + } + else + { + // den ueber die Minimalbreite herausgehenden Platz entsprechend + // den einzelnen Spalten anteilig zuschlagen + if( !nAbsTabWidth ) + nAbsTabWidth = nAbsAvail; + if( nAbsTabWidth < nMin ) + nAbsTabWidth = (sal_uInt16)nMin; + + if( nAbsTabWidth > nAbsAvail ) + { + ASSERT( IsTopTable(), + "Tabelle in Tabelle soll breiter werden als Platz da ist" ); + nAbsAvail = nAbsTabWidth; + } + + sal_uLong nAbsTabWidthL = nAbsTabWidth; + nRelTabWidth = + ( nRelAvail ? (sal_uInt16)((nAbsTabWidthL * nRelAvail) / nAbsAvail) + : nAbsTabWidth ); + double nW = nAbsTabWidth - nMin; + double nD = (nMax==nMin ? 1 : nMax-nMin); + sal_uInt16 nAbs = 0, nRel = 0; + for( sal_uInt16 i=0; i<nCols-1; i++ ) + { + double nd = GetColumn( i )->GetMax() - GetColumn( i )->GetMin(); + sal_uLong nAbsColWidth = GetColumn( i )->GetMin() + (sal_uLong)((nd*nW)/nD); + sal_uLong nRelColWidth = nRelAvail + ? (nAbsColWidth * nRelTabWidth) / nAbsTabWidth + : nAbsColWidth; + + GetColumn( i )->SetAbsColWidth( (sal_uInt16)nAbsColWidth ); + GetColumn( i )->SetRelColWidth( (sal_uInt16)nRelColWidth ); + nAbs = nAbs + (sal_uInt16)nAbsColWidth; + nRel = nRel + (sal_uInt16)nRelColWidth; + } + GetColumn( nCols-1 )->SetAbsColWidth( nAbsTabWidth - nAbs ); + GetColumn( nCols-1 )->SetRelColWidth( nRelTabWidth - nRel ); + + } + + // Schritt 4: Fuer Tabellen in Tabellen kann es links und/oder rechts + // noch Ausgleichzellen geben. Deren Breite wird jetzt berechnet. + nInhAbsLeftSpace = 0; + nInhAbsRightSpace = 0; + if( !IsTopTable() && (nRelLeftFill>0 || nRelRightFill>0 || + nAbsTabWidth<nAbsAvail) ) + { + // Die Breite von zusaetzlichen Zellen zur Ausrichtung der + // inneren Tabelle bestimmen + sal_uInt16 nAbsDist = (sal_uInt16)(nAbsAvail-nAbsTabWidth); + sal_uInt16 nRelDist = (sal_uInt16)(nRelAvail-nRelTabWidth); + sal_uInt16 nParentInhAbsLeftSpace = 0, nParentInhAbsRightSpace = 0; + + // Groesse und Position der zusaetzlichen Zellen bestimmen + switch( eTableAdjust ) + { + case SVX_ADJUST_RIGHT: + nAbsLeftFill = nAbsLeftFill + nAbsDist; + nRelLeftFill = nRelLeftFill + nRelDist; + nParentInhAbsLeftSpace = nParentInhAbsSpace; + break; + case SVX_ADJUST_CENTER: + { + sal_uInt16 nAbsLeftDist = nAbsDist / 2; + nAbsLeftFill = nAbsLeftFill + nAbsLeftDist; + nAbsRightFill += nAbsDist - nAbsLeftDist; + sal_uInt16 nRelLeftDist = nRelDist / 2; + nRelLeftFill = nRelLeftFill + nRelLeftDist; + nRelRightFill += nRelDist - nRelLeftDist; + nParentInhAbsLeftSpace = nParentInhAbsSpace / 2; + nParentInhAbsRightSpace = nParentInhAbsSpace - + nParentInhAbsLeftSpace; + } + break; + case SVX_ADJUST_LEFT: + default: + nAbsRightFill = nAbsRightFill + nAbsDist; + nRelRightFill = nRelRightFill + nRelDist; + nParentInhAbsRightSpace = nParentInhAbsSpace; + break; + } + + ASSERT( !pLeftFillerBox || nRelLeftFill>0, + "Fuer linke Filler-Box ist keine Breite da!" ); + ASSERT( !pRightFillerBox || nRelRightFill>0, + "Fuer rechte Filler-Box ist keine Breite da!" ); + + // Filler-Breiten werden auf die ausseren Spalten geschlagen, wenn + // es nach dem ersten Durchlauf keine Boxen fuer sie gibt (nWidth>0) + // oder ihre Breite zu klein wuerde oder wenn es COL-Tags gibt und + // die Filler-Breite der Umrandung-Breite entspricht (dann haben wir + // die Tabelle wahrscheinlich selbst exportiert) + if( nRelLeftFill && !pLeftFillerBox && + ( nWidthSet>0 || nAbsLeftFill<MINLAY+nInhLeftBorderWidth || + (HasColTags() && nAbsLeftFill < nAbsLeftSpace+nParentInhAbsLeftSpace+20) ) ) +// (nAbsLeftFill<MINLAY || nAbsLeftFill<=nAbsLeftSpace) ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( 0 ); + pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsLeftFill ); + pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelLeftFill ); + nRelLeftFill = 0; + nInhAbsLeftSpace = nAbsLeftSpace + nParentInhAbsLeftSpace; + } + if( nRelRightFill && !pRightFillerBox && + ( nWidthSet>0 || nAbsRightFill<MINLAY+nInhRightBorderWidth || + (HasColTags() && nAbsRightFill < nAbsRightSpace+nParentInhAbsRightSpace+20) ) ) +// (nAbsRightFill<MINLAY || nAbsRightFill<=nAbsRightSpace) ) + { + SwHTMLTableLayoutColumn *pColumn = GetColumn( nCols-1 ); + pColumn->SetAbsColWidth( pColumn->GetAbsColWidth()+nAbsRightFill ); + pColumn->SetRelColWidth( pColumn->GetRelColWidth()+nRelRightFill ); + nRelRightFill = 0; + nInhAbsRightSpace = nAbsRightSpace + nParentInhAbsRightSpace; + } + } +} + +static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ); + +static sal_Bool lcl_ResizeBox( const SwTableBox*& rpBox, void* pPara ) +{ + sal_uInt16 *pWidth = (sal_uInt16 *)pPara; + + if( !rpBox->GetSttNd() ) + { + sal_uInt16 nWidth = 0; + ((SwTableBox *)rpBox)->GetTabLines().ForEach( &lcl_ResizeLine, &nWidth ); + rpBox->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); + *pWidth = *pWidth + nWidth; + } + else + { + *pWidth = *pWidth + (sal_uInt16)rpBox->GetFrmFmt()->GetFrmSize().GetSize().Width(); + } + + return sal_True; +} + +static sal_Bool lcl_ResizeLine( const SwTableLine*& rpLine, void* pPara ) +{ + sal_uInt16 *pWidth = (sal_uInt16 *)pPara; +#ifdef DBG_UTIL + sal_uInt16 nOldWidth = *pWidth; +#endif + *pWidth = 0; + ((SwTableLine *)rpLine)->GetTabBoxes().ForEach( &lcl_ResizeBox, pWidth ); + +#ifdef DBG_UTIL + ASSERT( !nOldWidth || Abs(*pWidth-nOldWidth) < COLFUZZY, + "Zeilen einer Box sind unterschiedlich lang" ); +#endif + + return sal_True; +} + +void SwHTMLTableLayout::SetWidths( sal_Bool bCallPass2, sal_uInt16 nAbsAvail, + sal_uInt16 nRelAvail, sal_uInt16 nAbsLeftSpace, + sal_uInt16 nAbsRightSpace, + sal_uInt16 nParentInhAbsSpace ) +{ + // SetWidth muss am Ende einmal mehr fuer jede Zelle durchlaufen + // worden sein. + nWidthSet++; + + // Schritt 0: Wenn noetig, wird hier noch der Pass2 des Layout-Alogithmus + // aufgerufen. + if( bCallPass2 ) + AutoLayoutPass2( nAbsAvail, nRelAvail, nAbsLeftSpace, nAbsRightSpace, + nParentInhAbsSpace ); + + // Schritt 1: Setzten der neuen Breite an allen Content-Boxen. + // Da die Boxen nichts von der HTML-Tabellen-Struktur wissen, wird + // ueber die HTML-Tabellen-Struktur iteriert. Fuer Tabellen in Tabellen + // in Tabellen wird rekursiv SetWidth aufgerufen. + for( sal_uInt16 i=0; i<nRows; i++ ) + { + for( sal_uInt16 j=0; j<nCols; j++ ) + { + SwHTMLTableLayoutCell *pCell = GetCell( i, j ); + + SwHTMLTableLayoutCnts* pCntnts = pCell->GetContents(); + while( pCntnts && !pCntnts->IsWidthSet(nWidthSet) ) + { + SwTableBox *pBox = pCntnts->GetTableBox(); + if( pBox ) + { + SetBoxWidth( pBox, j, pCell->GetColSpan() ); + } + else + { + sal_uInt16 nAbs = 0, nRel = 0, nLSpace = 0, nRSpace = 0, + nInhSpace = 0; + if( bCallPass2 ) + { + sal_uInt16 nColSpan = pCell->GetColSpan(); + GetAvail( j, nColSpan, nAbs, nRel ); + nLSpace = GetLeftCellSpace( j, nColSpan ); + nRSpace = GetRightCellSpace( j, nColSpan ); + nInhSpace = GetInhCellSpace( j, nColSpan ); + } + pCntnts->GetTable()->SetWidths( bCallPass2, nAbs, nRel, + nLSpace, nRSpace, + nInhSpace ); + } + + pCntnts->SetWidthSet( nWidthSet ); + pCntnts = pCntnts->GetNext(); + } + } + } + + // Schritt 2: Wenn eine Top-Tabelle vorliegt, werden jetzt die Formate + // der Nicht-Content-Boxen angepasst. Da diese aufgrund der + // Garbage-Collection in der HTML-Tabelle nicht bekannt sind, muessen + // wir hier ueber die Tabelle iterieren. Bei der Gelegenheit wird auch + // das Tabellen-Frameformat angepasst. Fuer Tabellen in Tabellen werden + // stattdessen die Breiten der Filler-Zellen gesetzt. + if( IsTopTable() ) + { + sal_uInt16 nCalcTabWidth = 0; + ((SwTable *)pSwTable)->GetTabLines().ForEach( &lcl_ResizeLine, + &nCalcTabWidth ); + ASSERT( Abs( nRelTabWidth-nCalcTabWidth ) < COLFUZZY, + "Tabellebreite stimmt nicht mit Zeilenbreite ueberein." ); + + // Beim Anpassen des Tabellen-Formats dieses locken, weil sonst + // die Boxformate erneut angepasst werden. Ausserdem muss eine + // evtl. vorhandene %-Angabe in jedem Fall erhalten bleiben. + SwFrmFmt *pFrmFmt = pSwTable->GetFrmFmt(); + ((SwTable *)pSwTable)->LockModify(); + SwFmtFrmSize aFrmSize( pFrmFmt->GetFrmSize() ); + aFrmSize.SetWidth( nRelTabWidth ); + sal_Bool bRel = bUseRelWidth && + text::HoriOrientation::FULL!=pFrmFmt->GetHoriOrient().GetHoriOrient(); + aFrmSize.SetWidthPercent( (sal_uInt8)(bRel ? nWidthOption : 0) ); + pFrmFmt->SetFmtAttr( aFrmSize ); + ((SwTable *)pSwTable)->UnlockModify(); + + // Wenn die Tabelle in einem Rahmen steht, muss auch noch dessen + // breite angepasst werden. + if( MayBeInFlyFrame() ) + { + SwFrmFmt *pFlyFrmFmt = FindFlyFrmFmt(); + if( pFlyFrmFmt ) + { + SwFmtFrmSize aFlyFrmSize( ATT_VAR_SIZE, nRelTabWidth, MINLAY ); + + if( bUseRelWidth ) + { + // Bei %-Angaben wird die Breite auf das Minimum gesetzt. + aFlyFrmSize.SetWidth( nMin > USHRT_MAX ? USHRT_MAX + : nMin ); + aFlyFrmSize.SetWidthPercent( (sal_uInt8)nWidthOption ); + } + pFlyFrmFmt->SetFmtAttr( aFlyFrmSize ); + } + } + +#ifdef DBG_UTIL + { + // steht im tblrwcl.cxx + extern void _CheckBoxWidth( const SwTableLine&, SwTwips ); + + // checke doch mal ob die Tabellen korrekte Breiten haben + SwTwips nSize = pSwTable->GetFrmFmt()->GetFrmSize().GetWidth(); + const SwTableLines& rLines = pSwTable->GetTabLines(); + for( sal_uInt16 n = 0; n < rLines.Count(); ++n ) + _CheckBoxWidth( *rLines[ n ], nSize ); + } +#endif + + } + else + { + if( pLeftFillerBox ) + { + pLeftFillerBox->GetFrmFmt()->SetFmtAttr( + SwFmtFrmSize( ATT_VAR_SIZE, nRelLeftFill, 0 )); + } + if( pRightFillerBox ) + { + pRightFillerBox->GetFrmFmt()->SetFmtAttr( + SwFmtFrmSize( ATT_VAR_SIZE, nRelRightFill, 0 )); + } + } +} + +void SwHTMLTableLayout::_Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc ) +{ + // Wenn bRecalc gestzt ist, hat sich am Inhalt der Tabelle etwas + // geaendert. Es muss dann der erste Pass noch einmal durchgefuehrt + // werden. + if( bRecalc ) + AutoLayoutPass1(); + + SwRootFrm *pRoot = (SwRootFrm*)GetDoc()->GetRootFrm(); + if ( pRoot && pRoot->IsCallbackActionEnabled() ) + pRoot->StartAllAction(); + + // Sonst koennen die Breiten gesetzt werden, wobei zuvor aber jewils + // noch der Pass 2 laufen muss. + SetWidths( sal_True, nAbsAvail ); + + if ( pRoot && pRoot->IsCallbackActionEnabled() ) + pRoot->EndAllAction( sal_True ); //True per VirDev (Browsen ruhiger) +} + +IMPL_STATIC_LINK( SwHTMLTableLayout, DelayedResize_Impl, void*, EMPTYARG ) +{ +#ifdef TEST_DELAYED_RESIZE + Sound::Beep( SOUND_WARNING ); +#endif + pThis->aResizeTimer.Stop(); + pThis->_Resize( pThis->nDelayedResizeAbsAvail, + pThis->bDelayedResizeRecalc ); + + return 0; +} + + +sal_Bool SwHTMLTableLayout::Resize( sal_uInt16 nAbsAvail, sal_Bool bRecalc, + sal_Bool bForce, sal_uLong nDelay ) +{ + if( 0 == nAbsAvail ) + return sal_False; + ASSERT( IsTopTable(), "Resize darf nur an Top-Tabellen aufgerufen werden" ); + + // Darf die Tabelle uberhaupt Resized werden oder soll sie es trotzdem? + if( bMustNotResize && !bForce ) + return sal_False; + + // Darf ein Recalc der Tabelle durchgefuehrt werden? + if( bMustNotRecalc && !bForce ) + bRecalc = sal_False; + + const SwDoc *pDoc = GetDoc(); + + // Wenn es ein Layout gibt, wurde evtl. die Groesse der Root-Frames + // und nicht die der VisArea uebergeben. Wenn wir nicht in einem Rahmen + // stehen, muss die Tabelle allerdings fuer die VisArea berechnet werden, + // weil sond die Umschaltung von relativ nach absolut nicht funktioniert. + if( pDoc->GetRootFrm() && pDoc->get(IDocumentSettingAccess::BROWSE_MODE) ) + { + const sal_uInt16 nVisAreaWidth = GetBrowseWidthByVisArea( *pDoc ); + if( nVisAreaWidth < nAbsAvail && !FindFlyFrmFmt() ) + nAbsAvail = nVisAreaWidth; + } + + if( nDelay==0 && aResizeTimer.IsActive() ) + { + // Wenn beim Aufruf eines synchronen Resize noch ein asynchrones + // Resize aussteht, dann werden nur die neuen Werte uebernommen. + + bRecalc |= bDelayedResizeRecalc; + nDelayedResizeAbsAvail = nAbsAvail; + return sal_False; + } + + // Optimierung: + // Wenn die Minima/Maxima nicht neu berechnet werden sollen und + // - die Breite der Tabelle nie neu berechnet werden muss, oder + // - die Tabelle schon fuer die uebergebene Breite berechnet wurde, oder + // - der verfuegbare Platz kleiner oder gleich der Minimalbreite ist + // und die Tabelle bereits die Minimalbreite besitzt, oder + // - der verfuegbare Platz groesser ist als die Maximalbreite und + // die Tabelle bereits die Maximalbreite besitzt + // wird sich an der Tabelle nichts aendern. + if( !bRecalc && ( !bMustResize || + (nLastResizeAbsAvail==nAbsAvail) || + (nAbsAvail<=nMin && nRelTabWidth==nMin) || + (!bPrcWidthOption && nAbsAvail>=nMax && nRelTabWidth==nMax) ) ) + return sal_False; + + if( nDelay==HTMLTABLE_RESIZE_NOW ) + { + if( aResizeTimer.IsActive() ) + aResizeTimer.Stop(); + _Resize( nAbsAvail, bRecalc ); + } + else if( nDelay > 0 ) + { + nDelayedResizeAbsAvail = nAbsAvail; + bDelayedResizeRecalc = bRecalc; + aResizeTimer.SetTimeout( nDelay ); + aResizeTimer.Start(); +#ifdef TEST_DELAYED_RESIZE + Sound::Beep( SOUND_DEFAULT ); +#endif + } + else + { + _Resize( nAbsAvail, bRecalc ); + } + + return sal_True; +} + +void SwHTMLTableLayout::BordersChanged( sal_uInt16 nAbsAvail, sal_Bool bRecalc ) +{ + bBordersChanged = sal_True; + + Resize( nAbsAvail, bRecalc ); +} + + diff --git a/sw/source/core/doc/lineinfo.cxx b/sw/source/core/doc/lineinfo.cxx new file mode 100644 index 000000000000..7490cf9f0719 --- /dev/null +++ b/sw/source/core/doc/lineinfo.cxx @@ -0,0 +1,154 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + + +#include "doc.hxx" +#include "lineinfo.hxx" +#include "charfmt.hxx" +#include "poolfmt.hxx" +#include "rootfrm.hxx" +#include "viewsh.hxx" + +void SwDoc::SetLineNumberInfo( const SwLineNumberInfo &rNew ) +{ + if ( GetRootFrm() && + (rNew.IsCountBlankLines() != pLineNumberInfo->IsCountBlankLines() || + rNew.IsRestartEachPage() != pLineNumberInfo->IsRestartEachPage()) ) + { + GetRootFrm()->StartAllAction(); + // FME 2007-08-14 #i80120# Invalidate size, because ChgThisLines() + // is only (onny may only be) called by the formatting routines + GetRootFrm()->InvalidateAllCntnt( INV_LINENUM | INV_SIZE ); + GetRootFrm()->EndAllAction(); + } + *pLineNumberInfo = rNew; + SetModified(); +} + +const SwLineNumberInfo& SwDoc::GetLineNumberInfo() const +{ + return *pLineNumberInfo; +} + +SwLineNumberInfo::SwLineNumberInfo() : + nPosFromLeft( MM50 ), + nCountBy( 5 ), + nDividerCountBy( 3 ), + ePos( LINENUMBER_POS_LEFT ), + bPaintLineNumbers( sal_False ), + bCountBlankLines( sal_True ), + bCountInFlys( sal_False ), + bRestartEachPage( sal_False ) +{ +} + +SwLineNumberInfo::SwLineNumberInfo(const SwLineNumberInfo &rCpy ) : SwClient(), + aType( rCpy.GetNumType() ), + aDivider( rCpy.GetDivider() ), + nPosFromLeft( rCpy.GetPosFromLeft() ), + nCountBy( rCpy.GetCountBy() ), + nDividerCountBy( rCpy.GetDividerCountBy() ), + ePos( rCpy.GetPos() ), + bPaintLineNumbers( rCpy.IsPaintLineNumbers() ), + bCountBlankLines( rCpy.IsCountBlankLines() ), + bCountInFlys( rCpy.IsCountInFlys() ), + bRestartEachPage( rCpy.IsRestartEachPage() ) +{ + if ( rCpy.GetRegisteredIn() ) + ((SwModify*)rCpy.GetRegisteredIn())->Add( this ); +} + +SwLineNumberInfo& SwLineNumberInfo::operator=(const SwLineNumberInfo &rCpy) +{ + if ( rCpy.GetRegisteredIn() ) + ((SwModify*)rCpy.GetRegisteredIn())->Add( this ); + else if ( GetRegisteredIn() ) + pRegisteredIn->Remove( this ); + + aType = rCpy.GetNumType(); + aDivider = rCpy.GetDivider(); + nPosFromLeft = rCpy.GetPosFromLeft(); + nCountBy = rCpy.GetCountBy(); + nDividerCountBy = rCpy.GetDividerCountBy(); + ePos = rCpy.GetPos(); + bPaintLineNumbers = rCpy.IsPaintLineNumbers(); + bCountBlankLines = rCpy.IsCountBlankLines(); + bCountInFlys = rCpy.IsCountInFlys(); + bRestartEachPage = rCpy.IsRestartEachPage(); + + return *this; +} + +sal_Bool SwLineNumberInfo::operator==( const SwLineNumberInfo& rInf ) const +{ + return GetRegisteredIn() == rInf.GetRegisteredIn() && + aType.GetNumberingType() == rInf.GetNumType().GetNumberingType() && + aDivider == rInf.GetDivider() && + nPosFromLeft == rInf.GetPosFromLeft() && + nCountBy == rInf.GetCountBy() && + nDividerCountBy == rInf.GetDividerCountBy() && + ePos == rInf.GetPos() && + bPaintLineNumbers == rInf.IsPaintLineNumbers() && + bCountBlankLines == rInf.IsCountBlankLines() && + bCountInFlys == rInf.IsCountInFlys() && + bRestartEachPage == rInf.IsRestartEachPage(); +} + + +SwCharFmt* SwLineNumberInfo::GetCharFmt( IDocumentStylePoolAccess& rIDSPA ) const +{ + if ( !GetRegisteredIn() ) + { + SwCharFmt* pFmt = rIDSPA.GetCharFmtFromPool( RES_POOLCHR_LINENUM ); + pFmt->Add( (SwClient*)this ); + } + return (SwCharFmt*)GetRegisteredIn(); +} + +void SwLineNumberInfo::SetCharFmt( SwCharFmt *pChFmt ) +{ + ASSERT( pChFmt, "SetCharFmt, 0 is not a valid pointer" ); + pChFmt->Add( this ); +} + +void SwLineNumberInfo::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + SwClient::Modify( pOld, pNew ); + SwDoc *pDoc = ((SwCharFmt*)GetRegisteredIn())->GetDoc(); + SwRootFrm* pRoot = pDoc->GetRootFrm(); + if( pRoot && pRoot->GetCurrShell() ) + { + pRoot->StartAllAction(); + pRoot->GetCurrShell()->AddPaintRect( pRoot->Frm() ); + pRoot->EndAllAction(); + } +} + diff --git a/sw/source/core/doc/list.cxx b/sw/source/core/doc/list.cxx new file mode 100644 index 000000000000..81f139bba99e --- /dev/null +++ b/sw/source/core/doc/list.cxx @@ -0,0 +1,303 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sw.hxx" + +#include <list.hxx> + +#include <vector> +#include <numrule.hxx> +#include <ndarr.hxx> +#include <node.hxx> +#include <pam.hxx> +#include <SwNodeNum.hxx> + +// ---------------------------------------------------------------------------- +// SwListImpl +// implementation class for SwList +// ---------------------------------------------------------------------------- +class SwListImpl +{ + public: + SwListImpl( const String sListId, + SwNumRule& rDefaultListStyle, + const SwNodes& rNodes ); + ~SwListImpl(); + + const String GetListId() const; + + const String GetDefaultListStyleName() const; + + void InsertListItem( SwNodeNum& rNodeNum, + const int nLevel ); + void RemoveListItem( SwNodeNum& rNodeNum ); + + void InvalidateListTree(); + void ValidateListTree(); + + void MarkListLevel( const int nListLevel, + const sal_Bool bValue ); + + bool IsListLevelMarked( const int nListLevel ) const; + + private: + // unique identifier of the list + const String msListId; + // default list style for the list items, identified by the list style name + String msDefaultListStyleName; + + // list trees for certain document ranges + typedef std::pair<SwNodeNum*, SwPaM*> tListTreeForRange; + typedef std::vector<tListTreeForRange> tListTrees; + tListTrees maListTrees; + + int mnMarkedListLevel; + + void NotifyItemsOnListLevel( const int nLevel ); +}; + +SwListImpl::SwListImpl( const String sListId, + SwNumRule& rDefaultListStyle, + const SwNodes& rNodes ) + : msListId( sListId ), + msDefaultListStyleName( rDefaultListStyle.GetName() ), + maListTrees(), + mnMarkedListLevel( MAXLEVEL ) +{ + // create empty list trees for the document ranges + const SwNode* pNode = rNodes[0]; + do + { + SwPaM aPam( *pNode, *pNode->EndOfSectionNode() ); + + SwNodeNum* pNumberTreeRootNode = new SwNodeNum( &rDefaultListStyle ); + SwPaM* pPam = new SwPaM( *(aPam.Start()), *(aPam.End()) ); + tListTreeForRange aListTreeForRange( pNumberTreeRootNode, pPam ); + maListTrees.push_back( aListTreeForRange ); + + pNode = pNode->EndOfSectionNode(); + if (pNode != &rNodes.GetEndOfContent()) + { + sal_uLong nIndex = pNode->GetIndex(); + nIndex++; + pNode = rNodes[nIndex]; + } + } + while ( pNode != &rNodes.GetEndOfContent() ); +} + +SwListImpl::~SwListImpl() +{ + tListTrees::iterator aNumberTreeIter; + for ( aNumberTreeIter = maListTrees.begin(); + aNumberTreeIter != maListTrees.end(); + ++aNumberTreeIter ) + { + SwNodeNum::HandleNumberTreeRootNodeDelete( *((*aNumberTreeIter).first) ); + delete (*aNumberTreeIter).first; + delete (*aNumberTreeIter).second; + } +} + +const String SwListImpl::GetListId() const +{ + return msListId; +} + +const String SwListImpl::GetDefaultListStyleName() const +{ + return msDefaultListStyleName; +} + +void SwListImpl::InsertListItem( SwNodeNum& rNodeNum, + const int nLevel ) +{ + const SwPosition aPosOfNodeNum( rNodeNum.GetPosition() ); + const SwNodes* pNodesOfNodeNum = &(aPosOfNodeNum.nNode.GetNode().GetNodes()); + + tListTrees::const_iterator aNumberTreeIter; + for ( aNumberTreeIter = maListTrees.begin(); + aNumberTreeIter != maListTrees.end(); + ++aNumberTreeIter ) + { + const SwPosition* pStart = (*aNumberTreeIter).second->Start(); + const SwPosition* pEnd = (*aNumberTreeIter).second->End(); + const SwNodes* pRangeNodes = &(pStart->nNode.GetNode().GetNodes()); + + if ( pRangeNodes == pNodesOfNodeNum && + *pStart <= aPosOfNodeNum && aPosOfNodeNum <= *pEnd) + { + (*aNumberTreeIter).first->AddChild( &rNodeNum, nLevel ); + + break; + } + } +} + +void SwListImpl::RemoveListItem( SwNodeNum& rNodeNum ) +{ + rNodeNum.RemoveMe(); +} + +void SwListImpl::InvalidateListTree() +{ + tListTrees::iterator aNumberTreeIter; + for ( aNumberTreeIter = maListTrees.begin(); + aNumberTreeIter != maListTrees.end(); + ++aNumberTreeIter ) + { + (*aNumberTreeIter).first->InvalidateTree(); + } +} + +void SwListImpl::ValidateListTree() +{ + tListTrees::iterator aNumberTreeIter; + for ( aNumberTreeIter = maListTrees.begin(); + aNumberTreeIter != maListTrees.end(); + ++aNumberTreeIter ) + { + (*aNumberTreeIter).first->NotifyInvalidChildren(); + } +} + +void SwListImpl::MarkListLevel( const int nListLevel, + const sal_Bool bValue ) +{ + if ( bValue ) + { + if ( nListLevel != mnMarkedListLevel ) + { + if ( mnMarkedListLevel != MAXLEVEL ) + { + // notify former marked list nodes + NotifyItemsOnListLevel( mnMarkedListLevel ); + } + + mnMarkedListLevel = nListLevel; + + // notify new marked list nodes + NotifyItemsOnListLevel( mnMarkedListLevel ); + } + } + else + { + if ( mnMarkedListLevel != MAXLEVEL ) + { + // notify former marked list nodes + NotifyItemsOnListLevel( mnMarkedListLevel ); + } + + mnMarkedListLevel = MAXLEVEL; + } +} + +bool SwListImpl::IsListLevelMarked( const int nListLevel ) const +{ + return nListLevel == mnMarkedListLevel; +} + +void SwListImpl::NotifyItemsOnListLevel( const int nLevel ) +{ + tListTrees::iterator aNumberTreeIter; + for ( aNumberTreeIter = maListTrees.begin(); + aNumberTreeIter != maListTrees.end(); + ++aNumberTreeIter ) + { + (*aNumberTreeIter).first->NotifyNodesOnListLevel( nLevel ); + } +} + +// ---------------------------------------------------------------------------- +// SwList +// ---------------------------------------------------------------------------- +SwList::SwList( const String sListId, + SwNumRule& rDefaultListStyle, + const SwNodes& rNodes ) + : mpListImpl( new SwListImpl( sListId, rDefaultListStyle, rNodes ) ) +{ +} + +SwList::~SwList() +{ + delete mpListImpl; +} + +const String SwList::GetListId() const +{ + return mpListImpl->GetListId(); +} + +const String SwList::GetDefaultListStyleName() const +{ + return mpListImpl->GetDefaultListStyleName(); +} + +void SwList::InsertListItem( SwNodeNum& rNodeNum, + const int nLevel ) +{ + mpListImpl->InsertListItem( rNodeNum, nLevel ); +} + +void SwList::RemoveListItem( SwNodeNum& rNodeNum ) +{ + mpListImpl->RemoveListItem( rNodeNum ); +} + +void SwList::InvalidateListTree() +{ + mpListImpl->InvalidateListTree(); +} + +void SwList::ValidateListTree() +{ + mpListImpl->ValidateListTree(); +} + +void SwList::MarkListLevel( const int nListLevel, + const sal_Bool bValue ) +{ + mpListImpl->MarkListLevel( nListLevel, bValue ); +} + +bool SwList::IsListLevelMarked( const int nListLevel ) const +{ + return mpListImpl->IsListLevelMarked( nListLevel ); +} + +//void SwList::ContinueList( SwList& rList ) +//{ +// mpListImpl->ContinueList( rList ); +//} +//const SwList* SwList::GetContinuedList() const +//{ +// return mpListImpl->GetContinuedList(); +//} +//void SwList::ClearContinuation() +//{ +// mpListImpl->ClearContinuation(); +//} diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx new file mode 100644 index 000000000000..8721d5d21164 --- /dev/null +++ b/sw/source/core/doc/notxtfrm.cxx @@ -0,0 +1,1098 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> +#include <tools/urlobj.hxx> +#include <vcl/print.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <svtools/imapobj.hxx> +#include <svtools/imap.hxx> +#include <svl/urihelper.hxx> +#include <svtools/soerr.hxx> +#include <sfx2/progress.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/printer.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/colritem.hxx> +#include <svx/xoutbmp.hxx> +#include <vcl/window.hxx> +#include <fmturl.hxx> +#include <fmtsrnd.hxx> +#include <frmfmt.hxx> +#include <swrect.hxx> +#include <fesh.hxx> +#include <doc.hxx> +#include <flyfrm.hxx> +#include <frmtool.hxx> +#include <viewopt.hxx> +#include <viewimp.hxx> +#include <pam.hxx> +#include <hints.hxx> +#include <rootfrm.hxx> +#include <dflyobj.hxx> +#include <pagefrm.hxx> +#include <notxtfrm.hxx> +#include <grfatr.hxx> +#include <charatr.hxx> +#include <fmtornt.hxx> +#include <ndnotxt.hxx> +#include <ndgrf.hxx> +#include <ndole.hxx> +#include <swregion.hxx> +#include <poolfmt.hxx> +#include <mdiexp.hxx> +#include <swwait.hxx> +#include <comcore.hrc> +#include <accessibilityoptions.hxx> +#include <com/sun/star/embed/EmbedMisc.hpp> +#include <com/sun/star/embed/EmbedStates.hpp> + +#include <svtools/embedhlp.hxx> +#include <svtools/chartprettypainter.hxx> +// --> OD 2009-03-05 #i99665# +#include <dview.hxx> +// <-- + +using namespace com::sun::star; + +#define DEFTEXTSIZE 12 + +extern void ClrContourCache( const SdrObject *pObj ); // TxtFly.Cxx + + +inline sal_Bool GetRealURL( const SwGrfNode& rNd, String& rTxt ) +{ + sal_Bool bRet = rNd.GetFileFilterNms( &rTxt, 0 ); + if( bRet ) + rTxt = URIHelper::removePassword( rTxt, INetURLObject::WAS_ENCODED, + INetURLObject::DECODE_UNAMBIGUOUS); + return bRet; +} + +void lcl_PaintReplacement( const SwRect &rRect, const String &rText, + const ViewShell &rSh, const SwNoTxtFrm *pFrm, + sal_Bool bDefect ) +{ + static Font *pFont = 0; + if ( !pFont ) + { + pFont = new Font(); + pFont->SetWeight( WEIGHT_BOLD ); + pFont->SetStyleName( aEmptyStr ); + pFont->SetName( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "Arial Unicode" ))); + pFont->SetFamily( FAMILY_SWISS ); + pFont->SetTransparent( sal_True ); + } + + Color aCol( COL_RED ); + FontUnderline eUnderline = UNDERLINE_NONE; + const SwFmtURL &rURL = pFrm->FindFlyFrm()->GetFmt()->GetURL(); + if( rURL.GetURL().Len() || rURL.GetMap() ) + { + sal_Bool bVisited = sal_False; + if ( rURL.GetMap() ) + { + ImageMap *pMap = (ImageMap*)rURL.GetMap(); + for( sal_uInt16 i = 0; i < pMap->GetIMapObjectCount(); i++ ) + { + IMapObject *pObj = pMap->GetIMapObject( i ); + if( rSh.GetDoc()->IsVisitedURL( pObj->GetURL() ) ) + { + bVisited = sal_True; + break; + } + } + } + else if ( rURL.GetURL().Len() ) + bVisited = rSh.GetDoc()->IsVisitedURL( rURL.GetURL() ); + + SwFmt *pFmt = rSh.GetDoc()->GetFmtFromPool( static_cast<sal_uInt16> + (bVisited ? RES_POOLCHR_INET_VISIT : RES_POOLCHR_INET_NORMAL ) ); + aCol = pFmt->GetColor().GetValue(); + eUnderline = pFmt->GetUnderline().GetLineStyle(); + } + + pFont->SetUnderline( eUnderline ); + pFont->SetColor( aCol ); + + const BitmapEx& rBmp = ViewShell::GetReplacementBitmap( bDefect != sal_False ); + Graphic::DrawEx( rSh.GetOut(), rText, *pFont, rBmp, rRect.Pos(), rRect.SSize() ); +} + +/************************************************************************* +|* +|* SwGrfFrm::SwGrfFrm(ViewShell * const,SwGrfNode *) +|* +|* Beschreibung +|* Ersterstellung JP 05.03.91 +|* Letzte Aenderung MA 03. Mar. 93 +|* +*************************************************************************/ + + +SwNoTxtFrm::SwNoTxtFrm(SwNoTxtNode * const pNode) + : SwCntntFrm(pNode) +{ + InitCtor(); +} + +// Initialisierung: z.Zt. Eintragen des Frames im Cache + + +void SwNoTxtFrm::InitCtor() +{ + nType = FRMC_NOTXT; + // Das Gewicht der Grafik ist 0, wenn sie noch nicht + // gelesen ist, < 0, wenn ein Lesefehler auftrat und + // Ersatzdarstellung angewendet werden musste und >0, + // wenn sie zur Verfuegung steht. + nWeight = 0; +} + +/************************************************************************* +|* +|* SwNoTxtNode::MakeFrm() +|* +|* Beschreibung +|* Ersterstellung JP 05.03.91 +|* Letzte Aenderung MA 03. Mar. 93 +|* +*************************************************************************/ + + +SwCntntFrm *SwNoTxtNode::MakeFrm() +{ + return new SwNoTxtFrm(this); +} + +/************************************************************************* +|* +|* SwNoTxtFrm::~SwNoTxtFrm() +|* +|* Beschreibung +|* Ersterstellung JP 05.03.91 +|* Letzte Aenderung MA 30. Apr. 96 +|* +*************************************************************************/ + +SwNoTxtFrm::~SwNoTxtFrm() +{ + StopAnimation(); +} + +/************************************************************************* +|* +|* void SwNoTxtFrm::Modify( SwHint * pOld, SwHint * pNew ) +|* +|* Beschreibung +|* Ersterstellung JP 05.03.91 +|* Letzte Aenderung JP 05.03.91 +|* +*************************************************************************/ + +void SetOutDev( ViewShell *pSh, OutputDevice *pOut ) +{ + pSh->pOut = pOut; +} + + + + +void lcl_ClearArea( const SwFrm &rFrm, + OutputDevice &rOut, const SwRect& rPtArea, + const SwRect &rGrfArea ) +{ + SwRegionRects aRegion( rPtArea, 4, 4 ); + aRegion -= rGrfArea; + + if ( aRegion.Count() ) + { + const SvxBrushItem *pItem; const Color *pCol; SwRect aOrigRect; + if ( rFrm.GetBackgroundBrush( pItem, pCol, aOrigRect, sal_False ) ) + for( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + ::DrawGraphic( pItem, &rOut, aOrigRect, aRegion[i] ); + else + { + // OD 2004-04-23 #116347# + rOut.Push( PUSH_FILLCOLOR|PUSH_LINECOLOR ); + rOut.SetFillColor( rFrm.GetShell()->Imp()->GetRetoucheColor()); + rOut.SetLineColor(); + for( sal_uInt16 i = 0; i < aRegion.Count(); ++i ) + rOut.DrawRect( aRegion[i].SVRect() ); + rOut.Pop(); + } + } +} + +/************************************************************************* +|* +|* void SwNoTxtFrm::Paint() +|* +|* Beschreibung +|* Ersterstellung JP 05.03.91 +|* Letzte Aenderung MA 10. Jan. 97 +|* +*************************************************************************/ + +void SwNoTxtFrm::Paint(SwRect const& rRect, SwPrintData const*const) const +{ + if ( Frm().IsEmpty() ) + return; + + const ViewShell* pSh = GetShell(); + if( !pSh->GetViewOptions()->IsGraphic() ) + { + StopAnimation(); + // OD 10.01.2003 #i6467# - no paint of placeholder for page preview + if ( pSh->GetWin() && !pSh->IsPreView() ) + { + const SwNoTxtNode* pNd = GetNode()->GetNoTxtNode(); + String aTxt( pNd->GetTitle() ); + if ( !aTxt.Len() && pNd->IsGrfNode() ) + GetRealURL( *(SwGrfNode*)pNd, aTxt ); + if( !aTxt.Len() ) + aTxt = FindFlyFrm()->GetFmt()->GetName(); + lcl_PaintReplacement( Frm(), aTxt, *pSh, this, sal_False ); + } + return; + } + + if( pSh->GetAccessibilityOptions()->IsStopAnimatedGraphics() || + // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export + !pSh->GetWin() ) + // <-- + StopAnimation(); + + SfxProgress::EnterLock(); //Keine Progress-Reschedules im Paint (SwapIn) + + OutputDevice *pOut = pSh->GetOut(); + pOut->Push(); + sal_Bool bClip = sal_True; + PolyPolygon aPoly; + + SwNoTxtNode& rNoTNd = *(SwNoTxtNode*)GetNode(); + SwGrfNode* pGrfNd = rNoTNd.GetGrfNode(); + if( pGrfNd ) + pGrfNd->SetFrameInPaint( sal_True ); + + // OD 16.04.2003 #i13147# - add 2nd parameter with value <sal_True> to + // method call <FindFlyFrm().GetContour(..)> to indicate that it is called + // for paint in order to avoid load of the intrinsic graphic. + if ( ( !pOut->GetConnectMetaFile() || + !pSh->GetWin() ) && + FindFlyFrm()->GetContour( aPoly, sal_True ) + ) + { + pOut->SetClipRegion( aPoly ); + bClip = sal_False; + } + + SwRect aOrigPaint( rRect ); + if ( HasAnimation() && pSh->GetWin() ) + { + aOrigPaint = Frm(); aOrigPaint += Prt().Pos(); + } + + SwRect aGrfArea( Frm() ); + SwRect aPaintArea( aGrfArea ); + aPaintArea._Intersection( aOrigPaint ); + + SwRect aNormal( Frm().Pos() + Prt().Pos(), Prt().SSize() ); + aNormal.Justify(); //Normalisiertes Rechteck fuer die Vergleiche + + if( aPaintArea.IsOver( aNormal ) ) + { + // berechne die 4 zu loeschenden Rechtecke + if( pSh->GetWin() ) + ::lcl_ClearArea( *this, *pSh->GetOut(), aPaintArea, aNormal ); + + // in der Schnittmenge vom PaintBereich und der Bitmap liegt + // der absolut sichtbare Bereich vom Frame + aPaintArea._Intersection( aNormal ); + + if ( bClip ) + pOut->IntersectClipRegion( aPaintArea.SVRect() ); + /// OD 25.09.2002 #99739# - delete unused 3rd parameter + PaintPicture( pOut, aGrfArea ); + } + else + // wenn nicht sichtbar, loesche einfach den angegebenen Bereich + lcl_ClearArea( *this, *pSh->GetOut(), aPaintArea, SwRect() ); + if( pGrfNd ) + pGrfNd->SetFrameInPaint( sal_False ); + + pOut->Pop(); + SfxProgress::LeaveLock(); +} + +/************************************************************************* +|* +|* void lcl_CalcRect( Point & aPt, Size & aDim, +|* sal_uInt16 nMirror ) +|* +|* Beschreibung Errechne die Position und die Groesse der Grafik im +|* Frame, entsprechen der aktuellen Grafik-Attribute +|* +|* Parameter Point& die Position im Frame ( auch Return-Wert ) +|* Size& die Groesse der Grafik ( auch Return-Wert ) +|* MirrorGrf akt. Spiegelungs-Attribut +|* Ersterstellung JP 04.03.91 +|* Letzte Aenderung JP 31.08.94 +|* +*************************************************************************/ + + +void lcl_CalcRect( Point& rPt, Size& rDim, sal_uInt16 nMirror ) +{ + if( nMirror == RES_MIRROR_GRAPH_VERT || nMirror == RES_MIRROR_GRAPH_BOTH ) + { + rPt.X() += rDim.Width() -1; + rDim.Width() = -rDim.Width(); + } + + if( nMirror == RES_MIRROR_GRAPH_HOR || nMirror == RES_MIRROR_GRAPH_BOTH ) + { + rPt.Y() += rDim.Height() -1; + rDim.Height() = -rDim.Height(); + } +} + +/************************************************************************* +|* +|* void SwNoTxtFrm::GetGrfArea() +|* +|* Beschreibung Errechne die Position und die Groesse der Bitmap +|* innerhalb des uebergebenem Rechtecks. +|* +|* Ersterstellung JP 03.09.91 +|* Letzte Aenderung MA 11. Oct. 94 +|* +*************************************************************************/ + +void SwNoTxtFrm::GetGrfArea( SwRect &rRect, SwRect* pOrigRect, + sal_Bool ) const +{ + // JP 23.01.2001: currently only used for scaling, cropping and mirroring + // the contour of graphics! + // all other is handled by the GraphicObject + + //In rRect wird das sichbare Rechteck der Grafik gesteckt. + //In pOrigRect werden Pos+Size der Gesamtgrafik gesteck. + + const SwAttrSet& rAttrSet = GetNode()->GetSwAttrSet(); + const SwCropGrf& rCrop = rAttrSet.GetCropGrf(); + sal_uInt16 nMirror = rAttrSet.GetMirrorGrf().GetValue(); + + if( rAttrSet.GetMirrorGrf().IsGrfToggle() ) + { + if( !(FindPageFrm()->GetVirtPageNum() % 2) ) + { + switch ( nMirror ) + { + case RES_MIRROR_GRAPH_DONT: nMirror = RES_MIRROR_GRAPH_VERT; break; + case RES_MIRROR_GRAPH_VERT: nMirror = RES_MIRROR_GRAPH_DONT; break; + case RES_MIRROR_GRAPH_HOR: nMirror = RES_MIRROR_GRAPH_BOTH; break; + default: nMirror = RES_MIRROR_GRAPH_HOR; break; + } + } + } + + //Grafik wird vom Node eingelesen falls notwendig. Kann aber schiefgehen. + long nLeftCrop, nRightCrop, nTopCrop, nBottomCrop; + Size aOrigSz( ((SwNoTxtNode*)GetNode())->GetTwipSize() ); + if ( !aOrigSz.Width() ) + { + aOrigSz.Width() = Prt().Width(); + nLeftCrop = -rCrop.GetLeft(); + nRightCrop = -rCrop.GetRight(); + } + else + { + nLeftCrop = Max( aOrigSz.Width() - + (rCrop.GetRight() + rCrop.GetLeft()), long(1) ); + const double nScale = double(Prt().Width()) / double(nLeftCrop); + nLeftCrop = long(nScale * -rCrop.GetLeft() ); + nRightCrop = long(nScale * -rCrop.GetRight() ); + } + + // crop values have to be mirrored too + if( nMirror == RES_MIRROR_GRAPH_VERT || nMirror == RES_MIRROR_GRAPH_BOTH ) + { + long nTmpCrop = nLeftCrop; + nLeftCrop = nRightCrop; + nRightCrop= nTmpCrop; + } + + if( !aOrigSz.Height() ) + { + aOrigSz.Height() = Prt().Height(); + nTopCrop = -rCrop.GetTop(); + nBottomCrop= -rCrop.GetBottom(); + } + else + { + nTopCrop = Max( aOrigSz.Height() - (rCrop.GetTop() + rCrop.GetBottom()), long(1) ); + const double nScale = double(Prt().Height()) / double(nTopCrop); + nTopCrop = long(nScale * -rCrop.GetTop() ); + nBottomCrop= long(nScale * -rCrop.GetBottom() ); + } + + // crop values have to be mirrored too + if( nMirror == RES_MIRROR_GRAPH_HOR || nMirror == RES_MIRROR_GRAPH_BOTH ) + { + long nTmpCrop = nTopCrop; + nTopCrop = nBottomCrop; + nBottomCrop= nTmpCrop; + } + + Size aVisSz( Prt().SSize() ); + Size aGrfSz( aVisSz ); + Point aVisPt( Frm().Pos() + Prt().Pos() ); + Point aGrfPt( aVisPt ); + + //Erst das 'sichtbare' Rect einstellen. + if ( nLeftCrop > 0 ) + { + aVisPt.X() += nLeftCrop; + aVisSz.Width() -= nLeftCrop; + } + if ( nTopCrop > 0 ) + { + aVisPt.Y() += nTopCrop; + aVisSz.Height() -= nTopCrop; + } + if ( nRightCrop > 0 ) + aVisSz.Width() -= nRightCrop; + if ( nBottomCrop > 0 ) + aVisSz.Height() -= nBottomCrop; + + rRect.Pos ( aVisPt ); + rRect.SSize( aVisSz ); + + //Ggf. Die Gesamtgrafik berechnen + if ( pOrigRect ) + { + Size aTmpSz( aGrfSz ); + aGrfPt.X() += nLeftCrop; + aTmpSz.Width() -= nLeftCrop + nRightCrop; + aGrfPt.Y() += nTopCrop; + aTmpSz.Height()-= nTopCrop + nBottomCrop; + + if( RES_MIRROR_GRAPH_DONT != nMirror ) + lcl_CalcRect( aGrfPt, aTmpSz, nMirror ); + + pOrigRect->Pos ( aGrfPt ); + pOrigRect->SSize( aTmpSz ); + } +} + +/************************************************************************* +|* +|* Size SwNoTxtFrm::GetSize() +|* +|* Beschreibung Gebe die Groesse des umgebenen FLys und +|* damit die der Grafik zurueck. +|* Ersterstellung JP 04.03.91 +|* Letzte Aenderung JP 31.08.94 +|* +*************************************************************************/ + + +const Size& SwNoTxtFrm::GetSize() const +{ + // gebe die Groesse des Frames zurueck + const SwFrm *pFly = FindFlyFrm(); + if( !pFly ) + pFly = this; + return pFly->Prt().SSize(); +} + +/************************************************************************* +|* +|* SwNoTxtFrm::MakeAll() +|* +|* Ersterstellung MA 29. Nov. 96 +|* Letzte Aenderung MA 29. Nov. 96 +|* +*************************************************************************/ + + +void SwNoTxtFrm::MakeAll() +{ + SwCntntNotify aNotify( this ); + SwBorderAttrAccess aAccess( SwFrm::GetCache(), this ); + const SwBorderAttrs &rAttrs = *aAccess.Get(); + + while ( !bValidPos || !bValidSize || !bValidPrtArea ) + { + MakePos(); + + if ( !bValidSize ) + Frm().Width( GetUpper()->Prt().Width() ); + + MakePrtArea( rAttrs ); + + if ( !bValidSize ) + { bValidSize = sal_True; + Format(); + } + } +} + +/************************************************************************* +|* +|* SwNoTxtFrm::Format() +|* +|* Beschreibung Errechne die Groesse der Bitmap, wenn noetig +|* Ersterstellung JP 11.03.91 +|* Letzte Aenderung MA 13. Mar. 96 +|* +*************************************************************************/ + + +void SwNoTxtFrm::Format( const SwBorderAttrs * ) +{ + const Size aNewSize( GetSize() ); + + // hat sich die Hoehe geaendert? + SwTwips nChgHght = IsVertical() ? + (SwTwips)(aNewSize.Width() - Prt().Width()) : + (SwTwips)(aNewSize.Height() - Prt().Height()); + if( nChgHght > 0) + Grow( nChgHght ); + else if( nChgHght < 0) + Shrink( Min(Prt().Height(), -nChgHght) ); +} + +/************************************************************************* +|* +|* SwNoTxtFrm::GetCharRect() +|* +|* Beschreibung +|* Ersterstellung SS 29-Apr-1991 +|* Letzte Aenderung MA 10. Oct. 94 +|* +|*************************************************************************/ + + +sal_Bool SwNoTxtFrm::GetCharRect( SwRect &rRect, const SwPosition& rPos, + SwCrsrMoveState *pCMS ) const +{ + if ( &rPos.nNode.GetNode() != (SwNode*)GetNode() ) + return sal_False; + + Calc(); + SwRect aFrameRect( Frm() ); + rRect = aFrameRect; + rRect.Pos( Frm().Pos() + Prt().Pos() ); + rRect.SSize( Prt().SSize() ); + + rRect.Justify(); + + // liegt die Bitmap ueberhaupt im sichtbaren Berich ? + if( !aFrameRect.IsOver( rRect ) ) + { + // wenn nicht dann steht der Cursor auf dem Frame + rRect = aFrameRect; + rRect.Width( 1 ); + } + else + rRect._Intersection( aFrameRect ); + + if ( pCMS ) + { + if ( pCMS->bRealHeight ) + { + pCMS->aRealHeight.Y() = rRect.Height(); + pCMS->aRealHeight.X() = 0; + } + } + + return sal_True; +} + + +sal_Bool SwNoTxtFrm::GetCrsrOfst(SwPosition* pPos, Point& , + SwCrsrMoveState* ) const +{ + SwCntntNode* pCNd = (SwCntntNode*)GetNode(); + pPos->nNode = *pCNd; + pPos->nContent.Assign( pCNd, 0 ); + return sal_True; +} + +#define CLEARCACHE( pNd ) {\ + (pNd)->GetGrfObj().ReleaseFromCache();\ + SwFlyFrm* pFly = FindFlyFrm();\ + if( pFly && pFly->GetFmt()->GetSurround().IsContour() )\ + {\ + ClrContourCache( pFly->GetVirtDrawObj() );\ + pFly->NotifyBackground( FindPageFrm(), Prt(), PREP_FLY_ATTR_CHG );\ + }\ +} + +void SwNoTxtFrm::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + sal_uInt16 nWhich = pNew ? pNew->Which() : pOld ? pOld->Which() : 0; + + // --> OD 2007-03-06 #i73788# + // no <SwCntntFrm::Modify(..)> for RES_LINKED_GRAPHIC_STREAM_ARRIVED + if ( RES_GRAPHIC_PIECE_ARRIVED != nWhich && + RES_GRAPHIC_ARRIVED != nWhich && + RES_GRF_REREAD_AND_INCACHE != nWhich && + RES_LINKED_GRAPHIC_STREAM_ARRIVED != nWhich ) + // <-- + { + SwCntntFrm::Modify( pOld, pNew ); + } + + sal_Bool bComplete = sal_True; + + switch( nWhich ) + { + case RES_OBJECTDYING: + break; + + case RES_GRF_REREAD_AND_INCACHE: + if( ND_GRFNODE == GetNode()->GetNodeType() ) + { + bComplete = sal_False; + SwGrfNode* pNd = (SwGrfNode*) GetNode(); + + ViewShell *pVSh = 0; + pNd->GetDoc()->GetEditShell( &pVSh ); + if( pVSh ) + { + GraphicAttr aAttr; + if( pNd->GetGrfObj().IsCached( pVSh->GetOut(), Point(), + Prt().SSize(), &pNd->GetGraphicAttr( aAttr, this ) )) + { + ViewShell *pSh = pVSh; + do { + SET_CURR_SHELL( pSh ); + if( pSh->GetWin() ) + { + if( pSh->IsPreView() ) + ::RepaintPagePreview( pSh, Frm().SVRect() ); + else + pSh->GetWin()->Invalidate( Frm().SVRect() ); + } + } while( pVSh != (pSh = (ViewShell*)pSh->GetNext() )); + } + else + pNd->SwapIn(); + } + } + break; + + case RES_UPDATE_ATTR: + case RES_FMT_CHG: + CLEARCACHE( (SwGrfNode*) GetNode() ) + break; + + case RES_ATTRSET_CHG: + { + sal_uInt16 n; + for( n = RES_GRFATR_BEGIN; n < RES_GRFATR_END; ++n ) + if( SFX_ITEM_SET == ((SwAttrSetChg*)pOld)->GetChgSet()-> + GetItemState( n, sal_False )) + { + CLEARCACHE( (SwGrfNode*) GetNode() ) + break; + } + if( RES_GRFATR_END == n ) // not found + return ; + } + break; + + case RES_GRAPHIC_PIECE_ARRIVED: + case RES_GRAPHIC_ARRIVED: + // --> OD 2007-03-06 #i73788# + // handle RES_LINKED_GRAPHIC_STREAM_ARRIVED as RES_GRAPHIC_ARRIVED + case RES_LINKED_GRAPHIC_STREAM_ARRIVED: + // <-- + if ( GetNode()->GetNodeType() == ND_GRFNODE ) + { + bComplete = sal_False; + SwGrfNode* pNd = (SwGrfNode*) GetNode(); + + CLEARCACHE( pNd ) + + SwRect aRect( Frm() ); + + ViewShell *pVSh = 0; + pNd->GetDoc()->GetEditShell( &pVSh ); + if( !pVSh ) + break; + + ViewShell *pSh = pVSh; + do { + SET_CURR_SHELL( pSh ); + if( pSh->IsPreView() ) + { + if( pSh->GetWin() ) + ::RepaintPagePreview( pSh, aRect ); + } + else if ( pSh->VisArea().IsOver( aRect ) && + OUTDEV_WINDOW == pSh->GetOut()->GetOutDevType() ) + { + // OD 27.11.2002 #105519# - invalidate instead of painting + pSh->GetWin()->Invalidate( aRect.SVRect() ); + } + + pSh = (ViewShell *)pSh->GetNext(); + } while( pSh != pVSh ); + } + break; + + default: + if ( !pNew || !isGRFATR(nWhich) ) + return; + } + + if( bComplete ) + { + InvalidatePrt(); + SetCompletePaint(); + } +} + +void lcl_correctlyAlignRect( SwRect& rAlignedGrfArea, const SwRect& rInArea, OutputDevice* pOut ) +{ + + if(!pOut) + return; + Rectangle aPxRect = pOut->LogicToPixel( rInArea.SVRect() ); + Rectangle aNewPxRect( aPxRect ); + while( aNewPxRect.Left() < aPxRect.Left() ) + { + rAlignedGrfArea.Left( rAlignedGrfArea.Left()+1 ); + aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() ); + } + while( aNewPxRect.Top() < aPxRect.Top() ) + { + rAlignedGrfArea.Top( rAlignedGrfArea.Top()+1 ); + aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() ); + } + while( aNewPxRect.Bottom() > aPxRect.Bottom() ) + { + rAlignedGrfArea.Bottom( rAlignedGrfArea.Bottom()-1 ); + aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() ); + } + while( aNewPxRect.Right() > aPxRect.Right() ) + { + rAlignedGrfArea.Right( rAlignedGrfArea.Right()-1 ); + aNewPxRect = pOut->LogicToPixel( rAlignedGrfArea.SVRect() ); + } +} + +// Ausgabe der Grafik. Hier wird entweder eine QuickDraw-Bmp oder +// eine Grafik vorausgesetzt. Ist nichts davon vorhanden, wird +// eine Ersatzdarstellung ausgegeben. +/// OD 25.09.2002 #99739# - delete unused 3rd parameter. +/// OD 25.09.2002 #99739# - use aligned rectangle for drawing graphic. +/// OD 25.09.2002 #99739# - pixel-align coordinations for drawing graphic. +void SwNoTxtFrm::PaintPicture( OutputDevice* pOut, const SwRect &rGrfArea ) const +{ + ViewShell* pShell = GetShell(); + + SwNoTxtNode& rNoTNd = *(SwNoTxtNode*)GetNode(); + SwGrfNode* pGrfNd = rNoTNd.GetGrfNode(); + SwOLENode* pOLENd = rNoTNd.GetOLENode(); + + const sal_Bool bPrn = pOut == rNoTNd.getIDocumentDeviceAccess()->getPrinter( false ) || + pOut->GetConnectMetaFile(); + + const bool bIsChart = pOLENd && ChartPrettyPainter::IsChart( pOLENd->GetOLEObj().GetObject() ); + + /// OD 25.09.2002 #99739# - calculate aligned rectangle from parameter <rGrfArea>. + /// Use aligned rectangle <aAlignedGrfArea> instead of <rGrfArea> in + /// the following code. + SwRect aAlignedGrfArea = rGrfArea; + ::SwAlignRect( aAlignedGrfArea, pShell ); + + if( !bIsChart ) + { + /// OD 25.09.2002 #99739# + /// Because for drawing a graphic left-top-corner and size coordinations are + /// used, these coordinations have to be determined on pixel level. + ::SwAlignGrfRect( &aAlignedGrfArea, *pOut ); + } + else //if( bIsChart ) + { + //#i78025# charts own borders are not completely visible + //the above pixel correction is not correct - at least not for charts + //so a different pixel correction is choosen here + //this might be a good idea for all other OLE objects also, + //but as I cannot oversee the consequences I fix it only for charts for now + lcl_correctlyAlignRect( aAlignedGrfArea, rGrfArea, pOut ); + } + + if( pGrfNd ) + { + sal_Bool bForceSwap = sal_False, bContinue = sal_True; + GraphicObject& rGrfObj = pGrfNd->GetGrfObj(); + + GraphicAttr aGrfAttr; + pGrfNd->GetGraphicAttr( aGrfAttr, this ); + + if( !bPrn ) + { + // --> OD 2007-01-02 #i73788# + if ( pGrfNd->IsLinkedInputStreamReady() ) + { + pGrfNd->UpdateLinkWithInputStream(); + } + // <-- + // --> OD 2008-01-30 #i85717# + // --> OD 2008-07-21 #i90395# - check, if asynchronous retrieval + // if input stream for the graphic is possible +// else if( GRAPHIC_DEFAULT == rGrfObj.GetType() && + else if ( ( rGrfObj.GetType() == GRAPHIC_DEFAULT || + rGrfObj.GetType() == GRAPHIC_NONE ) && + pGrfNd->IsLinkedFile() && + pGrfNd->IsAsyncRetrieveInputStreamPossible() ) + // <-- + { + Size aTmpSz; + ::sfx2::SvLinkSource* pGrfObj = pGrfNd->GetLink()->GetObj(); + if( !pGrfObj || + !pGrfObj->IsDataComplete() || + !(aTmpSz = pGrfNd->GetTwipSize()).Width() || + !aTmpSz.Height() || !pGrfNd->GetAutoFmtLvl() ) + { + // --> OD 2006-12-22 #i73788# + pGrfNd->TriggerAsyncRetrieveInputStream(); + // <-- + } + String aTxt( pGrfNd->GetTitle() ); + if ( !aTxt.Len() ) + GetRealURL( *pGrfNd, aTxt ); + ::lcl_PaintReplacement( aAlignedGrfArea, aTxt, *pShell, this, sal_False ); + bContinue = sal_False; + } + else if( rGrfObj.IsCached( pOut, aAlignedGrfArea.Pos(), + aAlignedGrfArea.SSize(), &aGrfAttr )) + { + rGrfObj.DrawWithPDFHandling( *pOut, + aAlignedGrfArea.Pos(), aAlignedGrfArea.SSize(), + &aGrfAttr ); + bContinue = sal_False; + } + } + + if( bContinue ) + { + const sal_Bool bSwapped = rGrfObj.IsSwappedOut(); + const sal_Bool bSwappedIn = 0 != pGrfNd->SwapIn( bPrn ); + if( bSwappedIn && rGrfObj.GetGraphic().IsSupportedGraphic()) + { + const sal_Bool bAnimate = rGrfObj.IsAnimated() && + !pShell->IsPreView() && + !pShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() && + // --> FME 2004-06-21 #i9684# Stop animation during printing/pdf export + pShell->GetWin(); + // <-- + + if( bAnimate && + FindFlyFrm() != ::GetFlyFromMarked( 0, pShell )) + { + OutputDevice* pVout; + if( pOut == pShell->GetOut() && SwRootFrm::FlushVout() ) + pVout = pOut, pOut = pShell->GetOut(); + else if( pShell->GetWin() && + OUTDEV_VIRDEV == pOut->GetOutDevType() ) + pVout = pOut, pOut = pShell->GetWin(); + else + pVout = 0; + + ASSERT( OUTDEV_VIRDEV != pOut->GetOutDevType() || + pShell->GetViewOptions()->IsPDFExport(), + "pOut sollte kein virtuelles Device sein" ); + + rGrfObj.StartAnimation( pOut, aAlignedGrfArea.Pos(), + aAlignedGrfArea.SSize(), long(this), + 0, GRFMGR_DRAW_STANDARD, pVout ); + } + else + rGrfObj.DrawWithPDFHandling( *pOut, + aAlignedGrfArea.Pos(), aAlignedGrfArea.SSize(), + &aGrfAttr ); + } + else + { + sal_uInt16 nResId = 0; + if( bSwappedIn ) + { + if( GRAPHIC_NONE == rGrfObj.GetType() ) + nResId = STR_COMCORE_READERROR; + else if ( !rGrfObj.GetGraphic().IsSupportedGraphic() ) + nResId = STR_COMCORE_CANT_SHOW; + } + ((SwNoTxtFrm*)this)->nWeight = -1; + String aText; + if ( !nResId && + !(aText = pGrfNd->GetTitle()).Len() && + (!GetRealURL( *pGrfNd, aText ) || !aText.Len())) + { + nResId = STR_COMCORE_READERROR; + } + if ( nResId ) + aText = SW_RESSTR( nResId ); + + ::lcl_PaintReplacement( aAlignedGrfArea, aText, *pShell, this, sal_True ); + } + + //Beim Drucken duerfen wir nicht die Grafiken sammeln... + if( bSwapped && bPrn ) + bForceSwap = sal_True; + } + if( bForceSwap ) + pGrfNd->SwapOut(); + } + else if( bIsChart + //charts must be painted resolution dependent!! #i82893#, #i75867# + && ChartPrettyPainter::ShouldPrettyPaintChartOnThisDevice( pOut ) + && svt::EmbeddedObjectRef::TryRunningState( pOLENd->GetOLEObj().GetOleRef() ) + && ChartPrettyPainter::DoPrettyPaintChart( uno::Reference< frame::XModel >( + pOLENd->GetOLEObj().GetOleRef()->getComponent(), uno::UNO_QUERY), pOut, aAlignedGrfArea.SVRect() ) ) + { + (void)(0);//all was done in if statement + } + else if( pOLENd ) + { + // --> OD 2009-03-05 #i99665# + // Adjust AntiAliasing mode at output device for chart OLE + const sal_uInt16 nFormerAntialiasingAtOutput( pOut->GetAntialiasing() ); + if ( pOLENd->IsChart() && + pShell->Imp()->GetDrawView()->IsAntiAliasing() ) + { + const sal_uInt16 nAntialiasingForChartOLE = + nFormerAntialiasingAtOutput | ANTIALIASING_PIXELSNAPHAIRLINE; + pOut->SetAntialiasing( nAntialiasingForChartOLE ); + } + // <-- + + Point aPosition(aAlignedGrfArea.Pos()); + Size aSize(aAlignedGrfArea.SSize()); + + // Im BrowseModus gibt es nicht unbedingt einen Drucker und + // damit kein JobSetup, also legen wir eines an ... + const JobSetup* pJobSetup = pOLENd->getIDocumentDeviceAccess()->getJobsetup(); + sal_Bool bDummyJobSetup = 0 == pJobSetup; + if( bDummyJobSetup ) + pJobSetup = new JobSetup(); + + // #i42323# + // The reason for #114233# is gone, so i remove it again + //TODO/LATER: is it a problem that the JopSetup isn't used? + //xRef->DoDraw( pOut, aAlignedGrfArea.Pos(), aAlignedGrfArea.SSize(), *pJobSetup ); + + // get hi-contrast image, but never for printing + Graphic* pGraphic = NULL; + if (pOut && !bPrn && Application::GetSettings().GetStyleSettings().GetHighContrastMode() ) + pGraphic = pOLENd->GetHCGraphic(); + + // when it is not possible to get HC-representation, the original image should be used + if ( !pGraphic ) + pGraphic = pOLENd->GetGraphic(); + + if ( pGraphic && pGraphic->GetType() != GRAPHIC_NONE ) + { + pGraphic->Draw( pOut, aPosition, aSize ); + + // shade the representation if the object is activated outplace + uno::Reference < embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef(); + if ( xObj.is() && xObj->getCurrentState() == embed::EmbedStates::ACTIVE ) + { + ::svt::EmbeddedObjectRef::DrawShading( Rectangle( aPosition, aSize ), pOut ); + } + } + else + ::svt::EmbeddedObjectRef::DrawPaintReplacement( Rectangle( aPosition, aSize ), pOLENd->GetOLEObj().GetCurrentPersistName(), pOut ); + + if( bDummyJobSetup ) + delete pJobSetup; // ... und raeumen wieder auf. + + sal_Int64 nMiscStatus = pOLENd->GetOLEObj().GetOleRef()->getStatus( pOLENd->GetAspect() ); + if ( !bPrn && pShell->ISA( SwCrsrShell ) && + nMiscStatus & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE ) + { + const SwFlyFrm *pFly = FindFlyFrm(); + ASSERT( pFly, "OLE not in FlyFrm" ); + ((SwFEShell*)pShell)->ConnectObj( pOLENd->GetOLEObj().GetObject(), pFly->Prt(), pFly->Frm()); + } + + // --> OD 2009-03-05 #i99665# + if ( pOLENd->IsChart() && + pShell->Imp()->GetDrawView()->IsAntiAliasing() ) + { + pOut->SetAntialiasing( nFormerAntialiasingAtOutput ); + } + // <-- + } +} + + +sal_Bool SwNoTxtFrm::IsTransparent() const +{ + const ViewShell* pSh = GetShell(); + if ( !pSh || !pSh->GetViewOptions()->IsGraphic() ) + return sal_True; + + const SwGrfNode *pNd; + if( 0 != (pNd = GetNode()->GetGrfNode()) ) + return pNd->IsTransparent(); + + //#29381# OLE sind immer Transparent. + return sal_True; +} + + +void SwNoTxtFrm::StopAnimation( OutputDevice* pOut ) const +{ + //animierte Grafiken anhalten + SwGrfNode* pGrfNd = (SwGrfNode*)GetNode()->GetGrfNode(); + if( pGrfNd && pGrfNd->IsAnimated() ) + pGrfNd->GetGrfObj().StopAnimation( pOut, long(this) ); +} + + +sal_Bool SwNoTxtFrm::HasAnimation() const +{ + const SwGrfNode* pGrfNd = GetNode()->GetGrfNode(); + return pGrfNd && pGrfNd->IsAnimated(); +} + + + diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx new file mode 100644 index 000000000000..2333169f2222 --- /dev/null +++ b/sw/source/core/doc/number.cxx @@ -0,0 +1,1686 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#include <string.h> +#include <vcl/font.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/numitem.hxx> +#include <fmtornt.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <charfmt.hxx> +#include <paratr.hxx> +#include <frmfmt.hxx> +#include <ndtxt.hxx> +#include <docary.hxx> +#ifndef _DOCSH_HXX +#include <docsh.hxx> +#endif +#include <SwStyleNameMapper.hxx> +// --> OD 2006-06-28 #b6440955# +// Needed to load default bullet list configuration +#include <unotools/configitem.hxx> +// <-- +#include <numrule.hxx> +#include <SwNodeNum.hxx> + +#include <hash_map> +// --> OD 2008-02-19 #refactorlists# +#include <list.hxx> +#include <algorithm> +// <-- +// --> OD 2008-06-06 #i89178# +#include <unotools/saveopt.hxx> +// <-- +// --> OD 2008-07-08 #i91400# +#include <IDocumentListsAccess.hxx> +// <-- + +using namespace ::com::sun::star; + + +sal_uInt16 SwNumRule::nRefCount = 0; +SwNumFmt* SwNumRule::aBaseFmts[ RULE_END ][ MAXLEVEL ] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; +// --> OD 2008-02-11 #newlistlevelattrs# +SwNumFmt* SwNumRule::aLabelAlignmentBaseFmts[ RULE_END ][ MAXLEVEL ] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; + +char sOutline[] = "Outline"; +char* SwNumRule::pDefOutlineName = sOutline; + +// #i30312# +sal_uInt16 SwNumRule::aDefNumIndents[ MAXLEVEL ] = { +//inch: 0,5 1,0 1,5 2,0 2,5 3,0 3,5 4,0 4,5 5,0 + 1440/4, 1440/2, 1440*3/4, 1440, 1440*5/4, 1440*3/2, 1440*7/4, 1440*2, + 1440*9/4, 1440*5/2 +}; + +const SwNumFmt& SwNumRule::Get( sal_uInt16 i ) const +{ + ASSERT_ID( i < MAXLEVEL && eRuleType < RULE_END, ERR_NUMLEVEL); + return aFmts[ i ] + ? *aFmts[ i ] + // --> OD 2008-02-11 #newlistlevelattrs# + : ( meDefaultNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION + ? *aBaseFmts[ eRuleType ][ i ] + : *aLabelAlignmentBaseFmts[ eRuleType ][ i ] ); + // <-- +} + +const SwNumFmt* SwNumRule::GetNumFmt( sal_uInt16 i ) const +{ + const SwNumFmt * pResult = NULL; + + ASSERT_ID( i < MAXLEVEL && eRuleType < RULE_END, ERR_NUMLEVEL); + if ( i < MAXLEVEL && eRuleType < RULE_END) + { + pResult = aFmts[ i ]; + } + + return pResult; +} + +// --> OD 2008-07-08 #i91400# +void SwNumRule::SetName( const String & rName, + IDocumentListsAccess& rDocListAccess) +// <-- +{ + if ( sName != rName ) + { + if (pNumRuleMap) + { + pNumRuleMap->erase(sName); + (*pNumRuleMap)[rName] = this; + + // --> OD 2008-07-08 #i91400# + if ( GetDefaultListId().Len() > 0 ) + { + rDocListAccess.trackChangeOfListStyleName( sName, rName ); + } + // <-- + } + + sName = rName; + } +} + +// --> OD 2008-02-19 #refactorlists# +void SwNumRule::GetTxtNodeList( SwNumRule::tTxtNodeList& rTxtNodeList ) const +{ + rTxtNodeList = maTxtNodeList; +} + +SwNumRule::tTxtNodeList::size_type SwNumRule::GetTxtNodeListSize() const +{ + return maTxtNodeList.size(); +} + +void SwNumRule::AddTxtNode( SwTxtNode& rTxtNode ) +{ + tTxtNodeList::iterator aIter = + std::find( maTxtNodeList.begin(), maTxtNodeList.end(), &rTxtNode ); + + if ( aIter == maTxtNodeList.end() ) + { + maTxtNodeList.push_back( &rTxtNode ); + } +} + +void SwNumRule::RemoveTxtNode( SwTxtNode& rTxtNode ) +{ + tTxtNodeList::iterator aIter = + std::find( maTxtNodeList.begin(), maTxtNodeList.end(), &rTxtNode ); + + if ( aIter != maTxtNodeList.end() ) + { + maTxtNodeList.erase( aIter ); + } +} +// <-- + +void SwNumRule::SetNumRuleMap(std::hash_map<String, SwNumRule *, StringHash> * + _pNumRuleMap) +{ + pNumRuleMap = _pNumRuleMap; +} + +sal_uInt16 SwNumRule::GetNumIndent( sal_uInt8 nLvl ) +{ + ASSERT( MAXLEVEL > nLvl, "NumLevel is out of range" ); + return aDefNumIndents[ nLvl ]; +} + +sal_uInt16 SwNumRule::GetBullIndent( sal_uInt8 nLvl ) +{ + ASSERT( MAXLEVEL > nLvl, "NumLevel is out of range" ); + return aDefNumIndents[ nLvl ]; +} + + + +static void lcl_SetRuleChgd( SwTxtNode& rNd, sal_uInt8 nLevel ) +{ + if( rNd.GetActualListLevel() == nLevel ) + rNd.NumRuleChgd(); +} +/* -----------------------------22.02.01 13:41-------------------------------- + + ---------------------------------------------------------------------------*/ +SwNumFmt::SwNumFmt() : + SvxNumberFormat(SVX_NUM_ARABIC), + SwClient( 0 ), + pVertOrient(new SwFmtVertOrient( 0, text::VertOrientation::NONE)) +{ +} +/* -----------------------------22.02.01 13:42-------------------------------- + + ---------------------------------------------------------------------------*/ +SwNumFmt::SwNumFmt( const SwNumFmt& rFmt) : + SvxNumberFormat(rFmt), + SwClient( rFmt.pRegisteredIn ), + pVertOrient(new SwFmtVertOrient( 0, rFmt.GetVertOrient())) +{ + sal_Int16 eMyVertOrient = rFmt.GetVertOrient(); + SetGraphicBrush( rFmt.GetBrush(), &rFmt.GetGraphicSize(), + &eMyVertOrient); +} +/* -----------------------------22.02.01 13:58-------------------------------- + + ---------------------------------------------------------------------------*/ +SwNumFmt::SwNumFmt(const SvxNumberFormat& rNumFmt, SwDoc* pDoc) : + SvxNumberFormat(rNumFmt), + pVertOrient(new SwFmtVertOrient( 0, rNumFmt.GetVertOrient())) +{ + sal_Int16 eMyVertOrient = rNumFmt.GetVertOrient(); + SetGraphicBrush( rNumFmt.GetBrush(), &rNumFmt.GetGraphicSize(), + &eMyVertOrient); + const String& rCharStyleName = rNumFmt.SvxNumberFormat::GetCharFmtName(); + if( rCharStyleName.Len() ) + { + SwCharFmt* pCFmt = pDoc->FindCharFmtByName( rCharStyleName ); + if( !pCFmt ) + { + sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCharStyleName, + nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); + pCFmt = nId != USHRT_MAX + ? pDoc->GetCharFmtFromPool( nId ) + : pDoc->MakeCharFmt( rCharStyleName, 0 ); + } + pCFmt->Add( this ); + } + else if( GetRegisteredIn() ) + pRegisteredIn->Remove( this ); + +} +/* -----------------------------22.02.01 13:42-------------------------------- + + ---------------------------------------------------------------------------*/ +SwNumFmt::~SwNumFmt() +{ + delete pVertOrient; +} +/* -----------------------------02.07.01 15:37-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::NotifyGraphicArrived() +{ + if( GetCharFmt() ) + UpdateNumNodes( (SwDoc*)GetCharFmt()->GetDoc() ); +} + +// #i22362# +sal_Bool SwNumFmt::IsEnumeration() const +{ + // --> FME 2004-08-12 #i30655# native numbering did not work any longer + // using this code. Therefore HBRINKM and I agreed upon defining + // IsEnumeration() as !IsItemize() + return !IsItemize(); + // <-- + + /* + sal_Bool bResult; + + switch(GetNumberingType()) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_ROMAN_UPPER: + case SVX_NUM_ROMAN_LOWER: + case SVX_NUM_ARABIC: + case SVX_NUM_PAGEDESC: + case SVX_NUM_CHARS_UPPER_LETTER_N: + case SVX_NUM_CHARS_LOWER_LETTER_N: + bResult = sal_True; + + break; + + default: + bResult = sal_False; + } + + return bResult; + */ +} + +// #i29560# +sal_Bool SwNumFmt::IsItemize() const +{ + sal_Bool bResult; + + switch(GetNumberingType()) + { + case SVX_NUM_CHAR_SPECIAL: + case SVX_NUM_BITMAP: + bResult = sal_True; + + break; + + default: + bResult = sal_False; + } + + return bResult; + +} + + +/* -----------------------------23.02.01 09:28-------------------------------- + + ---------------------------------------------------------------------------*/ +SwNumFmt& SwNumFmt::operator=( const SwNumFmt& rNumFmt) +{ + SvxNumberFormat::operator=(rNumFmt); + if( rNumFmt.GetRegisteredIn() ) + rNumFmt.pRegisteredIn->Add( this ); + else if( GetRegisteredIn() ) + pRegisteredIn->Remove( this ); + return *this; +} +/* -----------------------------23.02.01 09:28-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool SwNumFmt::operator==( const SwNumFmt& rNumFmt) const +{ + sal_Bool bRet = SvxNumberFormat::operator==(rNumFmt) && + pRegisteredIn == rNumFmt.pRegisteredIn; + return bRet; +} + +/* -----------------------------22.02.01 13:44-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::SetCharFmt( SwCharFmt* pChFmt) +{ + if( pChFmt ) + pChFmt->Add( this ); + else if( GetRegisteredIn() ) + pRegisteredIn->Remove( this ); +} +/* -----------------------------22.02.01 13:45-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::Modify( SfxPoolItem* pOld, SfxPoolItem* pNew ) +{ + // dann suche mal in dem Doc nach dem NumRules-Object, in dem dieses + // NumFormat gesetzt ist. Das Format muss es nicht geben! + const SwCharFmt* pFmt = 0; + switch( pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ) + { + case RES_ATTRSET_CHG: + case RES_FMT_CHG: + pFmt = GetCharFmt(); + break; + } + + if( pFmt && !pFmt->GetDoc()->IsInDtor() ) + UpdateNumNodes( (SwDoc*)pFmt->GetDoc() ); + else + SwClient::Modify( pOld, pNew ); +} +/* -----------------------------23.02.01 11:08-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::SetCharFmtName(const String& rSet) +{ + SvxNumberFormat::SetCharFmtName(rSet); +} +/* -----------------------------22.02.01 13:47-------------------------------- + + ---------------------------------------------------------------------------*/ +const String& SwNumFmt::GetCharFmtName() const +{ + if((SwCharFmt*)pRegisteredIn) + return ((SwCharFmt*)pRegisteredIn)->GetName(); + else + return aEmptyStr; +} +/* -----------------------------22.02.01 16:05-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::SetGraphicBrush( const SvxBrushItem* pBrushItem, const Size* pSize, + const sal_Int16* pOrient) +{ + if(pOrient) + pVertOrient->SetVertOrient( *pOrient ); + SvxNumberFormat::SetGraphicBrush( pBrushItem, pSize, pOrient); +} +/* -----------------------------22.02.01 16:05-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::SetVertOrient(sal_Int16 eSet) +{ + SvxNumberFormat::SetVertOrient(eSet); +} +/* -----------------------------22.02.01 16:05-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Int16 SwNumFmt::GetVertOrient() const +{ + return SvxNumberFormat::GetVertOrient(); +} +/* -----------------------------22.02.01 13:54-------------------------------- + + ---------------------------------------------------------------------------*/ +void SwNumFmt::UpdateNumNodes( SwDoc* pDoc ) +{ + sal_Bool bDocIsModified = pDoc->IsModified(); + sal_Bool bFnd = sal_False; + const SwNumRule* pRule; + for( sal_uInt16 n = pDoc->GetNumRuleTbl().Count(); !bFnd && n; ) + { + pRule = pDoc->GetNumRuleTbl()[ --n ]; + for( sal_uInt8 i = 0; i < MAXLEVEL; ++i ) + if( pRule->GetNumFmt( i ) == this ) + { + // --> OD 2008-02-19 #refactorlists# +// const String& rRuleNm = pRule->GetName(); + +// SwModify* pMod; +// const SfxPoolItem* pItem; +// sal_uInt16 k, nMaxItems = pDoc->GetAttrPool().GetItemCount( +// RES_PARATR_NUMRULE ); +// for( k = 0; k < nMaxItems; ++k ) +// if( 0 != (pItem = pDoc->GetAttrPool().GetItem( +// RES_PARATR_NUMRULE, k ) ) && +// 0 != ( pMod = (SwModify*)((SwNumRuleItem*)pItem)-> +// GetDefinedIn()) && +// ((SwNumRuleItem*)pItem)->GetValue() == rRuleNm ) +// { +// if( pMod->IsA( TYPE( SwFmt )) ) +// { +// SwNumRuleInfo aInfo( rRuleNm ); +// pMod->GetInfo( aInfo ); + +// for( sal_uLong nFirst = 0, nLast = aInfo.GetList().Count(); +// nFirst < nLast; ++nFirst ) +// lcl_SetRuleChgd( +// *aInfo.GetList().GetObject( nFirst ), i ); +// } +// else if( ((SwTxtNode*)pMod)->GetNodes().IsDocNodes() ) +// lcl_SetRuleChgd( *(SwTxtNode*)pMod, i ); +// } + SwNumRule::tTxtNodeList aTxtNodeList; + pRule->GetTxtNodeList( aTxtNodeList ); + for ( SwNumRule::tTxtNodeList::iterator aIter = aTxtNodeList.begin(); + aIter != aTxtNodeList.end(); ++aIter ) + { + lcl_SetRuleChgd( *(*aIter), i ); + } + // <-- + bFnd = sal_True; + break; + } + } + + if( bFnd && !bDocIsModified ) + pDoc->ResetModified(); +} +/* -----------------------------31.05.01 16:08-------------------------------- + + ---------------------------------------------------------------------------*/ +const SwFmtVertOrient* SwNumFmt::GetGraphicOrientation() const +{ + sal_Int16 eOrient = SvxNumberFormat::GetVertOrient(); + if(text::VertOrientation::NONE == eOrient) + return 0; + else + { + pVertOrient->SetVertOrient(eOrient); + return pVertOrient; + } +} + +#ifdef DBG_UTIL +long int SwNumRule::nInstances = 0; +#endif + +// --> OD 2008-02-11 #newlistlevelattrs# +// handle new parameter <eDefaultNumberFormatPositionAndSpaceMode> +SwNumRule::SwNumRule( const String& rNm, + const SvxNumberFormat::SvxNumPositionAndSpaceMode eDefaultNumberFormatPositionAndSpaceMode, + SwNumRuleType eType, + sal_Bool bAutoFlg ) + : maTxtNodeList(), + // --> OD 2008-03-03 #refactorlists# + maParagraphStyleList(), + // <-- + pNumRuleMap(0), + sName( rNm ), + eRuleType( eType ), + nPoolFmtId( USHRT_MAX ), + nPoolHelpId( USHRT_MAX ), + nPoolHlpFileId( UCHAR_MAX ), + bAutoRuleFlag( bAutoFlg ), + bInvalidRuleFlag( sal_True ), + bContinusNum( sal_False ), + bAbsSpaces( sal_False ), + // --> OD 2005-10-21 - initialize member <mbCountPhantoms> + mbCountPhantoms( true ), + // <-- + // --> OD 2008-02-11 #newlistlevelattrs# + meDefaultNumberFormatPositionAndSpaceMode( eDefaultNumberFormatPositionAndSpaceMode ), + // <-- + // --> OD 2008-04-03 #refactorlists# + msDefaultListId() + // <-- +{ +#ifdef DBG_UTIL + nSerial = nInstances++; +#endif + + if( !nRefCount++ ) // zum erstmal, also initialisiern + { + SwNumFmt* pFmt; + sal_uInt8 n; + + // numbering: + // position-and-space mode LABEL_WIDTH_AND_POSITION: + for( n = 0; n < MAXLEVEL; ++n ) + { + pFmt = new SwNumFmt; + pFmt->SetIncludeUpperLevels( 1 ); + pFmt->SetStart( 1 ); + pFmt->SetLSpace( lNumIndent ); + pFmt->SetAbsLSpace( lNumIndent + SwNumRule::GetNumIndent( n ) ); + pFmt->SetFirstLineOffset( lNumFirstLineOffset ); + pFmt->SetSuffix( aDotStr ); + // --> OD 2006-06-29 #b6440955# + pFmt->SetBulletChar( numfunc::GetBulletChar(n)); + // <-- + SwNumRule::aBaseFmts[ NUM_RULE ][ n ] = pFmt; + } + // --> OD 2008-02-11 #newlistlevelattrs# + // position-and-space mode LABEL_ALIGNMENT + // first line indent of general numbering in inch: -0,25 inch + const long cFirstLineIndent = -1440/4; + // indent values of general numbering in inch: + // 0,5 0,75 1,0 1,25 1,5 + // 1,75 2,0 2,25 2,5 2,75 + const long cIndentAt[ MAXLEVEL ] = { + 1440/2, 1440*3/4, 1440, 1440*5/4, 1440*3/2, + 1440*7/4, 1440*2, 1440*9/4, 1440*5/2, 1440*11/4 }; + for( n = 0; n < MAXLEVEL; ++n ) + { + pFmt = new SwNumFmt; + pFmt->SetIncludeUpperLevels( 1 ); + pFmt->SetStart( 1 ); + // --> OD 2008-01-15 #newlistlevelattrs# + pFmt->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + pFmt->SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + pFmt->SetListtabPos( cIndentAt[ n ] ); + pFmt->SetFirstLineIndent( cFirstLineIndent ); + pFmt->SetIndentAt( cIndentAt[ n ] ); + // <-- + pFmt->SetSuffix( aDotStr ); + pFmt->SetBulletChar( numfunc::GetBulletChar(n)); + SwNumRule::aLabelAlignmentBaseFmts[ NUM_RULE ][ n ] = pFmt; + } + // <-- + + // outline: + // position-and-space mode LABEL_WIDTH_AND_POSITION: + for( n = 0; n < MAXLEVEL; ++n ) + { + pFmt = new SwNumFmt; + pFmt->SetNumberingType(SVX_NUM_NUMBER_NONE); + pFmt->SetIncludeUpperLevels( MAXLEVEL ); + pFmt->SetStart( 1 ); + pFmt->SetCharTextDistance( lOutlineMinTextDistance ); + // --> OD 2006-06-29 #b6440955# + pFmt->SetBulletChar( numfunc::GetBulletChar(n)); + // <-- + SwNumRule::aBaseFmts[ OUTLINE_RULE ][ n ] = pFmt; + } + // --> OD 2008-02-11 #newlistlevelattrs# + // position-and-space mode LABEL_ALIGNMENT: + // indent values of default outline numbering in inch: + // 0,3 0,4 0,5 0,6 0,7 + // 0,8 0,9 1,0 1,1 1,2 + const long cOutlineIndentAt[ MAXLEVEL ] = { + 1440*3/10, 1440*2/5, 1440/2, 1440*3/5, 1440*7/10, + 1440*4/5, 1440*9/10, 1440, 1440*11/10, 1440*6/5 }; + for( n = 0; n < MAXLEVEL; ++n ) + { + pFmt = new SwNumFmt; + pFmt->SetNumberingType(SVX_NUM_NUMBER_NONE); + pFmt->SetIncludeUpperLevels( MAXLEVEL ); + pFmt->SetStart( 1 ); + pFmt->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + pFmt->SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + pFmt->SetListtabPos( cOutlineIndentAt[ n ] ); + pFmt->SetFirstLineIndent( -cOutlineIndentAt[ n ] ); + pFmt->SetIndentAt( cOutlineIndentAt[ n ] ); + pFmt->SetBulletChar( numfunc::GetBulletChar(n)); + SwNumRule::aLabelAlignmentBaseFmts[ OUTLINE_RULE ][ n ] = pFmt; + } + // <-- + } + memset( aFmts, 0, sizeof( aFmts )); + ASSERT( sName.Len(), "NumRule ohne Namen!" ); +} + +SwNumRule::SwNumRule( const SwNumRule& rNumRule ) + : maTxtNodeList(), + // --> OD 2008-03-03 #refactorlists# + maParagraphStyleList(), + // <-- + pNumRuleMap(0), + sName( rNumRule.sName ), + eRuleType( rNumRule.eRuleType ), + nPoolFmtId( rNumRule.GetPoolFmtId() ), + nPoolHelpId( rNumRule.GetPoolHelpId() ), + nPoolHlpFileId( rNumRule.GetPoolHlpFileId() ), + bAutoRuleFlag( rNumRule.bAutoRuleFlag ), + bInvalidRuleFlag( sal_True ), + bContinusNum( rNumRule.bContinusNum ), + bAbsSpaces( rNumRule.bAbsSpaces ), + // --> OD 2005-10-21 - initialize member <mbCountPhantoms> + mbCountPhantoms( true ), + // <-- + // --> OD 2008-02-11 #newlistlevelattrs# + meDefaultNumberFormatPositionAndSpaceMode( rNumRule.meDefaultNumberFormatPositionAndSpaceMode ), + // <-- + // --> OD 2008-04-03 #refactorlists# + msDefaultListId( rNumRule.msDefaultListId ) + // <-- +{ +#ifdef DBG_UTIL + nSerial = nInstances++; +#endif + + ++nRefCount; + memset( aFmts, 0, sizeof( aFmts )); + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + if( rNumRule.aFmts[ n ] ) + Set( n, *rNumRule.aFmts[ n ] ); +} + +SwNumRule::~SwNumRule() +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + delete aFmts[ n ]; + + if (pNumRuleMap) + { + pNumRuleMap->erase(GetName()); + } + + if( !--nRefCount ) // der letzte macht die Tuer zu + { + // Nummerierung: + SwNumFmt** ppFmts = (SwNumFmt**)SwNumRule::aBaseFmts; + int n; + + for( n = 0; n < MAXLEVEL; ++n, ++ppFmts ) + delete *ppFmts, *ppFmts = 0; + + // Gliederung: + for( n = 0; n < MAXLEVEL; ++n, ++ppFmts ) + delete *ppFmts, *ppFmts = 0; + + // --> OD 2008-02-11 #newlistlevelattrs# + ppFmts = (SwNumFmt**)SwNumRule::aLabelAlignmentBaseFmts; + for( n = 0; n < MAXLEVEL; ++n, ++ppFmts ) + delete *ppFmts, *ppFmts = 0; + for( n = 0; n < MAXLEVEL; ++n, ++ppFmts ) + delete *ppFmts, *ppFmts = 0; + // <-- + } + + // --> OD 2008-02-19 #refactorlists# + maTxtNodeList.clear(); + maParagraphStyleList.clear(); + // <-- +} + +void SwNumRule::CheckCharFmts( SwDoc* pDoc ) +{ + SwCharFmt* pFmt; + for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) + if( aFmts[ n ] && 0 != ( pFmt = aFmts[ n ]->GetCharFmt() ) && + pFmt->GetDoc() != pDoc ) + { + // dann kopieren! + SwNumFmt* pNew = new SwNumFmt( *aFmts[ n ] ); + pNew->SetCharFmt( pDoc->CopyCharFmt( *pFmt ) ); + delete aFmts[ n ]; + aFmts[ n ] = pNew; + } +} + +SwNumRule& SwNumRule::operator=( const SwNumRule& rNumRule ) +{ + if( this != &rNumRule ) + { + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + Set( n, rNumRule.aFmts[ n ] ); + + eRuleType = rNumRule.eRuleType; + sName = rNumRule.sName; + bAutoRuleFlag = rNumRule.bAutoRuleFlag; + bInvalidRuleFlag = sal_True; + bContinusNum = rNumRule.bContinusNum; + bAbsSpaces = rNumRule.bAbsSpaces; + nPoolFmtId = rNumRule.GetPoolFmtId(); + nPoolHelpId = rNumRule.GetPoolHelpId(); + nPoolHlpFileId = rNumRule.GetPoolHlpFileId(); + } + return *this; +} + + +sal_Bool SwNumRule::operator==( const SwNumRule& rRule ) const +{ + sal_Bool bRet = eRuleType == rRule.eRuleType && + sName == rRule.sName && + bAutoRuleFlag == rRule.bAutoRuleFlag && + bContinusNum == rRule.bContinusNum && + bAbsSpaces == rRule.bAbsSpaces && + nPoolFmtId == rRule.GetPoolFmtId() && + nPoolHelpId == rRule.GetPoolHelpId() && + nPoolHlpFileId == rRule.GetPoolHlpFileId(); + if( bRet ) + { + for( sal_uInt8 n = 0; n < MAXLEVEL; ++n ) + if( !( rRule.Get( n ) == Get( n ) )) + { + bRet = sal_False; + break; + } + } + return bRet; +} + + +void SwNumRule::Set( sal_uInt16 i, const SwNumFmt& rNumFmt ) +{ + ASSERT( i < MAXLEVEL, "Serious defect, please inform OD" ) + if( i < MAXLEVEL ) + { + if( !aFmts[ i ] || !(rNumFmt == Get( i )) ) + { + delete aFmts[ i ]; + aFmts[ i ] = new SwNumFmt( rNumFmt ); + bInvalidRuleFlag = sal_True; + } + } +} + +void SwNumRule::Set( sal_uInt16 i, const SwNumFmt* pNumFmt ) +{ + ASSERT( i < MAXLEVEL, "Serious defect, please inform OD" ) + if( i >= MAXLEVEL ) + return; + SwNumFmt* pOld = aFmts[ i ]; + if( !pOld ) + { + if( pNumFmt ) + { + aFmts[ i ] = new SwNumFmt( *pNumFmt ); + bInvalidRuleFlag = sal_True; + } + } + else if( !pNumFmt ) + delete pOld, aFmts[ i ] = 0, bInvalidRuleFlag = sal_True; + else if( *pOld != *pNumFmt ) + *pOld = *pNumFmt, bInvalidRuleFlag = sal_True; +} + + +String SwNumRule::MakeNumString( const SwNodeNum& rNum, sal_Bool bInclStrings, + sal_Bool bOnlyArabic ) const +{ + String aStr; + + if (rNum.IsCounted()) + aStr = MakeNumString(rNum.GetNumberVector(), + bInclStrings, bOnlyArabic, MAXLEVEL); + + return aStr; +} + +String SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVector, + const sal_Bool bInclStrings, + const sal_Bool bOnlyArabic, + const unsigned int _nRestrictToThisLevel ) const +{ + String aStr; + + unsigned int nLevel = rNumVector.size() - 1; + // --> OD 2005-10-17 #126238# + if ( nLevel > _nRestrictToThisLevel ) + { + nLevel = _nRestrictToThisLevel; + } + // <-- + + if (nLevel < MAXLEVEL) + { + const SwNumFmt& rMyNFmt = Get( static_cast<sal_uInt16>(nLevel) ); + // --> OD 2006-06-02 #b6432095# + // - levels with numbering none has to provide prefix and suffix string +// if( SVX_NUM_NUMBER_NONE != rMyNFmt.GetNumberingType() ) + // <-- + { + sal_uInt8 i = static_cast<sal_uInt8>(nLevel); + + if( !IsContinusNum() && + // --> OD 2006-09-19 #i69672# + // - do not include upper levels, if level isn't numbered. + rMyNFmt.GetNumberingType() != SVX_NUM_NUMBER_NONE && + // <-- + rMyNFmt.GetIncludeUpperLevels() ) // nur der eigene Level ? + { + sal_uInt8 n = rMyNFmt.GetIncludeUpperLevels(); + if( 1 < n ) + { + if( i+1 >= n ) + i -= n - 1; + else + i = 0; + } + } + + for( ; i <= nLevel; ++i ) + { + const SwNumFmt& rNFmt = Get( i ); + if( SVX_NUM_NUMBER_NONE == rNFmt.GetNumberingType() ) + { + // Soll aus 1.1.1 --> 2. NoNum --> 1..1 oder 1.1 ?? + // if( i != rNum.nMyLevel ) + // aStr += aDotStr; + continue; + } + + if( rNumVector[ i ] ) + { + if( bOnlyArabic ) + aStr += String::CreateFromInt32( rNumVector[ i ] ); + else + aStr += rNFmt.GetNumStr( rNumVector[ i ] ); + } + else + aStr += '0'; // alle 0-Level sind eine 0 + if( i != nLevel && aStr.Len() ) + aStr += aDotStr; + } + + //JP 14.12.99: the type dont have any number, so dont append + // the Post-/Prefix String + if( bInclStrings && !bOnlyArabic && + SVX_NUM_CHAR_SPECIAL != rMyNFmt.GetNumberingType() && + SVX_NUM_BITMAP != rMyNFmt.GetNumberingType() ) + { + aStr.Insert( rMyNFmt.GetPrefix(), 0 ); + aStr += rMyNFmt.GetSuffix(); + } + } + } + + return aStr; +} + +// --> OD 2007-09-07 #i81002# +String SwNumRule::MakeRefNumString( const SwNodeNum& rNodeNum, + const bool bInclSuperiorNumLabels, + const sal_uInt8 nRestrictInclToThisLevel ) const +{ + String aRefNumStr; + + if ( rNodeNum.GetLevelInListTree() >= 0 ) + { + const SwNodeNum* pWorkingNodeNum( &rNodeNum ); + do + { + bool bMakeNumStringForPhantom( false ); + if ( pWorkingNodeNum->IsPhantom() ) + { + SwNumFmt aFmt( Get( static_cast<sal_uInt16>(pWorkingNodeNum->GetLevelInListTree()) ) ); + bMakeNumStringForPhantom = aFmt.IsEnumeration() && + SVX_NUM_NUMBER_NONE != aFmt.GetNumberingType(); + + } + if ( bMakeNumStringForPhantom || + ( !pWorkingNodeNum->IsPhantom() && + pWorkingNodeNum->GetTxtNode() && + pWorkingNodeNum->GetTxtNode()->HasNumber() ) ) + { + aRefNumStr.Insert( MakeNumString( pWorkingNodeNum->GetNumberVector() ), 0 ); + } + else if ( aRefNumStr.Len() > 0 ) + { + aRefNumStr.Insert( String::CreateFromAscii(" "), 0 ); + } + + if ( bInclSuperiorNumLabels && pWorkingNodeNum->GetLevelInListTree() > 0 ) + { + sal_uInt8 n = Get( static_cast<sal_uInt16>(pWorkingNodeNum->GetLevelInListTree()) ).GetIncludeUpperLevels(); + pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent()); + // skip parents, whose list label is already contained in the actual list label. + while ( pWorkingNodeNum && n > 1 ) + { + pWorkingNodeNum = dynamic_cast<SwNodeNum*>(pWorkingNodeNum->GetParent()); + --n; + } + } + else + { + break; + } + } while ( pWorkingNodeNum && + pWorkingNodeNum->GetLevelInListTree() >= 0 && + static_cast<sal_uInt8>(pWorkingNodeNum->GetLevelInListTree()) >= nRestrictInclToThisLevel ); + } + + return aRefNumStr; +} + +// ----- Copy-Methode vom SwNumRule ------ + + // eine Art Copy-Constructor, damit die Num-Formate auch an den + // richtigen CharFormaten eines Dokumentes haengen !! + // (Kopiert die NumFormate und returnt sich selbst) + +SwNumRule& SwNumRule::CopyNumRule( SwDoc* pDoc, const SwNumRule& rNumRule ) +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + Set( n, rNumRule.aFmts[ n ] ); + if( aFmts[ n ] && aFmts[ n ]->GetCharFmt() && + USHRT_MAX == pDoc->GetCharFmts()->GetPos( aFmts[n]->GetCharFmt() )) + // ueber unterschiedliche Dokumente kopieren, dann + // kopiere das entsprechende Char-Format ins neue + // Dokument. + aFmts[n]->SetCharFmt( pDoc->CopyCharFmt( *aFmts[n]-> + GetCharFmt() ) ); + } + eRuleType = rNumRule.eRuleType; + sName = rNumRule.sName; + bAutoRuleFlag = rNumRule.bAutoRuleFlag; + nPoolFmtId = rNumRule.GetPoolFmtId(); + nPoolHelpId = rNumRule.GetPoolHelpId(); + nPoolHlpFileId = rNumRule.GetPoolHlpFileId(); + bInvalidRuleFlag = sal_True; + return *this; +} +/* -----------------30.10.98 08:33------------------- + * + * --------------------------------------------------*/ +void SwNumRule::SetSvxRule(const SvxNumRule& rNumRule, SwDoc* pDoc) +{ + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + const SvxNumberFormat* pSvxFmt = rNumRule.Get(n); + delete aFmts[n]; + aFmts[n] = pSvxFmt ? new SwNumFmt(*pSvxFmt, pDoc) : 0; + } + + bInvalidRuleFlag = sal_True; + bContinusNum = rNumRule.IsContinuousNumbering(); +} +/* -----------------30.10.98 08:33------------------- + * + * --------------------------------------------------*/ +SvxNumRule SwNumRule::MakeSvxNumRule() const +{ + SvxNumRule aRule(NUM_CONTINUOUS|NUM_CHAR_TEXT_DISTANCE|NUM_CHAR_STYLE| + NUM_ENABLE_LINKED_BMP|NUM_ENABLE_EMBEDDED_BMP, + MAXLEVEL, bContinusNum, + eRuleType == + NUM_RULE ? + SVX_RULETYPE_NUMBERING : + SVX_RULETYPE_OUTLINE_NUMBERING ); + for( sal_uInt16 n = 0; n < MAXLEVEL; ++n ) + { + SwNumFmt aNumFmt = Get(n); + if(aNumFmt.GetCharFmt()) + aNumFmt.SetCharFmtName(aNumFmt.GetCharFmt()->GetName()); + aRule.SetLevel(n, aNumFmt, aFmts[n] != 0); + } + return aRule; +} + +void SwNumRule::SetInvalidRule(sal_Bool bFlag) +{ + if (bFlag) + { + // --> OD 2008-03-13 #refactorlists# +// tPamAndNums::iterator aIt; +// for (aIt = aNumberRanges.begin(); aIt != aNumberRanges.end(); aIt++) +// (*aIt).second->InvalidateTree(); + std::set< SwList* > aLists; + tTxtNodeList::iterator aIter; + for ( aIter = maTxtNodeList.begin(); aIter != maTxtNodeList.end(); ++aIter ) + { + const SwTxtNode* pTxtNode = *aIter; + // --> OD 2010-06-04 #i111681# - applying patch from cmc +// aLists.insert( pTxtNode->GetDoc()->getListByName( pTxtNode->GetListId() ) ); + SwList* pList = pTxtNode->GetDoc()->getListByName( pTxtNode->GetListId() ); + ASSERT( pList, "<SwNumRule::SetInvalidRule(..)> - list at which the text node is registered at does not exist. This is a serious issue --> please inform OD."); + if ( pList ) + { + aLists.insert( pList ); + } + // <-- + } + std::for_each( aLists.begin(), aLists.end(), + std::mem_fun( &SwList::InvalidateListTree ) ); + // <-- + } + + bInvalidRuleFlag = bFlag; +} + +// --> OD 2008-06-16 #i90078# +// #i23725#, #i23726# +//void SwNumRule::Indent(short nAmount, int nLevel, int nReferenceLevel, +// sal_Bool bRelative, sal_Bool bFirstLine, sal_Bool bCheckGtZero) +//{ +// int nStartLevel = 0; +// int nEndLevel = MAXLEVEL - 1; +// sal_Bool bGotInvalid = sal_False; + +// if (nLevel >= 0) +// nStartLevel = nEndLevel = nLevel; + +// int i; +// short nRealAmount = nAmount; + +// if (! bRelative) +// { +// if (bFirstLine) +// { +// if (nReferenceLevel >= 0) +// nAmount = nAmount - Get(static_cast<sal_uInt16>(nReferenceLevel)).GetFirstLineOffset(); +// else +// nAmount = nAmount - Get(static_cast<sal_uInt16>(nStartLevel)).GetFirstLineOffset(); +// } + +// sal_Bool bFirst = sal_True; + +// if (nReferenceLevel >= 0) +// nRealAmount = nAmount - Get(static_cast<sal_uInt16>(nReferenceLevel)).GetAbsLSpace(); +// else +// for (i = nStartLevel; i < nEndLevel + 1; i++) +// { +// short nTmp = nAmount - Get(static_cast<sal_uInt16>(i)).GetAbsLSpace(); + +// if (bFirst || nTmp > nRealAmount) +// { +// nRealAmount = nTmp; +// bFirst = sal_False; +// } +// } +// } + +// if (nRealAmount < 0) +// for (i = nStartLevel; i < nEndLevel + 1; i++) +// if (Get(static_cast<sal_uInt16>(i)).GetAbsLSpace() + nRealAmount < 0) +// nRealAmount = -Get(static_cast<sal_uInt16>(i)).GetAbsLSpace(); + +// for (i = nStartLevel; i < nEndLevel + 1; i++) +// { +// short nNew = Get(static_cast<sal_uInt16>(i)).GetAbsLSpace() + nRealAmount; + +// if (bCheckGtZero && nNew < 0) +// nNew = 0; + +// SwNumFmt aTmpNumFmt(Get(static_cast<sal_uInt16>(i))); +// aTmpNumFmt.SetAbsLSpace(nNew); + +// Set(static_cast<sal_uInt16>(i), aTmpNumFmt); + +// bGotInvalid = sal_True; +// } + +// if (bGotInvalid) +// SetInvalidRule(bGotInvalid); +//} + +// change indent of all list levels by given difference +void SwNumRule::ChangeIndent( const short nDiff ) +{ + for ( sal_uInt16 i = 0; i < MAXLEVEL; ++i ) + { + SwNumFmt aTmpNumFmt( Get(i) ); + + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFmt.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + short nNewIndent = nDiff + + aTmpNumFmt.GetAbsLSpace(); + if ( nNewIndent < 0 ) + { + nNewIndent = 0; + } + aTmpNumFmt.SetAbsLSpace( nNewIndent ); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + // --> OD 2009-01-20 #i93399# + // adjust also the list tab position, if a list tab stop is applied + if ( aTmpNumFmt.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB ) + { + const long nNewListTab = aTmpNumFmt.GetListtabPos() + nDiff; + aTmpNumFmt.SetListtabPos( nNewListTab ); + } + // <-- + const long nNewIndent = nDiff + + aTmpNumFmt.GetIndentAt(); + aTmpNumFmt.SetIndentAt( nNewIndent ); + } + + Set( i, aTmpNumFmt ); + } + + SetInvalidRule( sal_True ); +} + +// set indent of certain list level to given value +void SwNumRule::SetIndent( const short nNewIndent, + const sal_uInt16 nListLevel ) +{ + SwNumFmt aTmpNumFmt( Get(nListLevel) ); + + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFmt.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aTmpNumFmt.SetAbsLSpace( nNewIndent ); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + // --> OD 2009-01-20 #i93399# + // adjust also the list tab position, if a list tab stop is applied + if ( aTmpNumFmt.GetLabelFollowedBy() == SvxNumberFormat::LISTTAB ) + { + const long nNewListTab = aTmpNumFmt.GetListtabPos() + + ( nNewIndent - aTmpNumFmt.GetIndentAt() ); + aTmpNumFmt.SetListtabPos( nNewListTab ); + } + // <-- + aTmpNumFmt.SetIndentAt( nNewIndent ); + } + + SetInvalidRule( sal_True ); +} + +// set indent of first list level to given value and change other list level's +// indents accordingly +void SwNumRule::SetIndentOfFirstListLevelAndChangeOthers( const short nNewIndent ) +{ + SwNumFmt aTmpNumFmt( Get(0) ); + + short nDiff( 0 ); + const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode( + aTmpNumFmt.GetPositionAndSpaceMode() ); + if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + nDiff = nNewIndent + - aTmpNumFmt.GetFirstLineOffset() + - aTmpNumFmt.GetAbsLSpace(); + } + else if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + nDiff = static_cast<short>(nNewIndent + - aTmpNumFmt.GetIndentAt()); + } + if ( nDiff != 0 ) + { + ChangeIndent( nDiff ); + } +} +// <-- + +void SwNumRule::Validate() +{ + // --> OD 2008-03-13 #refactorlists# +// tPamAndNums::iterator aIt; +// for (aIt = aNumberRanges.begin(); aIt != aNumberRanges.end(); aIt++) +// (*aIt).second->NotifyInvalidChildren(); + std::set< SwList* > aLists; + tTxtNodeList::iterator aIter; + for ( aIter = maTxtNodeList.begin(); aIter != maTxtNodeList.end(); ++aIter ) + { + const SwTxtNode* pTxtNode = *aIter; + aLists.insert( pTxtNode->GetDoc()->getListByName( pTxtNode->GetListId() ) ); + } + std::for_each( aLists.begin(), aLists.end(), + std::mem_fun( &SwList::ValidateListTree ) ); + // <-- + + SetInvalidRule(sal_False); +} + +bool SwNumRule::IsCountPhantoms() const +{ + return mbCountPhantoms; +} + +void SwNumRule::SetCountPhantoms(bool bCountPhantoms) +{ + mbCountPhantoms = bCountPhantoms; +} + +// --> OD 2008-03-03 #refactorlists# +SwNumRule::tParagraphStyleList::size_type SwNumRule::GetParagraphStyleListSize() const +{ + return maParagraphStyleList.size(); +} + +void SwNumRule::AddParagraphStyle( SwTxtFmtColl& rTxtFmtColl ) +{ + tParagraphStyleList::iterator aIter = + std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTxtFmtColl ); + + if ( aIter == maParagraphStyleList.end() ) + { + maParagraphStyleList.push_back( &rTxtFmtColl ); + } +} + +void SwNumRule::RemoveParagraphStyle( SwTxtFmtColl& rTxtFmtColl ) +{ + tParagraphStyleList::iterator aIter = + std::find( maParagraphStyleList.begin(), maParagraphStyleList.end(), &rTxtFmtColl ); + + if ( aIter != maParagraphStyleList.end() ) + { + maParagraphStyleList.erase( aIter ); + } +} +// <-- + +// --> OD 2006-06-27 #b6440955# +namespace numfunc +{ + /** class containing default bullet list configuration data + + @author OD + */ + class SwDefBulletConfig : private utl::ConfigItem + { + public: + static SwDefBulletConfig* getInstance() + { + if ( mpInstance == 0 ) + { + mpInstance = new SwDefBulletConfig; + } + + return mpInstance; + } + + inline const String& GetFontname() const + { + return msFontname; + } + // --> OD 2008-06-02 #i63395# + inline bool IsFontnameUserDefined() const + { + return mbUserDefinedFontname; + } + // <-- + inline const Font& GetFont() const + { + return *mpFont; + } + inline short GetFontWeight() const + { + return static_cast<short>(meFontWeight); + } + inline short GetFontItalic() const + { + return static_cast<short>(meFontItalic); + } + inline sal_Unicode GetChar( sal_uInt8 p_nListLevel ) const + { + if ( p_nListLevel > MAXLEVEL ) + { + p_nListLevel = MAXLEVEL; + } + + return mnLevelChars[p_nListLevel]; + } + + private: + SwDefBulletConfig(); + + /** sets internal default bullet configuration data to default values + + @author OD + */ + void SetToDefault(); + + /** returns sequence of default bullet configuration property names + + @author OD + */ + uno::Sequence<rtl::OUString> GetPropNames() const; + + /** loads default bullet configuration properties and applies + values to internal data + + @author OD + */ + void LoadConfig(); + + /** initialize font instance for default bullet list + + @author OD + */ + void InitFont(); + + /** catches notification about changed default bullet configuration data + + @author OD + */ + virtual void Notify( const uno::Sequence<rtl::OUString>& aPropertyNames ); + virtual void Commit(); + + static SwDefBulletConfig* mpInstance; + + // default bullet list configuration data + String msFontname; + // --> OD 2008-06-02 #i63395# + bool mbUserDefinedFontname; + // <-- + FontWeight meFontWeight; + FontItalic meFontItalic; + sal_Unicode mnLevelChars[MAXLEVEL]; + + // default bullet list font instance + Font* mpFont; + }; + + SwDefBulletConfig* SwDefBulletConfig::mpInstance = 0; + + SwDefBulletConfig::SwDefBulletConfig() + : ConfigItem( rtl::OUString::createFromAscii("Office.Writer/Numbering/DefaultBulletList") ), + // --> OD 2008-06-02 #i63395# + // default bullet font is now OpenSymbol + msFontname( String::CreateFromAscii("OpenSymbol") ), + mbUserDefinedFontname( false ), + // <-- + meFontWeight( WEIGHT_DONTKNOW ), + meFontItalic( ITALIC_NONE ), + mpFont( 0 ) + { + SetToDefault(); + LoadConfig(); + InitFont(); + + // enable notification for changes on default bullet configuration change + EnableNotification( GetPropNames() ); + } + + void SwDefBulletConfig::SetToDefault() + { + // --> OD 2008-06-02 #i63395# + // default bullet font name is now OpenSymbol +// msFontname = String::CreateFromAscii("StarSymbol"); + msFontname = String::CreateFromAscii("OpenSymbol"); + mbUserDefinedFontname = false; + // <-- + meFontWeight = WEIGHT_DONTKNOW; + meFontItalic = ITALIC_NONE; + + // --> OD 2008-06-03 #i63395# + // new bullet characters +// mnLevelChars[0] = 0x25cf; +// mnLevelChars[1] = 0x25cb; +// mnLevelChars[2] = 0x25a0; +// mnLevelChars[3] = 0x25cf; +// mnLevelChars[4] = 0x25cb; +// mnLevelChars[5] = 0x25a0; +// mnLevelChars[6] = 0x25cf; +// mnLevelChars[7] = 0x25cb; +// mnLevelChars[8] = 0x25a0; +// mnLevelChars[9] = 0x25cf; + mnLevelChars[0] = 0x2022; + mnLevelChars[1] = 0x25e6; + mnLevelChars[2] = 0x25aa; + mnLevelChars[3] = 0x2022; + mnLevelChars[4] = 0x25e6; + mnLevelChars[5] = 0x25aa; + mnLevelChars[6] = 0x2022; + mnLevelChars[7] = 0x25e6; + mnLevelChars[8] = 0x25aa; + mnLevelChars[9] = 0x2022; + // <-- + } + + uno::Sequence<rtl::OUString> SwDefBulletConfig::GetPropNames() const + { + uno::Sequence<rtl::OUString> aPropNames(13); + rtl::OUString* pNames = aPropNames.getArray(); + pNames[0] = rtl::OUString::createFromAscii("BulletFont/FontFamilyname"); + pNames[1] = rtl::OUString::createFromAscii("BulletFont/FontWeight"); + pNames[2] = rtl::OUString::createFromAscii("BulletFont/FontItalic"); + pNames[3] = rtl::OUString::createFromAscii("BulletCharLvl1"); + pNames[4] = rtl::OUString::createFromAscii("BulletCharLvl2"); + pNames[5] = rtl::OUString::createFromAscii("BulletCharLvl3"); + pNames[6] = rtl::OUString::createFromAscii("BulletCharLvl4"); + pNames[7] = rtl::OUString::createFromAscii("BulletCharLvl5"); + pNames[8] = rtl::OUString::createFromAscii("BulletCharLvl6"); + pNames[9] = rtl::OUString::createFromAscii("BulletCharLvl7"); + pNames[10] = rtl::OUString::createFromAscii("BulletCharLvl8"); + pNames[11] = rtl::OUString::createFromAscii("BulletCharLvl9"); + pNames[12] = rtl::OUString::createFromAscii("BulletCharLvl10"); + + return aPropNames; + } + + void SwDefBulletConfig::LoadConfig() + { + uno::Sequence<rtl::OUString> aPropNames = GetPropNames(); + uno::Sequence<uno::Any> aValues = + GetProperties( aPropNames ); + const uno::Any* pValues = aValues.getConstArray(); + ASSERT( aValues.getLength() == aPropNames.getLength(), + "<SwDefBulletConfig::SwDefBulletConfig()> - GetProperties failed") + if ( aValues.getLength() == aPropNames.getLength() ) + { + for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( nProp ) + { + case 0: + { + rtl::OUString aStr; + pValues[nProp] >>= aStr; + msFontname = aStr; + // --> OD 2008-06-02 #i63395# + mbUserDefinedFontname = true; + // <-- + } + break; + case 1: + case 2: + { + sal_uInt8 nTmp = 0; + pValues[nProp] >>= nTmp; + if ( nProp == 1 ) + meFontWeight = static_cast<FontWeight>(nTmp); + else if ( nProp == 2 ) + meFontItalic = static_cast<FontItalic>(nTmp); + } + break; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + { + sal_Unicode cChar = sal_Unicode(); + pValues[nProp] >>= cChar; + mnLevelChars[nProp-3] = cChar; + } + break; + } + } + } + } + + } + + void SwDefBulletConfig::InitFont() + { + delete mpFont; + + mpFont = new Font( msFontname, aEmptyStr, Size( 0, 14 ) ); + mpFont->SetWeight( meFontWeight ); + mpFont->SetItalic( meFontItalic ); + } + + void SwDefBulletConfig::Notify( const uno::Sequence<rtl::OUString>& ) + { + SetToDefault(); + LoadConfig(); + InitFont(); + } + + void SwDefBulletConfig::Commit() + { + } + + const String& GetDefBulletFontname() + { + return SwDefBulletConfig::getInstance()->GetFontname(); + } + + // --> OD 2008-06-02 #i63395# + bool IsDefBulletFontUserDefined() + { + return SwDefBulletConfig::getInstance()->IsFontnameUserDefined(); + } + // <-- + + const Font& GetDefBulletFont() + { + return SwDefBulletConfig::getInstance()->GetFont(); + } + + sal_Unicode GetBulletChar( sal_uInt8 nLevel ) + { + return SwDefBulletConfig::getInstance()->GetChar( nLevel ); + } + + /** class containing configuration data about user interface behavior + regarding lists and list items. + + OD 2007-10-01 #b660435# + configuration item about behavior of <TAB>/<SHIFT-TAB>-key at first + position of first list item + + @author OD + */ + class SwNumberingUIBehaviorConfig : private utl::ConfigItem + { + public: + static SwNumberingUIBehaviorConfig* getInstance() + { + if ( mpInstance == 0 ) + { + mpInstance = new SwNumberingUIBehaviorConfig(); + } + + return mpInstance; + } + + inline sal_Bool ChangeIndentOnTabAtFirstPosOfFirstListItem() const + { + return mbChangeIndentOnTabAtFirstPosOfFirstListItem; + } + + private: + SwNumberingUIBehaviorConfig(); + + /** sets internal configuration data to default values + + @author OD + */ + void SetToDefault(); + + /** returns sequence of configuration property names + + @author OD + */ + com::sun::star::uno::Sequence<rtl::OUString> GetPropNames() const; + + /** loads configuration properties and applies values to internal data + + @author OD + */ + void LoadConfig(); + + /** catches notification about changed configuration data + + @author OD + */ + virtual void Notify( const com::sun::star::uno::Sequence<rtl::OUString>& aPropertyNames ); + virtual void Commit(); + + static SwNumberingUIBehaviorConfig* mpInstance; + + // configuration data + sal_Bool mbChangeIndentOnTabAtFirstPosOfFirstListItem; + }; + + SwNumberingUIBehaviorConfig* SwNumberingUIBehaviorConfig::mpInstance = 0; + + SwNumberingUIBehaviorConfig::SwNumberingUIBehaviorConfig() + : ConfigItem( rtl::OUString::createFromAscii("Office.Writer/Numbering/UserInterfaceBehavior") ), + mbChangeIndentOnTabAtFirstPosOfFirstListItem( sal_True ) + { + SetToDefault(); + LoadConfig(); + + // enable notification for changes on configuration change + EnableNotification( GetPropNames() ); + } + + void SwNumberingUIBehaviorConfig::SetToDefault() + { + mbChangeIndentOnTabAtFirstPosOfFirstListItem = sal_True; + } + + com::sun::star::uno::Sequence<rtl::OUString> SwNumberingUIBehaviorConfig::GetPropNames() const + { + com::sun::star::uno::Sequence<rtl::OUString> aPropNames(1); + rtl::OUString* pNames = aPropNames.getArray(); + pNames[0] = rtl::OUString::createFromAscii("ChangeIndentOnTabAtFirstPosOfFirstListItem"); + + return aPropNames; + } + + void SwNumberingUIBehaviorConfig::Commit() {} + + void SwNumberingUIBehaviorConfig::LoadConfig() + { + com::sun::star::uno::Sequence<rtl::OUString> aPropNames = GetPropNames(); + com::sun::star::uno::Sequence<com::sun::star::uno::Any> aValues = + GetProperties( aPropNames ); + const com::sun::star::uno::Any* pValues = aValues.getConstArray(); + ASSERT( aValues.getLength() == aPropNames.getLength(), + "<SwNumberingUIBehaviorConfig::LoadConfig()> - GetProperties failed") + if ( aValues.getLength() == aPropNames.getLength() ) + { + for ( int nProp = 0; nProp < aPropNames.getLength(); ++nProp ) + { + if ( pValues[nProp].hasValue() ) + { + switch ( nProp ) + { + case 0: + { + pValues[nProp] >>= mbChangeIndentOnTabAtFirstPosOfFirstListItem; + } + break; + default: + { + ASSERT( false, + "<SwNumberingUIBehaviorConfig::LoadConfig()> - unknown configuration property") + } + } + } + } + } + } + + void SwNumberingUIBehaviorConfig::Notify( const com::sun::star::uno::Sequence<rtl::OUString>& aPropertyNames ) + { + (void) aPropertyNames; + SetToDefault(); + LoadConfig(); + } + + sal_Bool ChangeIndentOnTabAtFirstPosOfFirstListItem() + { + return SwNumberingUIBehaviorConfig::getInstance()->ChangeIndentOnTabAtFirstPosOfFirstListItem(); + } + + // --> OD 2008-06-06 #i89178# + SvxNumberFormat::SvxNumPositionAndSpaceMode GetDefaultPositionAndSpaceMode() + { + SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode; + SvtSaveOptions aSaveOptions; + switch ( aSaveOptions.GetODFDefaultVersion() ) + { + case SvtSaveOptions::ODFVER_010: + case SvtSaveOptions::ODFVER_011: + { + ePosAndSpaceMode = SvxNumberFormat::LABEL_WIDTH_AND_POSITION; + } + break; + default: // ODFVER_UNKNOWN or ODFVER_012 + { + ePosAndSpaceMode = SvxNumberFormat::LABEL_ALIGNMENT; + } + } + + return ePosAndSpaceMode; + } + // <-- +} +// <-- diff --git a/sw/source/core/doc/poolfmt.cxx b/sw/source/core/doc/poolfmt.cxx new file mode 100644 index 000000000000..5c3bb6659b4a --- /dev/null +++ b/sw/source/core/doc/poolfmt.cxx @@ -0,0 +1,2591 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <hintids.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/localedatawrapper.hxx> +#include <editeng/paperinf.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <viewopt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtsrnd.hxx> +#include <fmtfsize.hxx> +#include <poolfmt.hxx> +#include <paratr.hxx> +#include <pagedesc.hxx> +#include <frmtool.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <fmtcol.hxx> +#include <ndtxt.hxx> +#include <fmtline.hxx> +#include <poolfmt.hrc> +#include <GetMetricVal.hxx> +#include <numrule.hxx> + + +using namespace ::com::sun::star; + +const sal_uInt16 PT_3 = 3 * 20; // 3 pt +const sal_uInt16 PT_6 = 6 * 20; // 6 pt +const sal_uInt16 PT_7 = 7 * 20; // 6 pt +const sal_uInt16 PT_8 = 8 * 20; // 8 pt +const sal_uInt16 PT_9 = 9 * 20; // 9 pt +const sal_uInt16 PT_10 = 10 * 20; // 10 pt +const sal_uInt16 PT_11 = 11 * 20; // 11 pt +const sal_uInt16 PT_12 = 12 * 20; // 12 pt +const sal_uInt16 PT_14 = 14 * 20; // 14 pt +const sal_uInt16 PT_16 = 16 * 20; // 16 pt +const sal_uInt16 PT_18 = 18 * 20; // 18 pt +const sal_uInt16 PT_22 = 22 * 20; // 22 pt +const sal_uInt16 PT_24 = 24 * 20; // 22 pt + + +//const sal_uInt16 HTML_PARSPACE = ((CM_05 * 7) / 10); +#define HTML_PARSPACE GetMetricVal( CM_05 ) + +static const sal_Char __FAR_DATA sKomma[] = ", "; + +static const sal_uInt16 aHeadlineSizes[ 2 * MAXLEVEL ] = { +// PT_16, PT_14, PT_14, PT_12, PT_12, // normal +//JP 10.12.96: jetzt soll alles prozentual sein: + 115, 100, 100, 85, 85, + 75, 75, 75, 75, 75, // normal +// PT_22, PT_16, PT_12, PT_11, PT_9 // HTML-Mode + PT_24, PT_18, PT_14, PT_12, PT_10, + PT_7, PT_7, PT_7, PT_7, PT_7 // HTML-Mode +}; + +long lcl_GetRightMargin( SwDoc& rDoc ) +{ + // sorge dafuer, dass die Druckereinstellungen in die Standard- + // Seitenvorlage uebernommen wurden. + const SwFrmFmt& rPgDscFmt = + const_cast<const SwDoc *>(&rDoc)->GetPageDesc( 0 ).GetMaster(); + const SvxLRSpaceItem& rLR = rPgDscFmt.GetLRSpace(); + const long nLeft = rLR.GetLeft(); + const long nRight = rLR.GetRight(); + const long nWidth = rPgDscFmt.GetFrmSize().GetWidth(); + return nWidth - nLeft - nRight; +} + +void SetAllScriptItem( SfxItemSet& rSet, const SfxPoolItem& rItem ) +{ + rSet.Put( rItem ); + sal_uInt16 nWhCJK = 0, nWhCTL = 0; + switch( rItem.Which() ) + { + case RES_CHRATR_FONTSIZE: + nWhCJK = RES_CHRATR_CJK_FONTSIZE, nWhCTL = RES_CHRATR_CTL_FONTSIZE; + break; + case RES_CHRATR_FONT: + nWhCJK = RES_CHRATR_CJK_FONT, nWhCTL = RES_CHRATR_CTL_FONT; + break; + case RES_CHRATR_LANGUAGE: + nWhCJK = RES_CHRATR_CJK_LANGUAGE, nWhCTL = RES_CHRATR_CTL_LANGUAGE; + break; + case RES_CHRATR_POSTURE: + nWhCJK = RES_CHRATR_CJK_POSTURE, nWhCTL = RES_CHRATR_CTL_POSTURE; + break; + case RES_CHRATR_WEIGHT: + nWhCJK = RES_CHRATR_CJK_WEIGHT, nWhCTL = RES_CHRATR_CTL_WEIGHT; + break; + } + + if( nWhCJK ) + rSet.Put( rItem, nWhCJK ); + if( nWhCTL ) + rSet.Put( rItem, nWhCTL ); +} + +void lcl_SetDfltFont( sal_uInt16 nFntType, SfxItemSet& rSet ) +{ + static struct { + sal_uInt16 nResLngId; + sal_uInt16 nResFntId; + } aArr[ 3 ] = { + { RES_CHRATR_LANGUAGE, RES_CHRATR_FONT }, + { RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_FONT }, + { RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_FONT } + }; + for( sal_uInt16 n = 0; n < 3; ++n ) + { + sal_uInt16 nLng = ((SvxLanguageItem&)rSet.GetPool()->GetDefaultItem( + aArr[n].nResLngId )).GetLanguage(); + Font aFnt( OutputDevice::GetDefaultFont( nFntType, + nLng, DEFAULTFONT_FLAGS_ONLYONE ) ); + + rSet.Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), + aEmptyStr, aFnt.GetPitch(), + aFnt.GetCharSet(), aArr[n].nResFntId )); + } +} + +void lcl_SetDfltFont( sal_uInt16 nLatinFntType, sal_uInt16 nCJKFntType, + sal_uInt16 nCTLFntType, SfxItemSet& rSet ) +{ + static struct { + sal_uInt16 nResLngId; + sal_uInt16 nResFntId; + sal_uInt16 nFntType; + } aArr[ 3 ] = { + { RES_CHRATR_LANGUAGE, RES_CHRATR_FONT, 0 }, + { RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_FONT, 0 }, + { RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_FONT, 0 } + }; + aArr[0].nFntType = nLatinFntType; + aArr[1].nFntType = nCJKFntType; + aArr[2].nFntType = nCTLFntType; + + for( sal_uInt16 n = 0; n < 3; ++n ) + { + sal_uInt16 nLng = ((SvxLanguageItem&)rSet.GetPool()->GetDefaultItem( + aArr[n].nResLngId )).GetLanguage(); + Font aFnt( OutputDevice::GetDefaultFont( aArr[n].nFntType, + nLng, DEFAULTFONT_FLAGS_ONLYONE ) ); + + rSet.Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), + aEmptyStr, aFnt.GetPitch(), + aFnt.GetCharSet(), aArr[n].nResFntId )); + } +} + +void lcl_SetHeadline( SwDoc* pDoc, SwTxtFmtColl* pColl, + SfxItemSet& rSet, + sal_uInt16 nOutLvlBits, sal_uInt8 nLevel, sal_Bool bItalic ) +{ + SetAllScriptItem( rSet, SvxWeightItem( WEIGHT_BOLD, RES_CHRATR_WEIGHT ) ); + SvxFontHeightItem aHItem(240, 100, RES_CHRATR_FONTSIZE); + const bool bHTMLMode = pDoc->get(IDocumentSettingAccess::HTML_MODE); + if( bHTMLMode ) + aHItem.SetHeight( aHeadlineSizes[ MAXLEVEL + nLevel ] ); + else + aHItem.SetHeight( PT_14, aHeadlineSizes[ nLevel ] ); + SetAllScriptItem( rSet, aHItem ); + + if( bItalic && !bHTMLMode ) + SetAllScriptItem( rSet, SvxPostureItem( ITALIC_NORMAL, RES_CHRATR_POSTURE ) ); + + if( bHTMLMode ) + { + ::lcl_SetDfltFont( DEFAULTFONT_LATIN_TEXT, DEFAULTFONT_CJK_TEXT, + DEFAULTFONT_CTL_TEXT, rSet ); + } + + if( pColl ) + { + if( !( nOutLvlBits & ( 1 << nLevel )) ) + { + //pColl->SetOutlineLevel( nLevel ); //#outline level zhaojianwei + pColl->AssignToListLevelOfOutlineStyle(nLevel);//<-end,zhaojianwei + if( !bHTMLMode ) + { + SwNumRule * pOutlineRule = pDoc->GetOutlineNumRule(); + const SwNumFmt& rNFmt = pOutlineRule->Get( nLevel ); + // --> OD 2008-02-01 #newlistlevelattrs# + if ( rNFmt.GetPositionAndSpaceMode() == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION && + ( rNFmt.GetAbsLSpace() || rNFmt.GetFirstLineOffset() ) ) + // <-- + { + SvxLRSpaceItem aLR( (SvxLRSpaceItem&)pColl->GetFmtAttr( RES_LR_SPACE ) ); + aLR.SetTxtFirstLineOfstValue( rNFmt.GetFirstLineOffset() ); + aLR.SetTxtLeft( rNFmt.GetAbsLSpace() ); + pColl->SetFmtAttr( aLR ); + } + + // --> OD 2006-11-20 #i71764# + // Check on document setting OUTLINE_LEVEL_YIELDS_OUTLINE_RULE no longer needed. + // All paragraph styles, which are assigned to a level of the + // outline style has to have the outline style set as its list style. + { + SwNumRuleItem aItem(pOutlineRule->GetName()); + + pColl->SetFmtAttr(aItem); + } + // <-- + } + } + pColl->SetNextTxtFmtColl( *pDoc->GetTxtCollFromPool( + RES_POOLCOLL_TEXT )); + } +} + + + +void lcl_SetRegister( SwDoc* pDoc, SfxItemSet& rSet, sal_uInt16 nFact, + sal_Bool bHeader, sal_Bool bTab ) +{ + SvxLRSpaceItem aLR( RES_LR_SPACE ); + sal_uInt16 nLeft = nFact ? GetMetricVal( CM_05 ) * nFact : 0; + aLR.SetTxtLeft( nLeft ); + + rSet.Put( aLR ); + if( bHeader ) + { + SetAllScriptItem( rSet, SvxWeightItem( WEIGHT_BOLD, RES_CHRATR_WEIGHT ) ); + SetAllScriptItem( rSet, SvxFontHeightItem( PT_16, 100, RES_CHRATR_FONTSIZE ) ); + } + if( bTab ) + { + long nRightMargin = lcl_GetRightMargin( *pDoc ); + SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); + aTStops.Insert( SvxTabStop( nRightMargin - nLeft, + SVX_TAB_ADJUST_RIGHT, + cDfltDecimalChar, '.' )); + rSet.Put( aTStops ); + } +} + + + +void lcl_SetNumBul( SwDoc* pDoc, SwTxtFmtColl* pColl, + SfxItemSet& rSet, + sal_uInt16 nNxt, SwTwips nEZ, SwTwips nLeft, + SwTwips nUpper, SwTwips nLower ) +{ + + SvxLRSpaceItem aLR( RES_LR_SPACE ); SvxULSpaceItem aUL( RES_UL_SPACE ); + aLR.SetTxtFirstLineOfst( sal_uInt16(nEZ) ); aLR.SetTxtLeft( sal_uInt16(nLeft) ); + aUL.SetUpper( sal_uInt16(nUpper) ); aUL.SetLower( sal_uInt16(nLower) ); + rSet.Put( aLR ); + rSet.Put( aUL ); + + if( !pColl ) + pColl->SetNextTxtFmtColl( *pDoc->GetTxtCollFromPool( nNxt )); +} + + + +// Gebe die "Auto-Collection" mit der Id zurueck. Existiert +// sie noch nicht, dann erzeuge sie +// Ist der String-Pointer definiert, dann erfrage nur die +// Beschreibung der Attribute, !! es legt keine Vorlage an !! + +SvxFrameDirection GetDefaultFrameDirection(sal_uLong nLanguage) +{ + SvxFrameDirection eResult = (MsLangId::isRightToLeft( static_cast<LanguageType>(nLanguage)) ? + FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP); + return eResult; +} + +SwTxtFmtColl* SwDoc::GetTxtCollFromPool( sal_uInt16 nId, bool bRegardLanguage ) +{ + ASSERT( + (RES_POOLCOLL_TEXT_BEGIN <= nId && nId < RES_POOLCOLL_TEXT_END) || + (RES_POOLCOLL_LISTS_BEGIN <= nId && nId < RES_POOLCOLL_LISTS_END) || + (RES_POOLCOLL_EXTRA_BEGIN <= nId && nId < RES_POOLCOLL_EXTRA_END) || + (RES_POOLCOLL_REGISTER_BEGIN <= nId && nId < RES_POOLCOLL_REGISTER_END) || + (RES_POOLCOLL_DOC_BEGIN <= nId && nId < RES_POOLCOLL_DOC_END) || + (RES_POOLCOLL_HTML_BEGIN <= nId && nId < RES_POOLCOLL_HTML_END), + "Falsche AutoFormat-Id" ); + + SwTxtFmtColl* pNewColl; + sal_uInt16 nOutLvlBits = 0; + for( sal_uInt16 n = 0; n < pTxtFmtCollTbl->Count(); ++n ) + { + if( nId == ( pNewColl = (*pTxtFmtCollTbl)[ n ] )->GetPoolFmtId() ) + { + return pNewColl; + } + //if( pNewColl->GetOutlineLevel() < MAXLEVEL ) //#outline level,zhaojianwei + //nOutLvlBits |= ( 1 << pNewColl->GetOutlineLevel() ); + if( pNewColl->IsAssignedToListLevelOfOutlineStyle()) + nOutLvlBits |= ( 1 << pNewColl->GetAssignedOutlineStyleLevel() );//<-end,zhaojianwei + } + + // bis hierher nicht gefunden -> neu anlegen + sal_uInt16 nResId = 0; + if( RES_POOLCOLL_TEXT_BEGIN <= nId && nId < RES_POOLCOLL_TEXT_END ) + nResId = RC_POOLCOLL_TEXT_BEGIN - RES_POOLCOLL_TEXT_BEGIN; + else if (RES_POOLCOLL_LISTS_BEGIN <= nId && nId < RES_POOLCOLL_LISTS_END) + nResId = RC_POOLCOLL_LISTS_BEGIN - RES_POOLCOLL_LISTS_BEGIN; + else if (RES_POOLCOLL_EXTRA_BEGIN <= nId && nId < RES_POOLCOLL_EXTRA_END) + nResId = RC_POOLCOLL_EXTRA_BEGIN - RES_POOLCOLL_EXTRA_BEGIN; + else if (RES_POOLCOLL_REGISTER_BEGIN <= nId && nId < RES_POOLCOLL_REGISTER_END) + nResId = RC_POOLCOLL_REGISTER_BEGIN - RES_POOLCOLL_REGISTER_BEGIN; + else if (RES_POOLCOLL_DOC_BEGIN <= nId && nId < RES_POOLCOLL_DOC_END) + nResId = RC_POOLCOLL_DOC_BEGIN - RES_POOLCOLL_DOC_BEGIN; + else if (RES_POOLCOLL_HTML_BEGIN <= nId && nId < RES_POOLCOLL_HTML_END) + nResId = RC_POOLCOLL_HTML_BEGIN - RES_POOLCOLL_HTML_BEGIN; + + ASSERT( nResId, "Ungueltige Pool-ID" ); + if( !nResId ) + return GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + + ResId aResId( nResId + nId, *pSwResMgr ); + String aNm( aResId ); + + // ein Set fuer alle zusetzenden Attribute + SwAttrSet aSet( GetAttrPool(), aTxtFmtCollSetRange ); + sal_uInt16 nParent = GetPoolParent( nId ); + + { + +//FEATURE::CONDCOLL + if(::IsConditionalByPoolId( nId )) + pNewColl = new SwConditionTxtFmtColl( GetAttrPool(), aNm, !nParent + ? pDfltTxtFmtColl + : GetTxtCollFromPool( nParent )); + else +//FEATURE::CONDCOLL + pNewColl = new SwTxtFmtColl( GetAttrPool(), aNm, !nParent + ? pDfltTxtFmtColl + : GetTxtCollFromPool( nParent )); + pNewColl->SetPoolFmtId( nId ); + pTxtFmtCollTbl->Insert( pNewColl, pTxtFmtCollTbl->Count() ); + } + + switch( nId ) + { + // allgemeine Inhaltsformen + case RES_POOLCOLL_STANDARD: + /* #111214# koreans do not like SvxScriptItem(sal_True) */ + if (bRegardLanguage) + { + sal_uLong nAppLanguage = GetAppLanguage(); + if (GetDefaultFrameDirection(nAppLanguage) == + FRMDIR_HORI_RIGHT_TOP) + { + SvxAdjustItem aAdjust(SVX_ADJUST_RIGHT, RES_PARATR_ADJUST ); + aSet.Put(aAdjust); + } + if (nAppLanguage == LANGUAGE_KOREAN) + { + SvxScriptSpaceItem aScriptSpace(sal_False, RES_PARATR_SCRIPTSPACE); + aSet.Put(aScriptSpace); + } + } + break; + + case RES_POOLCOLL_TEXT: // Textkoerper + { + SvxULSpaceItem aUL( 0, PT_6, RES_UL_SPACE ); + if( get(IDocumentSettingAccess::HTML_MODE) ) aUL.SetLower( HTML_PARSPACE ); + aSet.Put( aUL ); + } + break; + case RES_POOLCOLL_TEXT_IDENT: // Textkoerper Einzug + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtFirstLineOfst( GetMetricVal( CM_05 )); + aSet.Put( aLR ); + } + break; + case RES_POOLCOLL_TEXT_NEGIDENT: // Textkoerper neg. Einzug + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtFirstLineOfst( -(short)GetMetricVal( CM_05 )); + aLR.SetTxtLeft( GetMetricVal( CM_1 )); + SvxTabStopItem aTStops(RES_PARATR_TABSTOP); aTStops.Insert( SvxTabStop( 0 )); + + aSet.Put( aLR ); + aSet.Put( aTStops ); + } + break; + case RES_POOLCOLL_TEXT_MOVE: // Textkoerper Einrueckung + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtLeft( GetMetricVal( CM_05 )); + aSet.Put( aLR ); + } + break; + + case RES_POOLCOLL_CONFRONTATION: // Textkoerper Gegenueberstellung + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtFirstLineOfst( - short( GetMetricVal( CM_1 ) * 4 + + GetMetricVal( CM_05)) ); + aLR.SetTxtLeft( GetMetricVal( CM_1 ) * 5 ); + SvxTabStopItem aTStops( RES_PARATR_TABSTOP ); aTStops.Insert( SvxTabStop( 0 )); + + aSet.Put( aLR ); + aSet.Put( aTStops ); + } + break; + case RES_POOLCOLL_MARGINAL: // Textkoerper maginalie + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtLeft( GetMetricVal( CM_1 ) * 4 ); + aSet.Put( aLR ); + } + break; + + case RES_POOLCOLL_HEADLINE_BASE: // Basis Ueberschrift + { + static const sal_uInt16 aFntInit[] = { + DEFAULTFONT_LATIN_HEADING, RES_CHRATR_FONT, + RES_CHRATR_LANGUAGE, LANGUAGE_ENGLISH_US, + DEFAULTFONT_CJK_HEADING, RES_CHRATR_CJK_FONT, + RES_CHRATR_CJK_LANGUAGE, LANGUAGE_ENGLISH_US, + DEFAULTFONT_CTL_HEADING, RES_CHRATR_CTL_FONT, + RES_CHRATR_CTL_LANGUAGE, LANGUAGE_ARABIC_SAUDI_ARABIA, + 0 + }; + + for( const sal_uInt16* pArr = aFntInit; *pArr; pArr += 4 ) + { + sal_uInt16 nLng = ((SvxLanguageItem&)GetDefault( *(pArr+2) )).GetLanguage(); + if( LANGUAGE_DONTKNOW == nLng ) + nLng = *(pArr+3); + + Font aFnt( OutputDevice::GetDefaultFont( *pArr, + nLng, DEFAULTFONT_FLAGS_ONLYONE ) ); + + aSet.Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), + aEmptyStr, aFnt.GetPitch(), + aFnt.GetCharSet(), *(pArr+1) )); + } + + SvxFontHeightItem aFntSize( PT_14, 100, RES_CHRATR_FONTSIZE ); + SvxULSpaceItem aUL( PT_12, PT_6, RES_UL_SPACE ); + if( get(IDocumentSettingAccess::HTML_MODE) ) + aUL.SetLower( HTML_PARSPACE ); + aSet.Put( SvxFmtKeepItem( sal_True, RES_KEEP )); + + pNewColl->SetNextTxtFmtColl( *GetTxtCollFromPool( RES_POOLCOLL_TEXT )); + + aSet.Put( aUL ); + SetAllScriptItem( aSet, aFntSize ); + } + break; + + case RES_POOLCOLL_NUMBUL_BASE: // Basis Numerierung/Aufzaehlung + break; + + case RES_POOLCOLL_GREETING: // Grussformel + case RES_POOLCOLL_REGISTER_BASE: // Basis Verzeichnisse + case RES_POOLCOLL_SIGNATURE: // Unterschrift + case RES_POOLCOLL_TABLE: // Tabelle-Inhalt + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_HEADLINE1: // Ueberschrift 1 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 0, sal_False ); + break; + case RES_POOLCOLL_HEADLINE2: // Ueberschrift 2 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 1, sal_True ); + break; + case RES_POOLCOLL_HEADLINE3: // Ueberschrift 3 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 2, sal_False ); + break; + case RES_POOLCOLL_HEADLINE4: // Ueberschrift 4 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 3, sal_True ); + break; + case RES_POOLCOLL_HEADLINE5: // Ueberschrift 5 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 4, sal_False ); + break; + case RES_POOLCOLL_HEADLINE6: // Ueberschrift 6 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 5, sal_False ); + break; + case RES_POOLCOLL_HEADLINE7: // Ueberschrift 7 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 6, sal_False ); + break; + case RES_POOLCOLL_HEADLINE8: // Ueberschrift 8 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 7, sal_False ); + break; + case RES_POOLCOLL_HEADLINE9: // Ueberschrift 9 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 8, sal_False ); + break; + case RES_POOLCOLL_HEADLINE10: // Ueberschrift 10 + lcl_SetHeadline( this, pNewColl, aSet, nOutLvlBits, 9, sal_False ); + break; + + + // Sonderbereiche: + // Kopfzeilen + case RES_POOLCOLL_HEADER: + case RES_POOLCOLL_HEADERL: + case RES_POOLCOLL_HEADERR: + // Fusszeilen + case RES_POOLCOLL_FOOTER: + case RES_POOLCOLL_FOOTERL: + case RES_POOLCOLL_FOOTERR: + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + + long nRightMargin = lcl_GetRightMargin( *this ); + + SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); + aTStops.Insert( SvxTabStop( nRightMargin / 2, SVX_TAB_ADJUST_CENTER ) ); + aTStops.Insert( SvxTabStop( nRightMargin, SVX_TAB_ADJUST_RIGHT ) ); + + aSet.Put( aTStops ); + } + break; + + case RES_POOLCOLL_TABLE_HDLN: + { + SetAllScriptItem( aSet, SvxWeightItem( WEIGHT_BOLD, RES_CHRATR_WEIGHT ) ); + aSet.Put( SvxAdjustItem( SVX_ADJUST_CENTER, RES_PARATR_ADJUST ) ); + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_FOOTNOTE: // Fussnote + case RES_POOLCOLL_ENDNOTE: + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetTxtFirstLineOfst( -(short)GetMetricVal( CM_05 )); + aLR.SetTxtLeft( GetMetricVal( CM_05 )); + SetAllScriptItem( aSet, SvxFontHeightItem( PT_10, 100, RES_CHRATR_FONTSIZE ) ); + aSet.Put( aLR ); + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_LABEL: // Beschriftung-Basis + { + SvxULSpaceItem aUL( RES_UL_SPACE ); aUL.SetUpper( PT_6 ); aUL.SetLower( PT_6 ); + aSet.Put( aUL ); + SetAllScriptItem( aSet, SvxPostureItem( ITALIC_NORMAL, RES_CHRATR_POSTURE ) ); + SetAllScriptItem( aSet, SvxFontHeightItem( PT_10, 100, RES_CHRATR_FONTSIZE ) ); + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_FRAME: // Rahmen Inhalt + case RES_POOLCOLL_LABEL_ABB: // Beschriftung-Abbildung + case RES_POOLCOLL_LABEL_TABLE: // Beschriftung-Tabelle + case RES_POOLCOLL_LABEL_FRAME: // Beschriftung-Rahmen + case RES_POOLCOLL_LABEL_DRAWING: // Beschriftung-Zeichnung + break; + + case RES_POOLCOLL_JAKETADRESS: // UmschlagAdresse + { + SvxULSpaceItem aUL( RES_UL_SPACE ); aUL.SetLower( PT_3 ); + aSet.Put( aUL ); + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_SENDADRESS: // AbsenderAdresse + { + if( get(IDocumentSettingAccess::HTML_MODE) ) + SetAllScriptItem( aSet, SvxPostureItem(ITALIC_NORMAL, RES_CHRATR_POSTURE) ); + else + { + SvxULSpaceItem aUL( RES_UL_SPACE ); aUL.SetLower( PT_3 ); + aSet.Put( aUL ); + } + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + // Benutzer-Verzeichnisse: + case RES_POOLCOLL_TOX_USERH: // Header + lcl_SetRegister( this, aSet, 0, sal_True, sal_False ); + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + case RES_POOLCOLL_TOX_USER1: // 1. Ebene + lcl_SetRegister( this, aSet, 0, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER2: // 2. Ebene + lcl_SetRegister( this, aSet, 1, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER3: // 3. Ebene + lcl_SetRegister( this, aSet, 2, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER4: // 4. Ebene + lcl_SetRegister( this, aSet, 3, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER5: // 5. Ebene + lcl_SetRegister( this, aSet, 4, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER6: // 6. Ebene + lcl_SetRegister( this, aSet, 5, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER7: // 7. Ebene + lcl_SetRegister( this, aSet, 6, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER8: // 8. Ebene + lcl_SetRegister( this, aSet, 7, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER9: // 9. Ebene + lcl_SetRegister( this, aSet, 8, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_USER10: // 10. Ebene + lcl_SetRegister( this, aSet, 9, sal_False, sal_True ); + break; + + // Index-Verzeichnisse + case RES_POOLCOLL_TOX_IDXH: // Header + lcl_SetRegister( this, aSet, 0, sal_True, sal_False ); + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + case RES_POOLCOLL_TOX_IDX1: // 1. Ebene + lcl_SetRegister( this, aSet, 0, sal_False, sal_False ); + break; + case RES_POOLCOLL_TOX_IDX2: // 2. Ebene + lcl_SetRegister( this, aSet, 1, sal_False, sal_False ); + break; + case RES_POOLCOLL_TOX_IDX3: // 3. Ebene + lcl_SetRegister( this, aSet, 2, sal_False, sal_False ); + break; + case RES_POOLCOLL_TOX_IDXBREAK: // Trenner + lcl_SetRegister( this, aSet, 0, sal_False, sal_False ); + break; + + // Inhalts-Verzeichnisse + case RES_POOLCOLL_TOX_CNTNTH: // Header + lcl_SetRegister( this, aSet, 0, sal_True, sal_False ); + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + case RES_POOLCOLL_TOX_CNTNT1: // 1. Ebene + lcl_SetRegister( this, aSet, 0, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT2: // 2. Ebene + lcl_SetRegister( this, aSet, 1, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT3: // 3. Ebene + lcl_SetRegister( this, aSet, 2, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT4: // 4. Ebene + lcl_SetRegister( this, aSet, 3, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT5: // 5. Ebene + lcl_SetRegister( this, aSet, 4, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT6: // 6. Ebene + lcl_SetRegister( this, aSet, 5, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT7: // 7. Ebene + lcl_SetRegister( this, aSet, 6, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT8: // 8. Ebene + lcl_SetRegister( this, aSet, 7, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT9: // 9. Ebene + lcl_SetRegister( this, aSet, 8, sal_False, sal_True ); + break; + case RES_POOLCOLL_TOX_CNTNT10: // 10. Ebene + lcl_SetRegister( this, aSet, 9, sal_False, sal_True ); + break; + + case RES_POOLCOLL_TOX_ILLUSH: + case RES_POOLCOLL_TOX_OBJECTH: + case RES_POOLCOLL_TOX_TABLESH: + case RES_POOLCOLL_TOX_AUTHORITIESH: + lcl_SetRegister( this, aSet, 0, sal_True, sal_False ); + { + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + case RES_POOLCOLL_TOX_ILLUS1: + case RES_POOLCOLL_TOX_OBJECT1: + case RES_POOLCOLL_TOX_TABLES1: + case RES_POOLCOLL_TOX_AUTHORITIES1: + lcl_SetRegister( this, aSet, 0, sal_False, sal_True ); + break; + + + + case RES_POOLCOLL_NUM_LEVEL1S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL1, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 0 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL1: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL1, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 0 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL1E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL1, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 0 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_NUM_NONUM1: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_NONUM1, + 0, SwNumRule::GetNumIndent( 0 ), 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL2S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL2, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 1 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL2: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL2, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 1 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL2E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL2, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 1 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_NUM_NONUM2: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_NONUM2, + 0, SwNumRule::GetNumIndent( 1 ), 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL3S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL3, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 2 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL3: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL3, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 2 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL3E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL3, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 2 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_NUM_NONUM3: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_NONUM3, + 0, SwNumRule::GetNumIndent( 2 ), 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL4S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL4, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 3 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL4: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL4, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 3 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL4E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL4, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 3 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_NUM_NONUM4: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_NONUM4, + 0, SwNumRule::GetNumIndent( 3 ), 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL5S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL5, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 4 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL5: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL5, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 4 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_NUM_LEVEL5E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_LEVEL5, + lNumFirstLineOffset, SwNumRule::GetNumIndent( 4 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_NUM_NONUM5: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_NUM_NONUM5, + 0, SwNumRule::GetNumIndent( 4 ), 0, PT_6 ); + break; + + case RES_POOLCOLL_BUL_LEVEL1S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL1, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 0 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL1: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL1, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 0 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL1E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL1, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 0 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_BUL_NONUM1: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_NONUM1, + 0, SwNumRule::GetBullIndent( 0 ), 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL2S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL2, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 1 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL2: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL2, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 1 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL2E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL2, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 1 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_BUL_NONUM2: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_NONUM2, + 0, SwNumRule::GetBullIndent( 1 ), 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL3S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL3, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 2 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL3: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL3, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 2 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL3E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL3, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 2 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_BUL_NONUM3: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_NONUM3, + 0, SwNumRule::GetBullIndent( 2 ), 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL4S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL4, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 3 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL4: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL4, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 3 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL4E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL4, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 3 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_BUL_NONUM4: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_NONUM4, + 0, SwNumRule::GetBullIndent( 3 ), 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL5S: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL5, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 4 ), + PT_12, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL5: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL5, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 4 ), + 0, PT_6 ); + break; + case RES_POOLCOLL_BUL_LEVEL5E: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_LEVEL5, + lBullFirstLineOffset, SwNumRule::GetBullIndent( 4 ), + 0, PT_12 ); + break; + case RES_POOLCOLL_BUL_NONUM5: + lcl_SetNumBul( this, pNewColl, aSet, RES_POOLCOLL_BUL_NONUM5, + 0, SwNumRule::GetBullIndent( 4 ), 0, PT_6 ); + break; + + case RES_POOLCOLL_DOC_TITEL: // Doc. Titel + { + SetAllScriptItem( aSet, SvxWeightItem( WEIGHT_BOLD, RES_CHRATR_WEIGHT ) ); + SetAllScriptItem( aSet, SvxFontHeightItem( PT_18, 100, RES_CHRATR_FONTSIZE ) ); + + aSet.Put( SvxAdjustItem( SVX_ADJUST_CENTER, RES_PARATR_ADJUST ) ); + + pNewColl->SetNextTxtFmtColl( *GetTxtCollFromPool( + RES_POOLCOLL_DOC_SUBTITEL )); + } + break; + + case RES_POOLCOLL_DOC_SUBTITEL: // Doc. UnterTitel + { + SetAllScriptItem( aSet, SvxPostureItem( ITALIC_NORMAL, RES_CHRATR_POSTURE )); + SetAllScriptItem( aSet, SvxFontHeightItem( PT_14, 100, RES_CHRATR_FONTSIZE )); + + aSet.Put( SvxAdjustItem( SVX_ADJUST_CENTER, RES_PARATR_ADJUST )); + + pNewColl->SetNextTxtFmtColl( *GetTxtCollFromPool( + RES_POOLCOLL_TEXT )); + } + break; + + case RES_POOLCOLL_HTML_BLOCKQUOTE: + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetLeft( GetMetricVal( CM_1 )); + aLR.SetRight( GetMetricVal( CM_1 )); + aSet.Put( aLR ); +// aSet.Put( SvxAdjustItem( SVX_ADJUST_BLOCK, RES_PARATR_ADJUST ) ); + SvxULSpaceItem aUL( RES_UL_SPACE ); + aUL = pNewColl->GetULSpace(); + aUL.SetLower( HTML_PARSPACE ); + aSet.Put( aUL); + } + break; + + case RES_POOLCOLL_HTML_PRE: + { + ::lcl_SetDfltFont( DEFAULTFONT_FIXED, aSet ); + +// WORKAROUND: PRE auf 10pt setzten + SetAllScriptItem( aSet, SvxFontHeightItem(PT_10, 100, RES_CHRATR_FONTSIZE) ); +// WORKAROUND: PRE auf 10pt setzten + + // der untere Absatz-Abstand wird explizit gesetzt (macht + // die harte Attributierung einfacher) + SvxULSpaceItem aULSpaceItem( RES_UL_SPACE ); + aULSpaceItem = pNewColl->GetULSpace(); + aULSpaceItem.SetLower( 0 ); + aSet.Put( aULSpaceItem ); + } + break; + + case RES_POOLCOLL_HTML_HR: + { + SvxBoxItem aBox( RES_BOX ); + Color aColor( COL_GRAY ); + SvxBorderLine aNew( &aColor, DEF_DOUBLE_LINE0_OUT, + DEF_DOUBLE_LINE0_IN, + DEF_DOUBLE_LINE0_DIST ); + aBox.SetLine( &aNew, BOX_LINE_BOTTOM ); + + aSet.Put( aBox ); + aSet.Put( SwParaConnectBorderItem( sal_False ) ); + SetAllScriptItem( aSet, SvxFontHeightItem(120, 100, RES_CHRATR_FONTSIZE) ); + + SvxULSpaceItem aUL( RES_UL_SPACE ); + { + pNewColl->SetNextTxtFmtColl( *GetTxtCollFromPool( + RES_POOLCOLL_TEXT )); + aUL = pNewColl->GetULSpace(); + } + aUL.SetLower( HTML_PARSPACE ); + aSet.Put( aUL); + SwFmtLineNumber aLN; aLN.SetCountLines( sal_False ); + aSet.Put( aLN ); + } + break; + + case RES_POOLCOLL_HTML_DD: + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR = pNewColl->GetLRSpace(); + // es wird um 1cm eingerueckt. Die IDs liegen immer 2 auseinander! + aLR.SetLeft( GetMetricVal( CM_1 )); + aSet.Put( aLR ); + } + break; + case RES_POOLCOLL_HTML_DT: + { + SvxLRSpaceItem aLR( RES_LR_SPACE ); + { + pNewColl->SetNextTxtFmtColl( *GetTxtCollFromPool( + RES_POOLCOLL_HTML_DD )); + aLR = pNewColl->GetLRSpace(); + } + // es wird um 0cm eingerueckt. Die IDs liegen immer 2 auseinander! + aLR.SetLeft( 0 ); + aSet.Put( aLR ); + } + break; + } + + if( aSet.Count() ) + { + { + pNewColl->SetFmtAttr( aSet ); + // JP 31.08.95: erzeugen einer PoolVorlage ist keine Modifikation + // (Bug: 18545) + // SetModified(); + } + } + return pNewColl; +} + + + + // pruefe, ob diese "Auto-Collection" in Dokument schon/noch + // benutzt wird +bool SwDoc::IsPoolTxtCollUsed( sal_uInt16 nId ) const +{ + ASSERT( + (RES_POOLCOLL_TEXT_BEGIN <= nId && nId < RES_POOLCOLL_TEXT_END) || + (RES_POOLCOLL_LISTS_BEGIN <= nId && nId < RES_POOLCOLL_LISTS_END) || + (RES_POOLCOLL_EXTRA_BEGIN <= nId && nId < RES_POOLCOLL_EXTRA_END) || + (RES_POOLCOLL_REGISTER_BEGIN <= nId && nId < RES_POOLCOLL_REGISTER_END) || + (RES_POOLCOLL_DOC_BEGIN <= nId && nId < RES_POOLCOLL_DOC_END) || + (RES_POOLCOLL_HTML_BEGIN <= nId && nId < RES_POOLCOLL_HTML_END), + "Falsche AutoFormat-Id" ); + + SwTxtFmtColl* pNewColl = 0; + sal_Bool bFnd = sal_False; + for( sal_uInt16 n = 0; !bFnd && n < pTxtFmtCollTbl->Count(); ++n ) + { + pNewColl = (*pTxtFmtCollTbl)[ n ]; + if( nId == pNewColl->GetPoolFmtId() ) + bFnd = sal_True; + } + + if( !bFnd || !pNewColl->GetDepends() ) + return sal_False; + + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + return !pNewColl->GetInfo( aGetHt ); +} + + // Gebe das "Auto[matische]-Format" mit der Id zurueck. Existiert + // es noch nicht, dann erzeuge es + +SwFmt* SwDoc::GetFmtFromPool( sal_uInt16 nId ) +{ + SwFmt *pNewFmt = 0; + SwFmt *pDeriveFmt = 0; + + SvPtrarr* pArray[ 2 ]; + sal_uInt16 nArrCnt = 1, nRCId = 0; + sal_uInt16* pWhichRange = 0; + + switch( nId & (COLL_GET_RANGE_BITS + POOLGRP_NOCOLLID) ) + { + case POOLGRP_CHARFMT: + { + pArray[0] = pCharFmtTbl; + pDeriveFmt = pDfltCharFmt; + + if( nId > RES_POOLCHR_NORMAL_END ) + nRCId = RC_POOLCHRFMT_HTML_BEGIN - RES_POOLCHR_HTML_BEGIN; + else + nRCId = RC_POOLCHRFMT_BEGIN - RES_POOLCHR_BEGIN; + pWhichRange = aCharFmtSetRange; + + // Fehlerfall: unbekanntes Format, aber CharFormat + // -> returne das erste + if( RES_POOLCHR_BEGIN > nId || nId >= RES_POOLCHR_END ) + { + ASSERT( !this, "ungueltige Id" ); + nId = RES_POOLCHR_BEGIN; + } + } + break; + case POOLGRP_FRAMEFMT: + { + pArray[0] = pFrmFmtTbl; + pArray[1] = pSpzFrmFmtTbl; + pDeriveFmt = pDfltFrmFmt; + nArrCnt = 2; + nRCId = RC_POOLFRMFMT_BEGIN - RES_POOLFRM_BEGIN; + pWhichRange = aFrmFmtSetRange; + + // Fehlerfall: unbekanntes Format, aber FrameFormat + // -> returne das erste + if( RES_POOLFRM_BEGIN > nId || nId >= RES_POOLFRM_END ) + { + ASSERT( !this, "ungueltige Id" ); + nId = RES_POOLFRM_BEGIN; + } + } + break; + + default: + // Fehlerfall, unbekanntes Format + ASSERT( nId, "ungueltige Id" ); + return 0; + } + ASSERT( nRCId, "ungueltige Id" ); + + while( nArrCnt-- ) + for( sal_uInt16 n = 0; n < (*pArray[nArrCnt]).Count(); ++n ) + if( nId == ( pNewFmt = (SwFmt*)(*pArray[ nArrCnt ] )[ n ] )-> + GetPoolFmtId() ) + { + return pNewFmt; + } + + ResId aResId( nRCId + nId, *pSwResMgr ); + String aNm( aResId ); + SwAttrSet aSet( GetAttrPool(), pWhichRange ); + + { + sal_Bool bIsModified = IsModified(); + + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + switch (nId & (COLL_GET_RANGE_BITS + POOLGRP_NOCOLLID) ) + { + case POOLGRP_CHARFMT: + pNewFmt = _MakeCharFmt(aNm, pDeriveFmt, sal_False, sal_True); + break; + case POOLGRP_FRAMEFMT: + pNewFmt = _MakeFrmFmt(aNm, pDeriveFmt, sal_False, sal_True); + break; + default: + break; + } + } + + if( !bIsModified ) + ResetModified(); + pNewFmt->SetPoolFmtId( nId ); + pNewFmt->SetAuto( sal_False ); // kein Auto-Format + } + + switch( nId ) + { + case RES_POOLCHR_FOOTNOTE: // Fussnote + case RES_POOLCHR_PAGENO: // Seiten/Feld + case RES_POOLCHR_LABEL: // Beschriftung + case RES_POOLCHR_DROPCAPS: // Initialien + case RES_POOLCHR_NUM_LEVEL: // Aufzaehlungszeichen + case RES_POOLCHR_TOXJUMP: // Verzeichnissprung + case RES_POOLCHR_ENDNOTE: // Endnote + case RES_POOLCHR_LINENUM: // Zeilennummerierung + break; + + case RES_POOLCHR_ENDNOTE_ANCHOR: // Endnotenanker + case RES_POOLCHR_FOOTNOTE_ANCHOR: // Fussnotenanker + { + aSet.Put( SvxEscapementItem( DFLT_ESC_AUTO_SUPER, 58, RES_CHRATR_ESCAPEMENT ) ); + } + break; + + + case RES_POOLCHR_BUL_LEVEL: // Aufzaehlungszeichen + { + const Font& rBulletFont = numfunc::GetDefBulletFont(); + SetAllScriptItem( aSet, SvxFontItem( rBulletFont.GetFamily(), + rBulletFont.GetName(), rBulletFont.GetStyleName(), + rBulletFont.GetPitch(), rBulletFont.GetCharSet(), RES_CHRATR_FONT )); + // --> OD 2008-06-02 #i63395# + // no font and no font size any more +// SetAllScriptItem( aSet, SvxFontHeightItem( PT_9, 100, RES_CHRATR_FONTSIZE )); + // <-- + } + break; + + case RES_POOLCHR_INET_NORMAL: + { + Color aCol( COL_BLUE ); + aSet.Put( SvxColorItem( aCol, RES_CHRATR_COLOR ) ); + aSet.Put( SvxUnderlineItem( UNDERLINE_SINGLE, RES_CHRATR_UNDERLINE ) ); + // i40133: patch submitted by rail: set language to 'none' to prevent spell checking: + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_LANGUAGE ) ); + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_CJK_LANGUAGE ) ); + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_CTL_LANGUAGE ) ); + } + break; + case RES_POOLCHR_INET_VISIT: + { + Color aCol( COL_RED ); + aSet.Put( SvxColorItem( aCol, RES_CHRATR_COLOR ) ); + aSet.Put( SvxUnderlineItem( UNDERLINE_SINGLE, RES_CHRATR_UNDERLINE ) ); + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_LANGUAGE ) ); + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_CJK_LANGUAGE ) ); + aSet.Put( SvxLanguageItem( LANGUAGE_NONE, RES_CHRATR_CTL_LANGUAGE ) ); + } + break; + case RES_POOLCHR_JUMPEDIT: + { + Color aCol( COL_CYAN ); + aSet.Put( SvxColorItem( aCol, RES_CHRATR_COLOR ) ); + aSet.Put( SvxUnderlineItem( UNDERLINE_DOTTED, RES_CHRATR_UNDERLINE ) ); + aSet.Put( SvxCaseMapItem( SVX_CASEMAP_KAPITAELCHEN, RES_CHRATR_CASEMAP ) ); + } + break; + + case RES_POOLCHR_RUBYTEXT: + { + long nH = ((SvxFontHeightItem*)GetDfltAttr( + RES_CHRATR_CJK_FONTSIZE ))->GetHeight() / 2; + SetAllScriptItem( aSet, SvxFontHeightItem( nH, 100, RES_CHRATR_FONTSIZE)); + aSet.Put(SvxUnderlineItem( UNDERLINE_NONE, RES_CHRATR_UNDERLINE )); + aSet.Put(SvxEmphasisMarkItem( EMPHASISMARK_NONE, RES_CHRATR_EMPHASIS_MARK) ); + } + break; + + case RES_POOLCHR_HTML_EMPHASIS: + case RES_POOLCHR_HTML_CITIATION: + case RES_POOLCHR_HTML_VARIABLE: + { + SetAllScriptItem( aSet, SvxPostureItem( ITALIC_NORMAL, RES_CHRATR_POSTURE) ); + } + break; + + case RES_POOLCHR_IDX_MAIN_ENTRY: + case RES_POOLCHR_HTML_STRONG: + { + SetAllScriptItem( aSet, SvxWeightItem( WEIGHT_BOLD, RES_CHRATR_WEIGHT )); + } + break; + + case RES_POOLCHR_HTML_CODE: + case RES_POOLCHR_HTML_SAMPLE: + case RES_POOLCHR_HTML_KEYBOARD: + case RES_POOLCHR_HTML_TELETYPE: + { + ::lcl_SetDfltFont( DEFAULTFONT_FIXED, aSet ); + } + break; + case RES_POOLCHR_VERT_NUM: + aSet.Put( SvxCharRotateItem( 900, sal_False, RES_CHRATR_ROTATE ) ); + break; +//nichts besonderes +// case RES_POOLCHR_HTML_DEFINSTANCE: +// break; + + + case RES_POOLFRM_FRAME: + { + if ( get(IDocumentSettingAccess::BROWSE_MODE) ) + { + aSet.Put( SwFmtAnchor( FLY_AS_CHAR )); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::LINE_CENTER, text::RelOrientation::PRINT_AREA ) ); + aSet.Put( SwFmtSurround( SURROUND_NONE ) ); + } + else + { + aSet.Put( SwFmtAnchor( FLY_AT_PARA )); + aSet.Put( SwFmtSurround( SURROUND_PARALLEL ) ); + aSet.Put( SwFmtHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::PRINT_AREA ) ); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::PRINT_AREA ) ); + Color aCol( COL_BLACK ); + SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 ); + SvxBoxItem aBox( RES_BOX ); + aBox.SetLine( &aLine, BOX_LINE_TOP ); + aBox.SetLine( &aLine, BOX_LINE_BOTTOM ); + aBox.SetLine( &aLine, BOX_LINE_LEFT ); + aBox.SetLine( &aLine, BOX_LINE_RIGHT ); + aBox.SetDistance( 85 ); + aSet.Put( aBox ); + aSet.Put( SvxLRSpaceItem( 114, 114, 0, 0, RES_LR_SPACE ) ); + aSet.Put( SvxULSpaceItem( 114, 114, RES_UL_SPACE ) ); + } + } + break; + case RES_POOLFRM_GRAPHIC: + case RES_POOLFRM_OLE: + { + aSet.Put( SwFmtAnchor( FLY_AT_PARA )); + aSet.Put( SwFmtHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::FRAME )); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME )); + aSet.Put( SwFmtSurround( SURROUND_NONE )); + } + break; + case RES_POOLFRM_FORMEL: + { + aSet.Put( SwFmtAnchor( FLY_AS_CHAR ) ); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::FRAME ) ); + aSet.Put( SvxLRSpaceItem( 114, 114, 0, 0, RES_LR_SPACE ) ); + } + break; + case RES_POOLFRM_MARGINAL: + { + aSet.Put( SwFmtAnchor( FLY_AT_PARA )); + aSet.Put( SwFmtHoriOrient( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME )); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME )); + aSet.Put( SwFmtSurround( SURROUND_PARALLEL )); + // Breite 3.5 centimeter vorgegeben, als Hoehe nur den + // min. Wert benutzen + aSet.Put( SwFmtFrmSize( ATT_MIN_SIZE, + GetMetricVal( CM_1 ) * 3 + GetMetricVal( CM_05 ), + MM50 )); + } + break; + case RES_POOLFRM_WATERSIGN: + { + aSet.Put( SwFmtAnchor( FLY_AT_PAGE )); + aSet.Put( SwFmtHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::FRAME )); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::CENTER, text::RelOrientation::FRAME )); + aSet.Put( SvxOpaqueItem( sal_False )); + aSet.Put( SwFmtSurround( SURROUND_THROUGHT )); + } + break; + + case RES_POOLFRM_LABEL: + { + aSet.Put( SwFmtAnchor( FLY_AS_CHAR ) ); + aSet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ) ); + aSet.Put( SvxLRSpaceItem( 114, 114, 0, 0, RES_LR_SPACE ) ); + + SvxProtectItem aProtect( RES_PROTECT ); + aProtect.SetSizeProtect( sal_True ); + aProtect.SetPosProtect( sal_True ); + aSet.Put( aProtect ); + + pNewFmt->SetAutoUpdateFmt( sal_True ); + } + break; + } + if( aSet.Count() ) + { + { + pNewFmt->SetFmtAttr( aSet ); + // JP 31.08.95: erzeugen einer PoolVorlage ist keine Modifikation + // (Bug: 18545) + // SetModified(); + } + } + return pNewFmt; +} + +SwFrmFmt* SwDoc::GetFrmFmtFromPool( sal_uInt16 nId ) +{ + return (SwFrmFmt*)GetFmtFromPool( nId ); +} + +SwCharFmt* SwDoc::GetCharFmtFromPool( sal_uInt16 nId ) +{ + return (SwCharFmt*)GetFmtFromPool( nId ); +} + + // pruefe, ob diese "Auto-Collection" in Dokument schon/noch + // benutzt wird +bool SwDoc::IsPoolFmtUsed( sal_uInt16 nId ) const +{ + SwFmt *pNewFmt = 0; + const SvPtrarr* pArray[ 2 ]; + sal_uInt16 nArrCnt = 1; + sal_Bool bFnd = sal_True; + + if( RES_POOLCHR_BEGIN <= nId && nId < RES_POOLCHR_END ) + { + pArray[0] = pCharFmtTbl; + } + if( RES_POOLFRM_BEGIN <= nId && nId < RES_POOLFRM_END ) + { + pArray[0] = pFrmFmtTbl; + pArray[1] = pSpzFrmFmtTbl; + nArrCnt = 2; + } + else + { + ASSERT( sal_False, "ungueltige Id" ); + bFnd = sal_False; + } + + if( bFnd ) + { + bFnd = sal_False; + while( nArrCnt-- && !bFnd ) + for( sal_uInt16 n = 0; !bFnd && n < (*pArray[nArrCnt]).Count(); ++n ) + if( nId == ( pNewFmt = (SwFmt*)(*pArray[ nArrCnt ] )[ n ] )-> + GetPoolFmtId() ) + bFnd = sal_True; + } + + // nicht gefunden oder keine Abhaengigen ? + if( bFnd && pNewFmt->GetDepends() ) + { + // dann teste mal, ob es abhaengige ContentNodes im Nodes Array gibt + // (auch indirekte fuer Format-Ableitung! ) + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + bFnd = !pNewFmt->GetInfo( aGetHt ); + } + else + bFnd = sal_False; + + return bFnd; +} + + + +void lcl_GetStdPgSize( SwDoc* pDoc, SfxItemSet& rSet ) +{ + SwPageDesc* pStdPgDsc = pDoc->GetPageDescFromPool( RES_POOLPAGE_STANDARD ); + SwFmtFrmSize aFrmSz( pStdPgDsc->GetMaster().GetFrmSize() ); + if( pStdPgDsc->GetLandscape() ) + { + SwTwips nTmp = aFrmSz.GetHeight(); + aFrmSz.SetHeight( aFrmSz.GetWidth() ); + aFrmSz.SetWidth( nTmp ); + } + rSet.Put( aFrmSz ); +} + +SwPageDesc* SwDoc::GetPageDescFromPool( sal_uInt16 nId, bool bRegardLanguage ) +{ + ASSERT( RES_POOLPAGE_BEGIN <= nId && nId < RES_POOLPAGE_END, + "Falsche AutoFormat-Id" ); + + SwPageDesc *pNewPgDsc; + sal_uInt16 n; + + for( n = 0; n < aPageDescs.Count(); ++n ) + if( nId == ( pNewPgDsc = aPageDescs[ n ] )->GetPoolFmtId() ) + { + return pNewPgDsc; + } + + // Fehlerfall: unbekannte Poolvorlage + if( RES_POOLPAGE_BEGIN > nId || nId >= RES_POOLPAGE_END ) + { + ASSERT( !this, "ungueltige Id" ); + nId = RES_POOLPAGE_BEGIN; + } + + ResId aResId( sal_uInt32(RC_POOLPAGEDESC_BEGIN + nId - RES_POOLPAGE_BEGIN), *pSwResMgr ); + String aNm( aResId ); + { + sal_Bool bIsModified = IsModified(); + + { + ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo()); + n = MakePageDesc( aNm, 0, bRegardLanguage ); + } + + pNewPgDsc = aPageDescs[ n ]; + pNewPgDsc->SetPoolFmtId( nId ); + if( !bIsModified ) + ResetModified(); + } + + + SvxLRSpaceItem aLR( RES_LR_SPACE ); + aLR.SetLeft( GetMetricVal( CM_1 ) * 2 ); + aLR.SetRight( aLR.GetLeft() ); + SvxULSpaceItem aUL( RES_UL_SPACE ); + aUL.SetUpper( (sal_uInt16)aLR.GetLeft() ); + aUL.SetLower( (sal_uInt16)aLR.GetLeft() ); + + SwAttrSet aSet( GetAttrPool(), aPgFrmFmtSetRange ); + sal_Bool bSetLeft = sal_True; + + switch( nId ) + { + case RES_POOLPAGE_STANDARD: // Standard-Seite + { + aSet.Put( aLR ); + aSet.Put( aUL ); + if( pNewPgDsc ) + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + } + break; + + case RES_POOLPAGE_FIRST: // Erste Seite + case RES_POOLPAGE_REGISTER: // Verzeichnis + { + lcl_GetStdPgSize( this, aSet ); + aSet.Put( aLR ); + aSet.Put( aUL ); + if( pNewPgDsc ) + { + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + if( RES_POOLPAGE_FIRST == nId ) + pNewPgDsc->SetFollow( GetPageDescFromPool( RES_POOLPAGE_STANDARD )); + } + } + break; + + case RES_POOLPAGE_LEFT: // Linke Seite + { + lcl_GetStdPgSize( this, aSet ); + aSet.Put( aLR ); + aSet.Put( aUL ); + bSetLeft = sal_False; + if( pNewPgDsc ) + pNewPgDsc->SetUseOn( nsUseOnPage::PD_LEFT ); + } + break; + case RES_POOLPAGE_RIGHT: // Rechte Seite + { + lcl_GetStdPgSize( this, aSet ); + aSet.Put( aLR ); + aSet.Put( aUL ); + bSetLeft = sal_False; + if( pNewPgDsc ) + pNewPgDsc->SetUseOn( nsUseOnPage::PD_RIGHT ); + } + break; + + case RES_POOLPAGE_JAKET: // Umschlag + { + aLR.SetLeft( 0 ); aLR.SetRight( 0 ); + aUL.SetUpper( 0 ); aUL.SetLower( 0 ); + Size aPSize( SvxPaperInfo::GetPaperSize( PAPER_ENV_C65 ) ); + LandscapeSwap( aPSize ); + aSet.Put( SwFmtFrmSize( ATT_FIX_SIZE, aPSize.Width(), aPSize.Height() )); + aSet.Put( aLR ); + aSet.Put( aUL ); + + if( pNewPgDsc ) + { + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + pNewPgDsc->SetLandscape( sal_True ); + } + } + break; + + case RES_POOLPAGE_HTML: // HTML + { + lcl_GetStdPgSize( this, aSet ); + aLR.SetRight( GetMetricVal( CM_1 )); + aUL.SetUpper( (sal_uInt16)aLR.GetRight() ); + aUL.SetLower( (sal_uInt16)aLR.GetRight() ); + aSet.Put( aLR ); + aSet.Put( aUL ); + + if( pNewPgDsc ) + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + } + break; + case RES_POOLPAGE_FOOTNOTE: + case RES_POOLPAGE_ENDNOTE: + { + lcl_GetStdPgSize( this, aSet ); + aSet.Put( aLR ); + aSet.Put( aUL ); + if( pNewPgDsc ) + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + SwPageFtnInfo aInf( pNewPgDsc->GetFtnInfo() ); + aInf.SetLineWidth( 0 ); + aInf.SetTopDist( 0 ); + aInf.SetBottomDist( 0 ); + pNewPgDsc->SetFtnInfo( aInf ); + } + break; + case RES_POOLPAGE_LANDSCAPE: + { + SwPageDesc* pStdPgDsc = this->GetPageDescFromPool( RES_POOLPAGE_STANDARD ); + SwFmtFrmSize aFrmSz( pStdPgDsc->GetMaster().GetFrmSize() ); + SwTwips nTmp = aFrmSz.GetHeight(); + aFrmSz.SetHeight( aFrmSz.GetWidth() ); + aFrmSz.SetWidth( nTmp ); + aSet.Put( aFrmSz ); + aSet.Put( aLR ); + aSet.Put( aUL ); + if( pNewPgDsc ) + { + pNewPgDsc->SetUseOn( nsUseOnPage::PD_ALL ); + pNewPgDsc->SetLandscape( sal_True ); + } + } + break; + + } + + if( aSet.Count() ) + { + { + if( bSetLeft ) + pNewPgDsc->GetLeft().SetFmtAttr( aSet ); + pNewPgDsc->GetMaster().SetFmtAttr( aSet ); + // JP 31.08.95: erzeugen einer PoolVorlage ist keine Modifikation + // (Bug: 18545) + // SetModified(); + } + } + return pNewPgDsc; +} + +SwNumRule* SwDoc::GetNumRuleFromPool( sal_uInt16 nId ) +{ + ASSERT( RES_POOLNUMRULE_BEGIN <= nId && nId < RES_POOLNUMRULE_END, + "Falsche AutoFormat-Id" ); + + SwNumRule* pNewRule; + sal_uInt16 n; + + for( n = 0; n < GetNumRuleTbl().Count(); ++n ) + if( nId == ( pNewRule = GetNumRuleTbl()[ n ] )->GetPoolFmtId() ) + { + return pNewRule; + } + + // Fehlerfall: unbekannte Poolvorlage + if( RES_POOLNUMRULE_BEGIN > nId || nId >= RES_POOLNUMRULE_END ) + { + ASSERT( !this, "ungueltige Id" ); + nId = RES_POOLNUMRULE_BEGIN; + } + + ResId aResId( sal_uInt32(RC_POOLNUMRULE_BEGIN + nId - RES_POOLNUMRULE_BEGIN), *pSwResMgr ); + String aNm( aResId ); + + SwCharFmt *pNumCFmt = 0, *pBullCFmt = 0; + + // --> OD 2008-02-11 #newlistlevelattrs# + const SvxNumberFormat::SvxNumPositionAndSpaceMode eNumberFormatPositionAndSpaceMode + // --> OD 2008-06-06 #i89178# + = numfunc::GetDefaultPositionAndSpaceMode(); + // <-- + // <-- + { + sal_Bool bIsModified = IsModified(); + // --> OD 2008-02-11 #newlistlevelattrs# + n = MakeNumRule( aNm, 0, sal_False, eNumberFormatPositionAndSpaceMode ); + // <-- + pNewRule = GetNumRuleTbl()[ n ]; + pNewRule->SetPoolFmtId( nId ); + pNewRule->SetAutoRule( sal_False ); + + if( RES_POOLNUMRULE_NUM1 <= nId && nId <= RES_POOLNUMRULE_NUM5 ) + pNumCFmt = GetCharFmtFromPool( RES_POOLCHR_NUM_LEVEL ); + + if( ( RES_POOLNUMRULE_BUL1 <= nId && nId <= RES_POOLNUMRULE_BUL5 ) || + RES_POOLNUMRULE_NUM5 == nId ) + pBullCFmt = GetCharFmtFromPool( RES_POOLCHR_NUM_LEVEL ); + + if( !bIsModified ) + ResetModified(); + } + + switch( nId ) + { + case RES_POOLNUMRULE_NUM1: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_ARABIC); + aFmt.SetCharFmt( pNumCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + aFmt.SetSuffix( aDotStr ); + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,5 1,0 1,5 2,0 2,5 3,0 3,5 4,0 4,5 5,0 + 283, 567, 850, 1134, 1417, 1701, 1984, 2268, 2551, 2835 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 283, 567, 850, 1134, 1417, 1701, 1984, 2268, 2551, 2835 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + + case RES_POOLNUMRULE_NUM2: + { + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { + 283, 283, 567, 709, // 0.50, 0.50, 1.00, 1.25 + 850, 1021, 1304, 1474, // 1.50, 1.80, 2.30, 2.60 + 1588, 1758 // 2.80, 3.10 + }; + +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 385, 385, 770, 963, + 1155, 1386, 1771, 2002, + 2156, 2387 + }; + + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_ARABIC); + aFmt.SetCharFmt( pNumCFmt ); + aFmt.SetIncludeUpperLevels( 1 ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + } + // <-- + sal_uInt16 nSpace = 0; + for( n = 0; n < MAXLEVEL; ++n ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( nSpace = nSpace + pArr[ n ] ); + aFmt.SetFirstLineOffset( - pArr[ n ] ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( nSpace = nSpace + pArr[ n ] ); + aFmt.SetIndentAt( nSpace ); + aFmt.SetFirstLineIndent( - pArr[ n ] ); + } + // <-- + aFmt.SetStart( n+1 ); + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_NUM3: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_ARABIC); + aFmt.SetCharFmt( pNumCFmt ); + aFmt.SetIncludeUpperLevels( 1 ); + + sal_uInt16 nOffs = GetMetricVal( CM_1 ) * 3; + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - nOffs ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - nOffs ); + } + // <-- + + for( n = 0; n < MAXLEVEL; ++n ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( (n+1) * nOffs ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( (n+1) * nOffs ); + aFmt.SetIndentAt( (n+1) * nOffs ); + } + // <-- + aFmt.SetStart( n+1 ); + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_NUM4: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_ROMAN_UPPER); + aFmt.SetCharFmt( pNumCFmt ); + aFmt.SetIncludeUpperLevels( 1 ); + aFmt.SetSuffix( aDotStr ); + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,5 1,0 1,5 2,0 2,5 3,0 3,5 4,0 4,5 5,0 + 283, 567, 850, 1134, 1417, 1701, 1984, 2268, 2551, 2835 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 283, 567, 850, 1134, 1417, 1701, 1984, 2268, 2551, 2835 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::SPACE ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + aFmt.SetStart( n + 1 ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_NUM5: + { + // [ First, LSpace ] + static const sal_uInt16 aAbsSpace0to2[] = + { + 227, 227, // 0.40, 0.40, + 369, 624, // 0.65, 1.10, + 255, 879 // 0.45, 1.55 + }; + +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch0to2[] = + { + 308, 308, + 501, 847, + 347, 1194 + }; + const sal_uInt16* pArr0to2 = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace0to2 + : aAbsSpaceInch0to2; +#else + const sal_uInt16* pArr0to2 = aAbsSpace0to2; +#endif + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_ARABIC); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + aFmt.SetSuffix( aDotStr ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + } + // <-- + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( -pArr0to2[0] ); // == 0.40 cm + aFmt.SetAbsLSpace( pArr0to2[1] ); // == 0.40 cm + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetFirstLineIndent( -pArr0to2[0] ); + aFmt.SetListtabPos( pArr0to2[1] ); + aFmt.SetIndentAt( pArr0to2[1] ); + } + // <-- + + aFmt.SetCharFmt( pNumCFmt ); + pNewRule->Set( 0, aFmt ); + + aFmt.SetIncludeUpperLevels( 2 ); + aFmt.SetStart( 2 ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( -pArr0to2[2] ); // == 0.65 cm + aFmt.SetAbsLSpace( pArr0to2[3] ); // == 1.10 cm + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetFirstLineIndent( -pArr0to2[2] ); + aFmt.SetListtabPos( pArr0to2[3] ); + aFmt.SetIndentAt( pArr0to2[3] ); + } + // <-- + pNewRule->Set( 1, aFmt ); + + aFmt.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); + aFmt.SetSuffix( ')'); + aFmt.SetIncludeUpperLevels( 1 ); + aFmt.SetStart( 3 ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - pArr0to2[4] ); // == 0.45cm + aFmt.SetAbsLSpace( pArr0to2[5] ); // == 1.55 cm + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetFirstLineIndent( -pArr0to2[4] ); + aFmt.SetListtabPos( pArr0to2[5] ); + aFmt.SetIndentAt( pArr0to2[5] ); + } + // <-- + pNewRule->Set( 2, aFmt ); + + + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + aFmt.SetBulletChar( cBulletChar ); + sal_uInt16 nOffs = GetMetricVal( CM_01 ) * 4, + nOffs2 = GetMetricVal( CM_1 ) * 2; + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - nOffs ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetFirstLineIndent( - nOffs ); + } + // <-- + aFmt.SetSuffix( aEmptyStr ); + for( n = 3; n < MAXLEVEL; ++n ) + { + aFmt.SetStart( n+1 ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( nOffs2 + ((n-3) * nOffs) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( nOffs2 + ((n-3) * nOffs) ); + aFmt.SetIndentAt( nOffs2 + ((n-3) * nOffs) ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + + case RES_POOLNUMRULE_BUL1: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + aFmt.SetBulletChar( cBulletChar ); + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,4 0,8 1,2 1,6 2,0 2,4 2,8 3,2 3,6 4,0 + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_BUL2: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + aFmt.SetBulletChar( 0x2013 ); + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,3 0,6 0,9 1,2 1,5 1,8 2,1 2,4 2,7 3,0 + 170, 340, 510, 680, 850, 1020, 1191, 1361, 1531, 1701 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 170, 340, 510, 680, 850, 1020, 1191, 1361, 1531, 1701 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_BUL3: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + + sal_uInt16 nOffs = GetMetricVal( CM_01 ) * 4; + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - nOffs ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - nOffs ); + } + // <-- + + for( n = 0; n < MAXLEVEL; ++n ) + { + aFmt.SetBulletChar( ( n & 1 ? 0x25a1 : 0x2611 ) ); + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( ((n & 1) +1) * nOffs ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( ((n & 1) +1) * nOffs ); + aFmt.SetIndentAt( ((n & 1) +1) * nOffs ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_BUL4: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,4 0,8 1,2 1,6 2,0 2,4 2,8 3,2 3,6 4,0 + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::SPACE ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + switch( n ) + { + case 0: aFmt.SetBulletChar( 0x27a2 ); break; + case 1: aFmt.SetBulletChar( 0xE006 ); break; + default: aFmt.SetBulletChar( 0xE004 ); break; + } + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + case RES_POOLNUMRULE_BUL5: + { + SwNumFmt aFmt; + // --> OD 2008-02-11 #newlistlevelattrs# + aFmt.SetPositionAndSpaceMode( eNumberFormatPositionAndSpaceMode ); + // <-- + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + aFmt.SetCharFmt( pBullCFmt ); + aFmt.SetStart( 1 ); + aFmt.SetIncludeUpperLevels( 1 ); + aFmt.SetBulletChar( 0x2717 ); + // --> OD 2006-06-29 #6440955# + aFmt.SetBulletFont( &numfunc::GetDefBulletFont() ); + // <-- + + static const sal_uInt16 aAbsSpace[ MAXLEVEL ] = + { +// cm: 0,4 0,8 1,2 1,6 2,0 2,4 2,8 3,2 3,6 4,0 + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; +#ifdef USE_MEASUREMENT + static const sal_uInt16 aAbsSpaceInch[ MAXLEVEL ] = + { + 227, 454, 680, 907, 1134, 1361, 1587, 1814, 2041, 2268 + }; + const sal_uInt16* pArr = MEASURE_METRIC == + SvtSysLocale().GetLocaleData().getMeasurementSystemEnum() + ? aAbsSpace + : aAbsSpaceInch; +#else + const sal_uInt16* pArr = aAbsSpace; +#endif + + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetFirstLineOffset( - (*pArr) ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmt.SetFirstLineIndent( - (*pArr) ); + } + // <-- + for( n = 0; n < MAXLEVEL; ++n, ++pArr ) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmt.SetAbsLSpace( *pArr ); + } + else if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT ) + { + aFmt.SetListtabPos( *pArr ); + aFmt.SetIndentAt( *pArr ); + } + // <-- + pNewRule->Set( n, aFmt ); + } + } + break; + } + + return pNewRule; +} + + + + // pruefe, ob diese "Auto-Collection" in Dokument schon/noch + // benutzt wird +bool SwDoc::IsPoolPageDescUsed( sal_uInt16 nId ) const +{ + ASSERT( RES_POOLPAGE_BEGIN <= nId && nId < RES_POOLPAGE_END, + "Falsche AutoFormat-Id" ); + SwPageDesc *pNewPgDsc = 0; + sal_Bool bFnd = sal_False; + for( sal_uInt16 n = 0; !bFnd && n < aPageDescs.Count(); ++n ) + { + pNewPgDsc = aPageDescs[ n ]; + if( nId == pNewPgDsc->GetPoolFmtId() ) + bFnd = sal_True; + } + + // nicht gefunden oder keine Abhaengigen ? + if( !bFnd || !pNewPgDsc->GetDepends() ) // ?????? + return sal_False; + + // dann teste mal, ob es abhaengige ContentNodes im Nodes Array gibt + // (auch indirekte fuer Format-Ableitung! ) + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + return !pNewPgDsc->GetInfo( aGetHt ); +} + +// erfrage ob die Absatz-/Zeichen-/Rahmen-/Seiten - Vorlage benutzt wird +sal_Bool SwDoc::IsUsed( const SwModify& rModify ) const +{ + // dann teste mal, ob es abhaengige ContentNodes im Nodes Array gibt + // (auch indirekte fuer Format-Ableitung! ) + SwAutoFmtGetDocNode aGetHt( &GetNodes() ); + return !rModify.GetInfo( aGetHt ); +} + +// erfrage ob die NumRule benutzt wird +sal_Bool SwDoc::IsUsed( const SwNumRule& rRule ) const +{ + // --> OD 2008-03-04 #refactorlists# +// // dann teste mal, ob es abhaengige ContentNodes im Nodes Array gibt +// // (auch indirekte fuer Format-Ableitung! ) +// sal_Bool bUsed = sal_False; +// SwAutoFmtGetDocNode aGetHt( &aNodes ); +// SwModify* pMod; +// const SfxPoolItem* pItem; +// sal_uInt16 i, nMaxItems = GetAttrPool().GetItemCount( RES_PARATR_NUMRULE); +// for( i = 0; i < nMaxItems; ++i ) +// { +// if( 0 != (pItem = GetAttrPool().GetItem( RES_PARATR_NUMRULE, i ) ) && +// 0 != ( pMod = (SwModify*)((SwNumRuleItem*)pItem)->GetDefinedIn()) && +// ((SwNumRuleItem*)pItem)->GetValue().Len() && +// ((SwNumRuleItem*)pItem)->GetValue() == rRule.GetName() ) +// { +// if( pMod->IsA( TYPE( SwFmt )) ) +// { +// bUsed = !pMod->GetInfo( aGetHt ); +// if( bUsed ) +// break; +// } +// else if( ((SwTxtNode*)pMod)->GetNodes().IsDocNodes() ) +// { +// bUsed = sal_True; +// break; +// } +// } +// } + +// return bUsed; + sal_Bool bUsed = rRule.GetTxtNodeListSize() > 0 || + rRule.GetParagraphStyleListSize() > 0; + + return bUsed; + // <-- +} + + // Suche die Position vom Vorlagen-Namen. Ist nicht vorhanden + // dann fuege neu ein +sal_uInt16 SwDoc::SetDocPattern( const String& rPatternName ) +{ + ASSERT( rPatternName.Len(), "kein Dokument-Vorlagenname" ); + + sal_uInt16 nNewPos = aPatternNms.Count(); + for( sal_uInt16 n = 0; n < aPatternNms.Count(); ++n ) + if( !aPatternNms[n] ) + { + if( nNewPos == aPatternNms.Count() ) + nNewPos = n; + } + else if( rPatternName == *aPatternNms[n] ) + return n; + + if( nNewPos < aPatternNms.Count() ) + aPatternNms.Remove( nNewPos ); // Platz wieder frei machen + + String* pNewNm = new String( rPatternName ); + aPatternNms.Insert( pNewNm, nNewPos ); + SetModified(); + return nNewPos; +} + +sal_uInt16 GetPoolParent( sal_uInt16 nId ) +{ + sal_uInt16 nRet = USHRT_MAX; + if( POOLGRP_NOCOLLID & nId ) // 1 == Formate / 0 == Collections + { + switch( ( COLL_GET_RANGE_BITS | POOLGRP_NOCOLLID ) & nId ) + { + case POOLGRP_CHARFMT: + case POOLGRP_FRAMEFMT: + nRet = 0; // vom default abgeleitet + break; + case POOLGRP_PAGEDESC: + case POOLGRP_NUMRULE: + break; // es gibt keine Ableitung + } + } + else + { + switch( COLL_GET_RANGE_BITS & nId ) + { + case COLL_TEXT_BITS: + switch( nId ) + { + case RES_POOLCOLL_STANDARD: + nRet = 0; break; + case RES_POOLCOLL_TEXT_IDENT: + case RES_POOLCOLL_TEXT_NEGIDENT: + case RES_POOLCOLL_TEXT_MOVE: + case RES_POOLCOLL_CONFRONTATION: + case RES_POOLCOLL_MARGINAL: + nRet = RES_POOLCOLL_TEXT; break; + + case RES_POOLCOLL_TEXT: + case RES_POOLCOLL_GREETING: + case RES_POOLCOLL_SIGNATURE: + case RES_POOLCOLL_HEADLINE_BASE: + nRet = RES_POOLCOLL_STANDARD; break; + + case RES_POOLCOLL_HEADLINE1: + case RES_POOLCOLL_HEADLINE2: + case RES_POOLCOLL_HEADLINE3: + case RES_POOLCOLL_HEADLINE4: + case RES_POOLCOLL_HEADLINE5: + case RES_POOLCOLL_HEADLINE6: + case RES_POOLCOLL_HEADLINE7: + case RES_POOLCOLL_HEADLINE8: + case RES_POOLCOLL_HEADLINE9: + case RES_POOLCOLL_HEADLINE10: + nRet = RES_POOLCOLL_HEADLINE_BASE; break; + } + break; + + case COLL_LISTS_BITS: + switch( nId ) + { + case RES_POOLCOLL_NUMBUL_BASE: + nRet = RES_POOLCOLL_TEXT; break; + + default: + nRet = RES_POOLCOLL_NUMBUL_BASE; break; + } + break; + + case COLL_EXTRA_BITS: + switch( nId ) + { + case RES_POOLCOLL_FRAME: + nRet = RES_POOLCOLL_TEXT; break; + + case RES_POOLCOLL_TABLE_HDLN: + nRet = RES_POOLCOLL_TABLE; break; + + case RES_POOLCOLL_TABLE: + case RES_POOLCOLL_FOOTNOTE: + case RES_POOLCOLL_ENDNOTE: + case RES_POOLCOLL_JAKETADRESS: + case RES_POOLCOLL_SENDADRESS: + case RES_POOLCOLL_HEADER: + case RES_POOLCOLL_HEADERL: + case RES_POOLCOLL_HEADERR: + case RES_POOLCOLL_FOOTER: + case RES_POOLCOLL_FOOTERL: + case RES_POOLCOLL_FOOTERR: + case RES_POOLCOLL_LABEL: + nRet = RES_POOLCOLL_STANDARD; break; + + case RES_POOLCOLL_LABEL_ABB: + case RES_POOLCOLL_LABEL_TABLE: + case RES_POOLCOLL_LABEL_FRAME: + case RES_POOLCOLL_LABEL_DRAWING: + nRet = RES_POOLCOLL_LABEL; break; + } + break; + + case COLL_REGISTER_BITS: + switch( nId ) + { + case RES_POOLCOLL_REGISTER_BASE: + nRet = RES_POOLCOLL_STANDARD; break; + + case RES_POOLCOLL_TOX_USERH: + case RES_POOLCOLL_TOX_CNTNTH: + case RES_POOLCOLL_TOX_IDXH: + case RES_POOLCOLL_TOX_ILLUSH: + case RES_POOLCOLL_TOX_OBJECTH: + case RES_POOLCOLL_TOX_TABLESH: + case RES_POOLCOLL_TOX_AUTHORITIESH: + nRet = RES_POOLCOLL_HEADLINE_BASE; break; + + default: + nRet = RES_POOLCOLL_REGISTER_BASE; break; + } + break; + + case COLL_DOC_BITS: + nRet = RES_POOLCOLL_HEADLINE_BASE; + break; + + case COLL_HTML_BITS: + nRet = RES_POOLCOLL_STANDARD; + break; + } + } + + return nRet; +} + +void SwDoc::RemoveAllFmtLanguageDependencies() +{ + /* #106748# Restore the language independ pool defaults and styles. */ + GetAttrPool().ResetPoolDefaultItem( RES_PARATR_ADJUST ); + + SwTxtFmtColl * pTxtFmtColl = GetTxtCollFromPool( RES_POOLCOLL_STANDARD ); + + pTxtFmtColl->ResetFmtAttr( RES_PARATR_ADJUST ); + /* #111214# koreans do not like SvxScriptItem(sal_True) */ + pTxtFmtColl->ResetFmtAttr( RES_PARATR_SCRIPTSPACE ); + + SvxFrameDirectionItem aFrameDir( FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR ); + + sal_uInt16 nCount = GetPageDescCnt(); + for( sal_uInt16 i=0; i<nCount; ++i ) + { + SwPageDesc& rDesc = _GetPageDesc( i ); + rDesc.GetMaster().SetFmtAttr( aFrameDir ); + rDesc.GetLeft().SetFmtAttr( aFrameDir ); + } + + // OD 09.10.2003 #i18732# - restore static pool default for item + // RES_FOLLOW_TEXT_FLOW. + GetAttrPool().ResetPoolDefaultItem( RES_FOLLOW_TEXT_FLOW ); + + //#i16874# AutoKerning as default for new documents + GetAttrPool().ResetPoolDefaultItem( RES_CHRATR_AUTOKERN ); +} diff --git a/sw/source/core/doc/sortopt.cxx b/sw/source/core/doc/sortopt.cxx new file mode 100644 index 000000000000..e845ec6f6897 --- /dev/null +++ b/sw/source/core/doc/sortopt.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <tools/debug.hxx> +#include <i18npool/lang.h> +#include <sortopt.hxx> + + +SV_IMPL_PTRARR(SwSortKeys, SwSortKey*) + +/*-------------------------------------------------------------------- + Beschreibung: Sortier-Schluessel + --------------------------------------------------------------------*/ + +SwSortKey::SwSortKey() : + eSortOrder( SRT_ASCENDING ), + nColumnId( 0 ), + bIsNumeric( sal_True ) +{ +} + +SwSortKey::SwSortKey(sal_uInt16 nId, const String& rSrtType, SwSortOrder eOrder) : + sSortType( rSrtType ), + eSortOrder( eOrder ), + nColumnId( nId ), + bIsNumeric( 0 == rSrtType.Len() ) +{ +} + + +SwSortKey::SwSortKey(const SwSortKey& rOld) : + sSortType( rOld.sSortType ), + eSortOrder( rOld.eSortOrder ), + nColumnId( rOld.nColumnId ), + bIsNumeric( rOld.bIsNumeric ) +{ +} + +/*-------------------------------------------------------------------- + Beschreibung: Sortieroptionen fuers Sortieren + --------------------------------------------------------------------*/ + + +SwSortOptions::SwSortOptions() + : eDirection( SRT_ROWS ), + cDeli( 9 ), + nLanguage( LANGUAGE_SYSTEM ), + bTable( sal_False ), + bIgnoreCase( sal_False ) +{ +} + + +SwSortOptions::SwSortOptions(const SwSortOptions& rOpt) : + eDirection( rOpt.eDirection ), + cDeli( rOpt.cDeli ), + nLanguage( rOpt.nLanguage ), + bTable( rOpt.bTable ), + bIgnoreCase( rOpt.bIgnoreCase ) +{ + for( sal_uInt16 i=0; i < rOpt.aKeys.Count(); ++i ) + { + SwSortKey* pNew = new SwSortKey(*rOpt.aKeys[i]); + aKeys.C40_INSERT( SwSortKey, pNew, aKeys.Count()); + } +} + + +SwSortOptions::~SwSortOptions() +{ + aKeys.DeleteAndDestroy(0, aKeys.Count()); +} + + + diff --git a/sw/source/core/doc/swserv.cxx b/sw/source/core/doc/swserv.cxx new file mode 100644 index 000000000000..7903bffa2309 --- /dev/null +++ b/sw/source/core/doc/swserv.cxx @@ -0,0 +1,371 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <sot/storage.hxx> +#include <sfx2/linkmgr.hxx> +#include <com/sun/star/uno/Sequence.h> +#include <doc.hxx> +#include <swtypes.hxx> +#include <swserv.hxx> +#include <swbaslnk.hxx> +#include <mvsave.hxx> +#include <IMark.hxx> +#include <bookmrk.hxx> +#include <pam.hxx> +#include <shellio.hxx> +#ifndef _SWERROR_H +#include <swerror.h> +#endif + +using namespace ::com::sun::star; + +SV_IMPL_REF( SwServerObject ) + +SwServerObject::~SwServerObject() +{ +} + + +sal_Bool SwServerObject::GetData( uno::Any & rData, + const String & rMimeType, sal_Bool ) +{ + sal_Bool bRet = sal_False; + WriterRef xWrt; + switch( SotExchange::GetFormatIdFromMimeType( rMimeType ) ) + { + case FORMAT_STRING: + ::GetASCWriter( aEmptyStr, String(), xWrt ); + break; + + case FORMAT_RTF: + // mba: no BaseURL for data exchange + ::GetRTFWriter( aEmptyStr, String(), xWrt ); + break; + } + + if( xWrt.Is() ) + { + SwPaM* pPam = 0; + switch( eType ) + { + case BOOKMARK_SERVER: + if( CNTNT_TYPE.pBkmk->IsExpanded() ) + { + // Bereich aufspannen + pPam = new SwPaM( CNTNT_TYPE.pBkmk->GetMarkPos(), + CNTNT_TYPE.pBkmk->GetOtherMarkPos() ); + } + break; + + case TABLE_SERVER: + pPam = new SwPaM( *CNTNT_TYPE.pTblNd, + *CNTNT_TYPE.pTblNd->EndOfSectionNode() ); + break; + + case SECTION_SERVER: + pPam = new SwPaM( SwPosition( *CNTNT_TYPE.pSectNd ) ); + pPam->Move( fnMoveForward ); + pPam->SetMark(); + pPam->GetPoint()->nNode = *CNTNT_TYPE.pSectNd->EndOfSectionNode(); + pPam->Move( fnMoveBackward ); + break; + case NONE_SERVER: break; + } + + if( pPam ) + { + // Stream anlegen + SvMemoryStream aMemStm( 65535, 65535 ); + SwWriter aWrt( aMemStm, *pPam, sal_False ); + if( !IsError( aWrt.Write( xWrt )) ) + { + aMemStm << '\0'; // append a zero char + rData <<= uno::Sequence< sal_Int8 >( + (sal_Int8*)aMemStm.GetData(), + aMemStm.Seek( STREAM_SEEK_TO_END ) ); + bRet = sal_True; + } + + delete pPam; + } + } + return bRet; +} + + +sal_Bool SwServerObject::SetData( const String & , + const uno::Any& ) +{ + // set new data into the "server" -> at first nothing to do + return sal_False; +} + + +void SwServerObject::SendDataChanged( const SwPosition& rPos ) +{ + // ist an unseren Aenderungen jemand interessiert ? + if( HasDataLinks() ) + { + int bCall = sal_False; + const SwStartNode* pNd = 0; + switch( eType ) + { + case BOOKMARK_SERVER: + if( CNTNT_TYPE.pBkmk->IsExpanded() ) + { + bCall = CNTNT_TYPE.pBkmk->GetMarkStart() <= rPos + && rPos < CNTNT_TYPE.pBkmk->GetMarkEnd(); + } + break; + + case TABLE_SERVER: pNd = CNTNT_TYPE.pTblNd; break; + case SECTION_SERVER: pNd = CNTNT_TYPE.pSectNd; break; + case NONE_SERVER: break; + } + if( pNd ) + { + sal_uLong nNd = rPos.nNode.GetIndex(); + bCall = pNd->GetIndex() < nNd && nNd < pNd->EndOfSectionIndex(); + } + + if( bCall ) + { + // Recursionen erkennen und flaggen + IsLinkInServer( 0 ); + SvLinkSource::NotifyDataChanged(); + } + } + // sonst melden wir uns ab !! +// ????? JP 27.06.95: geht das so ???? +// else +// Closed(); +} + + +void SwServerObject::SendDataChanged( const SwPaM& rRange ) +{ + // ist an unseren Aenderungen jemand interessiert ? + if( HasDataLinks() ) + { + int bCall = sal_False; + const SwStartNode* pNd = 0; + const SwPosition* pStt = rRange.Start(), *pEnd = rRange.End(); + switch( eType ) + { + case BOOKMARK_SERVER: + if(CNTNT_TYPE.pBkmk->IsExpanded()) + { + bCall = *pStt <= CNTNT_TYPE.pBkmk->GetMarkEnd() + && *pEnd > CNTNT_TYPE.pBkmk->GetMarkStart(); + } + break; + + case TABLE_SERVER: pNd = CNTNT_TYPE.pTblNd; break; + case SECTION_SERVER: pNd = CNTNT_TYPE.pSectNd; break; + case NONE_SERVER: break; + } + if( pNd ) + { + // liegt der Start-Bereich im Node Bereich ? + bCall = pStt->nNode.GetIndex() < pNd->EndOfSectionIndex() && + pEnd->nNode.GetIndex() >= pNd->GetIndex(); + } + + if( bCall ) + { + // Recursionen erkennen und flaggen + IsLinkInServer( 0 ); + SvLinkSource::NotifyDataChanged(); + } + } + // sonst melden wir uns ab !! +// ????? JP 27.06.95: geht das so ???? +// else +// Closed(); +} + + +sal_Bool SwServerObject::IsLinkInServer( const SwBaseLink* pChkLnk ) const +{ + sal_uLong nSttNd = 0, nEndNd = 0; + xub_StrLen nStt = 0; + xub_StrLen nEnd = 0; + const SwNode* pNd = 0; + const SwNodes* pNds = 0; + + switch( eType ) + { + case BOOKMARK_SERVER: + if( CNTNT_TYPE.pBkmk->IsExpanded() ) + { + const SwPosition* pStt = &CNTNT_TYPE.pBkmk->GetMarkStart(), + * pEnd = &CNTNT_TYPE.pBkmk->GetMarkEnd(); + + nSttNd = pStt->nNode.GetIndex(); + nStt = pStt->nContent.GetIndex(); + nEndNd = pEnd->nNode.GetIndex(); + nEnd = pEnd->nContent.GetIndex(); + pNds = &pStt->nNode.GetNodes(); + } + break; + + case TABLE_SERVER: pNd = CNTNT_TYPE.pTblNd; break; + case SECTION_SERVER: pNd = CNTNT_TYPE.pSectNd; break; + + case SECTION_SERVER+1: + return sal_True; + } + + if( pNd ) + { + nSttNd = pNd->GetIndex(); + nEndNd = pNd->EndOfSectionIndex(); + nStt = 0, nEnd = USHRT_MAX; + pNds = &pNd->GetNodes(); + } + + if( nSttNd && nEndNd ) + { + // LinkManager besorgen: + const ::sfx2::SvBaseLinks& rLnks = pNds->GetDoc()->GetLinkManager().GetLinks(); + +// um Rekursionen zu Verhindern: ServerType umsetzen! +SwServerObject::ServerModes eSave = eType; +if( !pChkLnk ) +// sowas sollte man nicht tun, wer weiss schon, wie gross ein enum ist +// ICC nimmt keinen int +// #41723# +// *((int*)&eType) = SECTION_SERVER+1; + ((SwServerObject*)this)->eType = NONE_SERVER; + for( sal_uInt16 n = rLnks.Count(); n; ) + { + const ::sfx2::SvBaseLink* pLnk = &(*rLnks[ --n ]); + if( pLnk && OBJECT_CLIENT_GRF != pLnk->GetObjType() && + pLnk->ISA( SwBaseLink ) && + !((SwBaseLink*)pLnk)->IsNoDataFlag() && + ((SwBaseLink*)pLnk)->IsInRange( nSttNd, nEndNd, nStt, nEnd )) + { + if( pChkLnk ) + { + if( pLnk == pChkLnk || + ((SwBaseLink*)pLnk)->IsRecursion( pChkLnk ) ) + return sal_True; + } + else if( ((SwBaseLink*)pLnk)->IsRecursion( (SwBaseLink*)pLnk ) ) + ((SwBaseLink*)pLnk)->SetNoDataFlag(); + } + } +if( !pChkLnk ) + // *((int*)&eType) = eSave; + ((SwServerObject*)this)->eType = eSave; + } + + return sal_False; +} + +void SwServerObject::SetNoServer() +{ + if(eType == BOOKMARK_SERVER && CNTNT_TYPE.pBkmk) + { + ::sw::mark::DdeBookmark* const pDdeBookmark = dynamic_cast< ::sw::mark::DdeBookmark* >(CNTNT_TYPE.pBkmk); + if(pDdeBookmark) + { + CNTNT_TYPE.pBkmk = 0, eType = NONE_SERVER; + pDdeBookmark->SetRefObject(NULL); + } + } +} + +void SwServerObject::SetDdeBookmark( ::sw::mark::IMark& rBookmark) +{ + ::sw::mark::DdeBookmark* const pDdeBookmark = dynamic_cast< ::sw::mark::DdeBookmark* >(&rBookmark); + if(pDdeBookmark) + { + eType = BOOKMARK_SERVER; + CNTNT_TYPE.pBkmk = &rBookmark; + pDdeBookmark->SetRefObject(this); + } + else + OSL_ENSURE(false, + "SwServerObject::SetNoServer(..)" + " - setting an bookmark that is not DDE-capable"); +} + +/* */ + + +SwDataChanged::SwDataChanged( const SwPaM& rPam, sal_uInt16 nTyp ) + : pPam( &rPam ), pPos( 0 ), pDoc( rPam.GetDoc() ), nType( nTyp ) +{ + nNode = rPam.GetPoint()->nNode.GetIndex(); + nCntnt = rPam.GetPoint()->nContent.GetIndex(); +} + + +SwDataChanged::SwDataChanged( SwDoc* pDc, const SwPosition& rPos, sal_uInt16 nTyp ) + : pPam( 0 ), pPos( &rPos ), pDoc( pDc ), nType( nTyp ) +{ + nNode = rPos.nNode.GetIndex(); + nCntnt = rPos.nContent.GetIndex(); +} + +SwDataChanged::~SwDataChanged() +{ + // JP 09.04.96: nur wenn das Layout vorhanden ist ( also waehrend der + // Eingabe) + if( pDoc->GetRootFrm() ) + { + const ::sfx2::SvLinkSources& rServers = pDoc->GetLinkManager().GetServers(); + + for( sal_uInt16 nCnt = rServers.Count(); nCnt; ) + { + ::sfx2::SvLinkSourceRef refObj( rServers[ --nCnt ] ); + // noch jemand am Object interessiert ? + if( refObj->HasDataLinks() && refObj->ISA( SwServerObject )) + { + SwServerObject& rObj = *(SwServerObject*)&refObj; + if( pPos ) + rObj.SendDataChanged( *pPos ); + else + rObj.SendDataChanged( *pPam ); + } + + // sollte jetzt gar keine Verbindung mehr bestehen + if( !refObj->HasDataLinks() ) + { + // dann raus aus der Liste (Object bleibt aber bestehen!) + // falls es noch da ist !! + if( nCnt < rServers.Count() && &refObj == rServers[ nCnt ] ) + pDoc->GetLinkManager().RemoveServer( nCnt, 1 ); + } + } + } +} diff --git a/sw/source/core/doc/swstylemanager.cxx b/sw/source/core/doc/swstylemanager.cxx new file mode 100644 index 000000000000..ea8ba9366c75 --- /dev/null +++ b/sw/source/core/doc/swstylemanager.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include "swstylemanager.hxx" +#include <hash_map> +#include <svl/stylepool.hxx> +#include <doc.hxx> +#include <charfmt.hxx> +#include <docary.hxx> +#include <swtypes.hxx> +#include <istyleaccess.hxx> + +typedef ::std::hash_map< const ::rtl::OUString, + StylePool::SfxItemSet_Pointer_t, + ::rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > > SwStyleNameCache; + +class SwStyleCache +{ + SwStyleNameCache mMap; +public: + SwStyleCache() {} + void addStyleName( StylePool::SfxItemSet_Pointer_t pStyle ) + { mMap[ StylePool::nameOf(pStyle) ] = pStyle; } + void addCompletePool( StylePool& rPool ); + StylePool::SfxItemSet_Pointer_t getByName( const rtl::OUString& rName ) { return mMap[rName]; } +}; + +void SwStyleCache::addCompletePool( StylePool& rPool ) +{ + IStylePoolIteratorAccess *pIter = rPool.createIterator(); + StylePool::SfxItemSet_Pointer_t pStyle = pIter->getNext(); + while( pStyle.get() ) + { + rtl::OUString aName( StylePool::nameOf(pStyle) ); + mMap[ aName ] = pStyle; + pStyle = pIter->getNext(); + } + delete pIter; +} + +class SwStyleManager : public IStyleAccess +{ + StylePool aAutoCharPool; + StylePool aAutoParaPool; + SwStyleCache *mpCharCache; + SwStyleCache *mpParaCache; + +public: + // --> OD 2008-03-07 #refactorlists# + // accept empty item set for ignorable paragraph items. + SwStyleManager( SfxItemSet* pIgnorableParagraphItems ) + : aAutoCharPool(), + aAutoParaPool( pIgnorableParagraphItems ), + mpCharCache(0), + mpParaCache(0) + {} + // <-- + virtual ~SwStyleManager(); + virtual StylePool::SfxItemSet_Pointer_t getAutomaticStyle( const SfxItemSet& rSet, + IStyleAccess::SwAutoStyleFamily eFamily ); + virtual StylePool::SfxItemSet_Pointer_t getByName( const rtl::OUString& rName, + IStyleAccess::SwAutoStyleFamily eFamily ); + virtual void getAllStyles( std::vector<StylePool::SfxItemSet_Pointer_t> &rStyles, + IStyleAccess::SwAutoStyleFamily eFamily ); + virtual StylePool::SfxItemSet_Pointer_t cacheAutomaticStyle( const SfxItemSet& rSet, + SwAutoStyleFamily eFamily ); + virtual void clearCaches(); +}; + +IStyleAccess *createStyleManager( SfxItemSet* pIgnorableParagraphItems ) +{ + return new SwStyleManager( pIgnorableParagraphItems ); +} + +SwStyleManager::~SwStyleManager() +{ + delete mpCharCache; + delete mpParaCache; +} + +void SwStyleManager::clearCaches() +{ + delete mpCharCache; + mpCharCache = 0; + delete mpParaCache; + mpParaCache = 0; +} + +StylePool::SfxItemSet_Pointer_t SwStyleManager::getAutomaticStyle( const SfxItemSet& rSet, + IStyleAccess::SwAutoStyleFamily eFamily ) +{ + StylePool& rAutoPool = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? aAutoCharPool : aAutoParaPool; + return rAutoPool.insertItemSet( rSet ); +} + +StylePool::SfxItemSet_Pointer_t SwStyleManager::cacheAutomaticStyle( const SfxItemSet& rSet, + IStyleAccess::SwAutoStyleFamily eFamily ) +{ + StylePool& rAutoPool = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? aAutoCharPool : aAutoParaPool; + StylePool::SfxItemSet_Pointer_t pStyle = rAutoPool.insertItemSet( rSet ); + SwStyleCache* &rpCache = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? + mpCharCache : mpParaCache; + if( !rpCache ) + rpCache = new SwStyleCache(); + rpCache->addStyleName( pStyle ); + return pStyle; +} + +StylePool::SfxItemSet_Pointer_t SwStyleManager::getByName( const rtl::OUString& rName, + IStyleAccess::SwAutoStyleFamily eFamily ) +{ + StylePool& rAutoPool = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? aAutoCharPool : aAutoParaPool; + SwStyleCache* &rpCache = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? mpCharCache : mpParaCache; + if( !rpCache ) + rpCache = new SwStyleCache(); + StylePool::SfxItemSet_Pointer_t pStyle = rpCache->getByName( rName ); + if( !pStyle.get() ) + { + // Ok, ok, it's allowed to ask for uncached styles (from UNO) but it should not be done + // during loading a document + ASSERT( false, "Don't ask for uncached styles" ); + rpCache->addCompletePool( rAutoPool ); + pStyle = rpCache->getByName( rName ); + } + return pStyle; +} + +void SwStyleManager::getAllStyles( std::vector<StylePool::SfxItemSet_Pointer_t> &rStyles, + IStyleAccess::SwAutoStyleFamily eFamily ) +{ + StylePool& rAutoPool = eFamily == IStyleAccess::AUTO_STYLE_CHAR ? aAutoCharPool : aAutoParaPool; + // --> OD 2008-03-07 #refactorlists# + // setup <StylePool> iterator, which skips unused styles and ignorable items + IStylePoolIteratorAccess *pIter = rAutoPool.createIterator( true, true ); + // <-- + StylePool::SfxItemSet_Pointer_t pStyle = pIter->getNext(); + while( pStyle.get() ) + { + rStyles.push_back( pStyle ); + + pStyle = pIter->getNext(); + } + delete pIter; +} diff --git a/sw/source/core/doc/swstylemanager.hxx b/sw/source/core/doc/swstylemanager.hxx new file mode 100644 index 000000000000..4997ce5c0770 --- /dev/null +++ b/sw/source/core/doc/swstylemanager.hxx @@ -0,0 +1,38 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SWSTYLEMANAGER_HXX +#define _SWSTYLEMANAGER_HXX + +class IStyleAccess; +// --> OD 2008-03-07 #refactorlists# +class SfxItemSet; +// <-- + +// --> OD 2008-03-07 #refactorlists# +IStyleAccess *createStyleManager( SfxItemSet* pIgnorableParagraphItems = 0 ); +// <-- +#endif //_SWSTYLEMANAGER_HXX diff --git a/sw/source/core/doc/tblafmt.cxx b/sw/source/core/doc/tblafmt.cxx new file mode 100755 index 000000000000..3d4a21584f9a --- /dev/null +++ b/sw/source/core/doc/tblafmt.cxx @@ -0,0 +1,1106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <tools/resid.hxx> +#include <tools/stream.hxx> +#include <tools/shl.hxx> +#include <vcl/svapp.hxx> +#include <sfx2/docfile.hxx> +#include <svl/urihelper.hxx> +#include <svl/zforlist.hxx> +#include <svl/zformat.hxx> +#include <unotools/pathoptions.hxx> +#include <sfx2/app.hxx> +#include <svx/dialmgr.hxx> +#ifndef _SVX_DIALOGS_HRC +#include <svx/dialogs.hrc> +#endif + +#define READ_OLDVERS // erstmal noch alte Versionen lesen +#include <swtypes.hxx> +#include <doc.hxx> +#include <poolfmt.hxx> +#include <tblafmt.hxx> +#include <cellatr.hxx> +#include <SwStyleNameMapper.hxx> + +// bis SO5PF +const sal_uInt16 AUTOFORMAT_ID_X = 9501; +const sal_uInt16 AUTOFORMAT_ID_358 = 9601; +const sal_uInt16 AUTOFORMAT_DATA_ID_X = 9502; + +// ab SO5 +//! in nachfolgenden Versionen muss der Betrag dieser IDs groesser sein +const sal_uInt16 AUTOFORMAT_ID_504 = 9801; +const sal_uInt16 AUTOFORMAT_DATA_ID_504 = 9802; + +const sal_uInt16 AUTOFORMAT_ID_552 = 9901; +const sal_uInt16 AUTOFORMAT_DATA_ID_552 = 9902; + +// --- from 641 on: CJK and CTL font settings +const sal_uInt16 AUTOFORMAT_ID_641 = 10001; +const sal_uInt16 AUTOFORMAT_DATA_ID_641 = 10002; + +// --- from 680/dr14 on: diagonal frame lines +const sal_uInt16 AUTOFORMAT_ID_680DR14 = 10011; +const sal_uInt16 AUTOFORMAT_DATA_ID_680DR14 = 10012; + +// --- from 680/dr25 on: #21549# store strings as UTF-8 +const sal_uInt16 AUTOFORMAT_ID_680DR25 = 10021; +const sal_uInt16 AUTOFORMAT_DATA_ID_680DR25 = 10022; + +// --- from DEV300/overline2 on: #5991# overline +const sal_uInt16 AUTOFORMAT_ID_300OVRLN = 10031; +const sal_uInt16 AUTOFORMAT_DATA_ID_300OVRLN = 10032; + +// current version +const sal_uInt16 AUTOFORMAT_ID = AUTOFORMAT_ID_300OVRLN; +const sal_uInt16 AUTOFORMAT_DATA_ID = AUTOFORMAT_DATA_ID_300OVRLN; + + +#ifdef READ_OLDVERS +const sal_uInt16 AUTOFORMAT_OLD_ID = 8201; +const sal_uInt16 AUTOFORMAT_OLD_ID1 = 8301; +const sal_uInt16 AUTOFORMAT_OLD_DATA_ID = 8202; +#endif + + +SwBoxAutoFmt* SwTableAutoFmt::pDfltBoxAutoFmt = 0; + +#define sAutoTblFmtName "autotbl.fmt" + +// SwTable Auto-Format-Tabelle +SV_IMPL_PTRARR( _SwTableAutoFmtTbl, SwTableAutoFmt* ) + + +// Struct mit Versionsnummern der Items + +struct SwAfVersions +{ +public: + sal_uInt16 nFontVersion; + sal_uInt16 nFontHeightVersion; + sal_uInt16 nWeightVersion; + sal_uInt16 nPostureVersion; + sal_uInt16 nUnderlineVersion; + sal_uInt16 nOverlineVersion; + sal_uInt16 nCrossedOutVersion; + sal_uInt16 nContourVersion; + sal_uInt16 nShadowedVersion; + sal_uInt16 nColorVersion; + sal_uInt16 nBoxVersion; + sal_uInt16 nLineVersion; + sal_uInt16 nBrushVersion; + + sal_uInt16 nAdjustVersion; + + sal_uInt16 nHorJustifyVersion; + sal_uInt16 nVerJustifyVersion; + sal_uInt16 nOrientationVersion; + sal_uInt16 nMarginVersion; + sal_uInt16 nBoolVersion; + sal_uInt16 nInt32Version; + sal_uInt16 nRotateModeVersion; + + sal_uInt16 nNumFmtVersion; + + SwAfVersions(); + void Load( SvStream& rStream, sal_uInt16 nVer ); +}; + +SwAfVersions::SwAfVersions() : + nFontVersion(0), + nFontHeightVersion(0), + nWeightVersion(0), + nPostureVersion(0), + nUnderlineVersion(0), + nOverlineVersion(0), + nCrossedOutVersion(0), + nContourVersion(0), + nShadowedVersion(0), + nColorVersion(0), + nBoxVersion(0), + nLineVersion(0), + nBrushVersion(0), + nAdjustVersion(0), + nHorJustifyVersion(0), + nVerJustifyVersion(0), + nOrientationVersion(0), + nMarginVersion(0), + nBoolVersion(0), + nInt32Version(0), + nRotateModeVersion(0), + nNumFmtVersion(0) +{ +} + +void SwAfVersions::Load( SvStream& rStream, sal_uInt16 nVer ) +{ + rStream >> nFontVersion; + rStream >> nFontHeightVersion; + rStream >> nWeightVersion; + rStream >> nPostureVersion; + rStream >> nUnderlineVersion; + if ( nVer >= AUTOFORMAT_ID_300OVRLN ) + rStream >> nOverlineVersion; + rStream >> nCrossedOutVersion; + rStream >> nContourVersion; + rStream >> nShadowedVersion; + rStream >> nColorVersion; + rStream >> nBoxVersion; + if ( nVer >= AUTOFORMAT_ID_680DR14 ) + rStream >> nLineVersion; + rStream >> nBrushVersion; + rStream >> nAdjustVersion; + rStream >> nHorJustifyVersion; + rStream >> nVerJustifyVersion; + rStream >> nOrientationVersion; + rStream >> nMarginVersion; + rStream >> nBoolVersion; + if ( nVer >= AUTOFORMAT_ID_504 ) + { + rStream >> nInt32Version; + rStream >> nRotateModeVersion; + } + rStream >> nNumFmtVersion; +} + +// --------------------------------------------------------------------------- + +SwBoxAutoFmt::SwBoxAutoFmt() + : aFont( *(SvxFontItem*)GetDfltAttr( RES_CHRATR_FONT ) ), + aHeight( 240, 100, RES_CHRATR_FONTSIZE ), + aWeight( WEIGHT_NORMAL, RES_CHRATR_WEIGHT ), + aPosture( ITALIC_NONE, RES_CHRATR_POSTURE ), + + aCJKFont( *(SvxFontItem*)GetDfltAttr( RES_CHRATR_CJK_FONT ) ), + aCJKHeight( 240, 100, RES_CHRATR_CJK_FONTSIZE ), + aCJKWeight( WEIGHT_NORMAL, RES_CHRATR_CJK_WEIGHT ), + aCJKPosture( ITALIC_NONE, RES_CHRATR_CJK_POSTURE ), + + aCTLFont( *(SvxFontItem*)GetDfltAttr( RES_CHRATR_CTL_FONT ) ), + aCTLHeight( 240, 100, RES_CHRATR_CTL_FONTSIZE ), + aCTLWeight( WEIGHT_NORMAL, RES_CHRATR_CTL_WEIGHT ), + aCTLPosture( ITALIC_NONE, RES_CHRATR_CTL_POSTURE ), + + aUnderline( UNDERLINE_NONE, RES_CHRATR_UNDERLINE ), + aOverline( UNDERLINE_NONE, RES_CHRATR_OVERLINE ), + aCrossedOut( STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ), + aContour( sal_False, RES_CHRATR_CONTOUR ), + aShadowed( sal_False, RES_CHRATR_SHADOWED ), + aColor( RES_CHRATR_COLOR ), + aBox( RES_BOX ), + aTLBR( 0 ), + aBLTR( 0 ), + aBackground( RES_BACKGROUND ), + aAdjust( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ), + aHorJustify( SVX_HOR_JUSTIFY_STANDARD, 0), + aVerJustify( SVX_VER_JUSTIFY_STANDARD, 0), + aStacked( 0 ), + aMargin( 0 ), + aLinebreak( 0 ), + aRotateAngle( 0 ), + +// FIXME - add attribute IDs for the diagonal line items +// aTLBR( RES_... ), +// aBLTR( RES_... ), + aRotateMode( SVX_ROTATE_MODE_STANDARD, 0 ) +{ + eSysLanguage = eNumFmtLanguage = static_cast<LanguageType>(::GetAppLanguage()); + aBox.SetDistance( 55 ); +} + + +SwBoxAutoFmt::SwBoxAutoFmt( const SwBoxAutoFmt& rNew ) + : aFont( rNew.aFont ), + aHeight( rNew.aHeight ), + aWeight( rNew.aWeight ), + aPosture( rNew.aPosture ), + aCJKFont( rNew.aCJKFont ), + aCJKHeight( rNew.aCJKHeight ), + aCJKWeight( rNew.aCJKWeight ), + aCJKPosture( rNew.aCJKPosture ), + aCTLFont( rNew.aCTLFont ), + aCTLHeight( rNew.aCTLHeight ), + aCTLWeight( rNew.aCTLWeight ), + aCTLPosture( rNew.aCTLPosture ), + aUnderline( rNew.aUnderline ), + aOverline( rNew.aOverline ), + aCrossedOut( rNew.aCrossedOut ), + aContour( rNew.aContour ), + aShadowed( rNew.aShadowed ), + aColor( rNew.aColor ), + aBox( rNew.aBox ), + aTLBR( rNew.aTLBR ), + aBLTR( rNew.aBLTR ), + aBackground( rNew.aBackground ), + aAdjust( rNew.aAdjust ), + aHorJustify( rNew.aHorJustify ), + aVerJustify( rNew.aVerJustify ), + aStacked( rNew.aStacked ), + aMargin( rNew.aMargin ), + aLinebreak( rNew.aLinebreak ), + aRotateAngle( rNew.aRotateAngle ), + aRotateMode( rNew.aRotateMode ), + sNumFmtString( rNew.sNumFmtString ), + eSysLanguage( rNew.eSysLanguage ), + eNumFmtLanguage( rNew.eNumFmtLanguage ) +{ +} + + +SwBoxAutoFmt::~SwBoxAutoFmt() +{ +} + +SwBoxAutoFmt& SwBoxAutoFmt::operator=( const SwBoxAutoFmt& rNew ) +{ + aFont = rNew.aFont; + aHeight = rNew.aHeight; + aWeight = rNew.aWeight; + aPosture = rNew.aPosture; + aCJKFont = rNew.aCJKFont; + aCJKHeight = rNew.aCJKHeight; + aCJKWeight = rNew.aCJKWeight; + aCJKPosture = rNew.aCJKPosture; + aCTLFont = rNew.aCTLFont; + aCTLHeight = rNew.aCTLHeight; + aCTLWeight = rNew.aCTLWeight; + aCTLPosture = rNew.aCTLPosture; + aUnderline = rNew.aUnderline; + aOverline = rNew.aOverline; + aCrossedOut = rNew.aCrossedOut; + aContour = rNew.aContour; + aShadowed = rNew.aShadowed; + aColor = rNew.aColor; + SetAdjust( rNew.aAdjust ); + aBox = rNew.aBox; + aTLBR = rNew.aTLBR; + aBLTR = rNew.aBLTR; + aBackground = rNew.aBackground; + + aHorJustify = rNew.aHorJustify; + aVerJustify = rNew.aVerJustify; + aStacked.SetValue( rNew.aStacked.GetValue() ); + aMargin = rNew.aMargin; + aLinebreak.SetValue( rNew.aLinebreak.GetValue() ); + aRotateAngle.SetValue( rNew.aRotateAngle.GetValue() ); + aRotateMode.SetValue( rNew.aRotateMode.GetValue() ); + + sNumFmtString = rNew.sNumFmtString; + eSysLanguage = rNew.eSysLanguage; + eNumFmtLanguage = rNew.eNumFmtLanguage; + + return *this; +} + + +#define READ( aItem, aItemType, nVers )\ + pNew = aItem.Create(rStream, nVers ); \ + aItem = *(aItemType*)pNew; \ + delete pNew; + +sal_Bool SwBoxAutoFmt::Load( SvStream& rStream, const SwAfVersions& rVersions, sal_uInt16 nVer ) +{ + SfxPoolItem* pNew; + SvxOrientationItem aOrientation( SVX_ORIENTATION_STANDARD, 0); + + READ( aFont, SvxFontItem , rVersions.nFontVersion) + + if( rStream.GetStreamCharSet() == aFont.GetCharSet() ) + aFont.SetCharSet(::gsl_getSystemTextEncoding()); + + READ( aHeight, SvxFontHeightItem , rVersions.nFontHeightVersion) + READ( aWeight, SvxWeightItem , rVersions.nWeightVersion) + READ( aPosture, SvxPostureItem , rVersions.nPostureVersion) + // --- from 641 on: CJK and CTL font settings + if( AUTOFORMAT_DATA_ID_641 <= nVer ) + { + READ( aCJKFont, SvxFontItem , rVersions.nFontVersion) + READ( aCJKHeight, SvxFontHeightItem , rVersions.nFontHeightVersion) + READ( aCJKWeight, SvxWeightItem , rVersions.nWeightVersion) + READ( aCJKPosture, SvxPostureItem , rVersions.nPostureVersion) + READ( aCTLFont, SvxFontItem , rVersions.nFontVersion) + READ( aCTLHeight, SvxFontHeightItem , rVersions.nFontHeightVersion) + READ( aCTLWeight, SvxWeightItem , rVersions.nWeightVersion) + READ( aCTLPosture, SvxPostureItem , rVersions.nPostureVersion) + } + READ( aUnderline, SvxUnderlineItem , rVersions.nUnderlineVersion) + if( nVer >= AUTOFORMAT_DATA_ID_300OVRLN ) + { + READ( aOverline, SvxOverlineItem , rVersions.nOverlineVersion) + } + READ( aCrossedOut, SvxCrossedOutItem , rVersions.nCrossedOutVersion) + READ( aContour, SvxContourItem , rVersions.nContourVersion) + READ( aShadowed, SvxShadowedItem , rVersions.nShadowedVersion) + READ( aColor, SvxColorItem , rVersions.nColorVersion) + + READ( aBox, SvxBoxItem , rVersions.nBoxVersion) + + // --- from 680/dr14 on: diagonal frame lines + if( nVer >= AUTOFORMAT_DATA_ID_680DR14 ) + { + READ( aTLBR, SvxLineItem, rVersions.nLineVersion) + READ( aBLTR, SvxLineItem, rVersions.nLineVersion) + } + + READ( aBackground, SvxBrushItem , rVersions.nBrushVersion) + + pNew = aAdjust.Create(rStream, rVersions.nAdjustVersion ); + SetAdjust( *(SvxAdjustItem*)pNew ); + delete pNew; + + READ( aHorJustify, SvxHorJustifyItem , rVersions.nHorJustifyVersion) + READ( aVerJustify, SvxVerJustifyItem , rVersions.nVerJustifyVersion) + READ( aOrientation, SvxOrientationItem , rVersions.nOrientationVersion) + READ( aMargin, SvxMarginItem , rVersions.nMarginVersion) + + pNew = aLinebreak.Create(rStream, rVersions.nBoolVersion ); + aLinebreak.SetValue( ((SfxBoolItem*)pNew)->GetValue() ); + delete pNew; + + if ( nVer >= AUTOFORMAT_DATA_ID_504 ) + { + pNew = aRotateAngle.Create( rStream, rVersions.nInt32Version ); + aRotateAngle.SetValue( ((SfxInt32Item*)pNew)->GetValue() ); + delete pNew; + pNew = aRotateMode.Create( rStream, rVersions.nRotateModeVersion ); + aRotateMode.SetValue( ((SvxRotateModeItem*)pNew)->GetValue() ); + delete pNew; + } + + if( 0 == rVersions.nNumFmtVersion ) + { + sal_uInt16 eSys, eLge; + // --- from 680/dr25 on: #21549# store strings as UTF-8 + CharSet eCharSet = (nVer >= AUTOFORMAT_ID_680DR25) ? RTL_TEXTENCODING_UTF8 : rStream.GetStreamCharSet(); + rStream.ReadByteString( sNumFmtString, eCharSet ) + >> eSys >> eLge; + eSysLanguage = (LanguageType) eSys; + eNumFmtLanguage = (LanguageType) eLge; + if ( eSysLanguage == LANGUAGE_SYSTEM ) // von alten Versionen (Calc) + eSysLanguage = static_cast<LanguageType>(::GetAppLanguage()); + } + + aStacked.SetValue( aOrientation.IsStacked() ); + aRotateAngle.SetValue( aOrientation.GetRotation( aRotateAngle.GetValue() ) ); + + return 0 == rStream.GetError(); +} + +#ifdef READ_OLDVERS + +sal_Bool SwBoxAutoFmt::LoadOld( SvStream& rStream, sal_uInt16 aLoadVer[] ) +{ + SfxPoolItem* pNew; + READ( aFont, SvxFontItem , 0) + + if( rStream.GetStreamCharSet() == aFont.GetCharSet() ) + aFont.SetCharSet(::gsl_getSystemTextEncoding()); + + READ( aHeight, SvxFontHeightItem , 1) + READ( aWeight, SvxWeightItem , 2) + READ( aPosture, SvxPostureItem , 3) + READ( aUnderline, SvxUnderlineItem , 4) + READ( aCrossedOut, SvxCrossedOutItem , 5) + READ( aContour, SvxContourItem , 6) + READ( aShadowed, SvxShadowedItem , 7) + READ( aColor, SvxColorItem , 8) + + pNew = aAdjust.Create(rStream, aLoadVer[ 9 ] ); + SetAdjust( *(SvxAdjustItem*)pNew ); + delete pNew; + + READ( aBox, SvxBoxItem , 10) + READ( aBackground, SvxBrushItem , 11) + + return 0 == rStream.GetError(); +} + +#endif + + +sal_Bool SwBoxAutoFmt::Save( SvStream& rStream ) const +{ + SvxOrientationItem aOrientation( aRotateAngle.GetValue(), aStacked.GetValue(), 0 ); + + aFont.Store( rStream, aFont.GetVersion(SOFFICE_FILEFORMAT_40) ); + aHeight.Store( rStream, aHeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aWeight.Store( rStream, aWeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aPosture.Store( rStream, aPosture.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCJKFont.Store( rStream, aCJKFont.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCJKHeight.Store( rStream, aCJKHeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCJKWeight.Store( rStream, aCJKWeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCJKPosture.Store( rStream, aCJKPosture.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCTLFont.Store( rStream, aCTLFont.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCTLHeight.Store( rStream, aCTLHeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCTLWeight.Store( rStream, aCTLWeight.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCTLPosture.Store( rStream, aCTLPosture.GetVersion(SOFFICE_FILEFORMAT_40) ); + aUnderline.Store( rStream, aUnderline.GetVersion(SOFFICE_FILEFORMAT_40) ); + aOverline.Store( rStream, aOverline.GetVersion(SOFFICE_FILEFORMAT_40) ); + aCrossedOut.Store( rStream, aCrossedOut.GetVersion(SOFFICE_FILEFORMAT_40) ); + aContour.Store( rStream, aContour.GetVersion(SOFFICE_FILEFORMAT_40) ); + aShadowed.Store( rStream, aShadowed.GetVersion(SOFFICE_FILEFORMAT_40) ); + aColor.Store( rStream, aColor.GetVersion(SOFFICE_FILEFORMAT_40) ); + aBox.Store( rStream, aBox.GetVersion(SOFFICE_FILEFORMAT_40) ); + aTLBR.Store( rStream, aTLBR.GetVersion(SOFFICE_FILEFORMAT_40) ); + aBLTR.Store( rStream, aBLTR.GetVersion(SOFFICE_FILEFORMAT_40) ); + aBackground.Store( rStream, aBackground.GetVersion(SOFFICE_FILEFORMAT_40) ); + + aAdjust.Store( rStream, aAdjust.GetVersion(SOFFICE_FILEFORMAT_40) ); + + aHorJustify.Store( rStream, aHorJustify.GetVersion(SOFFICE_FILEFORMAT_40) ); + aVerJustify.Store( rStream, aVerJustify.GetVersion(SOFFICE_FILEFORMAT_40) ); + aOrientation.Store( rStream, aOrientation.GetVersion(SOFFICE_FILEFORMAT_40) ); + aMargin.Store( rStream, aMargin.GetVersion(SOFFICE_FILEFORMAT_40) ); + aLinebreak.Store( rStream, aLinebreak.GetVersion(SOFFICE_FILEFORMAT_40) ); + // Calc Rotation ab SO5 + aRotateAngle.Store( rStream, aRotateAngle.GetVersion(SOFFICE_FILEFORMAT_40) ); + aRotateMode.Store( rStream, aRotateMode.GetVersion(SOFFICE_FILEFORMAT_40) ); + + // --- from 680/dr25 on: #21549# store strings as UTF-8 + rStream.WriteByteString( sNumFmtString, RTL_TEXTENCODING_UTF8 ) + << (sal_uInt16)eSysLanguage << (sal_uInt16)eNumFmtLanguage; + + return 0 == rStream.GetError(); +} + + +sal_Bool SwBoxAutoFmt::SaveVerionNo( SvStream& rStream ) const +{ + rStream << aFont.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aHeight.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aWeight.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aPosture.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aUnderline.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aOverline.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aCrossedOut.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aContour.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aShadowed.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aColor.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aBox.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aTLBR.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aBackground.GetVersion( SOFFICE_FILEFORMAT_40 ); + + rStream << aAdjust.GetVersion( SOFFICE_FILEFORMAT_40 ); + + rStream << aHorJustify.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aVerJustify.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << SvxOrientationItem(SVX_ORIENTATION_STANDARD, 0).GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aMargin.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aLinebreak.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aRotateAngle.GetVersion( SOFFICE_FILEFORMAT_40 ); + rStream << aRotateMode.GetVersion( SOFFICE_FILEFORMAT_40 ); + + rStream << (sal_uInt16)0; // NumberFormat + + return 0 == rStream.GetError(); +} + +/* */ + + +SwTableAutoFmt::SwTableAutoFmt( const String& rName ) + : aName( rName ), nStrResId( USHRT_MAX ) +{ + bInclFont = sal_True; + bInclJustify = sal_True; + bInclFrame = sal_True; + bInclBackground = sal_True; + bInclValueFormat = sal_True; + bInclWidthHeight = sal_True; + + memset( aBoxAutoFmt, 0, sizeof( aBoxAutoFmt ) ); +} + + +SwTableAutoFmt::SwTableAutoFmt( const SwTableAutoFmt& rNew ) +{ + for( sal_uInt8 n = 0; n < 16; ++n ) + aBoxAutoFmt[ n ] = 0; + *this = rNew; +} + +SwTableAutoFmt& SwTableAutoFmt::operator=( const SwTableAutoFmt& rNew ) +{ + for( sal_uInt8 n = 0; n < 16; ++n ) + { + if( aBoxAutoFmt[ n ] ) + delete aBoxAutoFmt[ n ]; + + SwBoxAutoFmt* pFmt = rNew.aBoxAutoFmt[ n ]; + if( pFmt ) // ist gesetzt -> kopieren + aBoxAutoFmt[ n ] = new SwBoxAutoFmt( *pFmt ); + else // sonst default + aBoxAutoFmt[ n ] = 0; + } + + aName = rNew.aName; + nStrResId = rNew.nStrResId; + bInclFont = rNew.bInclFont; + bInclJustify = rNew.bInclJustify; + bInclFrame = rNew.bInclFrame; + bInclBackground = rNew.bInclBackground; + bInclValueFormat = rNew.bInclValueFormat; + bInclWidthHeight = rNew.bInclWidthHeight; + + return *this; +} + + +SwTableAutoFmt::~SwTableAutoFmt() +{ + SwBoxAutoFmt** ppFmt = aBoxAutoFmt; + for( sal_uInt8 n = 0; n < 16; ++n, ++ppFmt ) + if( *ppFmt ) + delete *ppFmt; +} + + +void SwTableAutoFmt::SetBoxFmt( const SwBoxAutoFmt& rNew, sal_uInt8 nPos ) +{ + ASSERT( nPos < 16, "falscher Bereich" ); + + SwBoxAutoFmt* pFmt = aBoxAutoFmt[ nPos ]; + if( pFmt ) // ist gesetzt -> kopieren + *aBoxAutoFmt[ nPos ] = rNew; + else // sonst neu setzen + aBoxAutoFmt[ nPos ] = new SwBoxAutoFmt( rNew ); +} + + +const SwBoxAutoFmt& SwTableAutoFmt::GetBoxFmt( sal_uInt8 nPos ) const +{ + ASSERT( nPos < 16, "falscher Bereich" ); + + SwBoxAutoFmt* pFmt = aBoxAutoFmt[ nPos ]; + if( pFmt ) // ist gesetzt -> kopieren + return *pFmt; + else // sonst den default returnen + { + // falls noch nicht vorhanden: + if( !pDfltBoxAutoFmt ) + pDfltBoxAutoFmt = new SwBoxAutoFmt; + return *pDfltBoxAutoFmt; + } +} + + + +SwBoxAutoFmt& SwTableAutoFmt::UpdateFromSet( sal_uInt8 nPos, + const SfxItemSet& rSet, + UpdateFlags eFlags, + SvNumberFormatter* pNFmtr ) +{ + ASSERT( nPos < 16, "falscher Bereich" ); + + SwBoxAutoFmt* pFmt = aBoxAutoFmt[ nPos ]; + if( !pFmt ) // ist gesetzt -> kopieren + { + pFmt = new SwBoxAutoFmt; + aBoxAutoFmt[ nPos ] = pFmt; + } + + if( UPDATE_CHAR & eFlags ) + { + pFmt->SetFont( (SvxFontItem&)rSet.Get( RES_CHRATR_FONT ) ); + pFmt->SetHeight( (SvxFontHeightItem&)rSet.Get( RES_CHRATR_FONTSIZE ) ); + pFmt->SetWeight( (SvxWeightItem&)rSet.Get( RES_CHRATR_WEIGHT ) ); + pFmt->SetPosture( (SvxPostureItem&)rSet.Get( RES_CHRATR_POSTURE ) ); + pFmt->SetCJKFont( (SvxFontItem&)rSet.Get( RES_CHRATR_CJK_FONT ) ); + pFmt->SetCJKHeight( (SvxFontHeightItem&)rSet.Get( RES_CHRATR_CJK_FONTSIZE ) ); + pFmt->SetCJKWeight( (SvxWeightItem&)rSet.Get( RES_CHRATR_CJK_WEIGHT ) ); + pFmt->SetCJKPosture( (SvxPostureItem&)rSet.Get( RES_CHRATR_CJK_POSTURE ) ); + pFmt->SetCTLFont( (SvxFontItem&)rSet.Get( RES_CHRATR_CTL_FONT ) ); + pFmt->SetCTLHeight( (SvxFontHeightItem&)rSet.Get( RES_CHRATR_CTL_FONTSIZE ) ); + pFmt->SetCTLWeight( (SvxWeightItem&)rSet.Get( RES_CHRATR_CTL_WEIGHT ) ); + pFmt->SetCTLPosture( (SvxPostureItem&)rSet.Get( RES_CHRATR_CTL_POSTURE ) ); + pFmt->SetUnderline( (SvxUnderlineItem&)rSet.Get( RES_CHRATR_UNDERLINE ) ); + pFmt->SetOverline( (SvxOverlineItem&)rSet.Get( RES_CHRATR_OVERLINE ) ); + pFmt->SetCrossedOut( (SvxCrossedOutItem&)rSet.Get( RES_CHRATR_CROSSEDOUT ) ); + pFmt->SetContour( (SvxContourItem&)rSet.Get( RES_CHRATR_CONTOUR ) ); + pFmt->SetShadowed( (SvxShadowedItem&)rSet.Get( RES_CHRATR_SHADOWED ) ); + pFmt->SetColor( (SvxColorItem&)rSet.Get( RES_CHRATR_COLOR ) ); + pFmt->SetAdjust( (SvxAdjustItem&)rSet.Get( RES_PARATR_ADJUST ) ); + } + if( UPDATE_BOX & eFlags ) + { + pFmt->SetBox( (SvxBoxItem&)rSet.Get( RES_BOX ) ); +// FIXME - add attribute IDs for the diagonal line items +// pFmt->SetTLBR( (SvxLineItem&)rSet.Get( RES_... ) ); +// pFmt->SetBLTR( (SvxLineItem&)rSet.Get( RES_... ) ); + pFmt->SetBackground( (SvxBrushItem&)rSet.Get( RES_BACKGROUND ) ); + + const SwTblBoxNumFormat* pNumFmtItem; + const SvNumberformat* pNumFormat = 0; + if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_True, + (const SfxPoolItem**)&pNumFmtItem ) && pNFmtr && + 0 != (pNumFormat = pNFmtr->GetEntry( pNumFmtItem->GetValue() )) ) + pFmt->SetValueFormat( ((SvNumberformat*)pNumFormat)->GetFormatstring(), + pNumFormat->GetLanguage(), + static_cast<LanguageType>(::GetAppLanguage())); + else + { + // defaulten + pFmt->SetValueFormat( aEmptyStr, LANGUAGE_SYSTEM, + static_cast<LanguageType>(::GetAppLanguage() )); + } + } + // den Rest koennen wir nicht, StarCalc spezifisch + + return *pFmt; +} + + +void SwTableAutoFmt::UpdateToSet( sal_uInt8 nPos, SfxItemSet& rSet, + UpdateFlags eFlags, SvNumberFormatter* pNFmtr ) const +{ + const SwBoxAutoFmt& rChg = GetBoxFmt( nPos ); + + if( UPDATE_CHAR & eFlags ) + { + if( IsFont() ) + { + rSet.Put( rChg.GetFont() ); + rSet.Put( rChg.GetHeight() ); + rSet.Put( rChg.GetWeight() ); + rSet.Put( rChg.GetPosture() ); + // #103065# do not insert empty CJK font + const SvxFontItem& rCJKFont = rChg.GetCJKFont(); + if( rCJKFont.GetStyleName().Len() ) + { + rSet.Put( rChg.GetCJKFont() ); + rSet.Put( rChg.GetCJKHeight() ); + rSet.Put( rChg.GetCJKWeight() ); + rSet.Put( rChg.GetCJKPosture() ); + } + else + { + rSet.Put( rChg.GetHeight(), RES_CHRATR_CJK_FONTSIZE ); + rSet.Put( rChg.GetWeight(), RES_CHRATR_CJK_WEIGHT ); + rSet.Put( rChg.GetPosture(), RES_CHRATR_CJK_POSTURE ); + } + // #103065# do not insert empty CTL font + const SvxFontItem& rCTLFont = rChg.GetCTLFont(); + if( rCTLFont.GetStyleName().Len() ) + { + rSet.Put( rChg.GetCTLFont() ); + rSet.Put( rChg.GetCTLHeight() ); + rSet.Put( rChg.GetCTLWeight() ); + rSet.Put( rChg.GetCTLPosture() ); + } + else + { + rSet.Put( rChg.GetHeight(), RES_CHRATR_CTL_FONTSIZE ); + rSet.Put( rChg.GetWeight(), RES_CHRATR_CTL_WEIGHT ); + rSet.Put( rChg.GetPosture(), RES_CHRATR_CTL_POSTURE ); + } + rSet.Put( rChg.GetUnderline() ); + rSet.Put( rChg.GetOverline() ); + rSet.Put( rChg.GetCrossedOut() ); + rSet.Put( rChg.GetContour() ); + rSet.Put( rChg.GetShadowed() ); + rSet.Put( rChg.GetColor() ); + } + if( IsJustify() ) + rSet.Put( rChg.GetAdjust() ); + } + + if( UPDATE_BOX & eFlags ) + { + if( IsFrame() ) + { + rSet.Put( rChg.GetBox() ); +// FIXME - uncomment the lines to put the diagonal line items +// rSet.Put( rChg.GetTLBR() ); +// rSet.Put( rChg.GetBLTR() ); + } + if( IsBackground() ) + rSet.Put( rChg.GetBackground() ); + + if( IsValueFormat() && pNFmtr ) + { + String sFmt; LanguageType eLng, eSys; + rChg.GetValueFormat( sFmt, eLng, eSys ); + if( sFmt.Len() ) + { + short nType; + sal_Bool bNew; + xub_StrLen nCheckPos; + sal_uInt32 nKey = pNFmtr->GetIndexPuttingAndConverting( sFmt, eLng, + eSys, nType, bNew, nCheckPos); + rSet.Put( SwTblBoxNumFormat( nKey )); + } + else + rSet.ClearItem( RES_BOXATR_FORMAT ); + } + } + + // den Rest koennen wir nicht, StarCalc spezifisch +} + + +sal_Bool SwTableAutoFmt::Load( SvStream& rStream, const SwAfVersions& rVersions ) +{ + sal_Bool bRet = sal_True; + sal_uInt16 nVal = 0; + rStream >> nVal; + bRet = 0 == rStream.GetError(); + + if( bRet && (nVal == AUTOFORMAT_DATA_ID_X || + (AUTOFORMAT_DATA_ID_504 <= nVal && nVal <= AUTOFORMAT_DATA_ID)) ) + { + sal_Bool b; + // --- from 680/dr25 on: #21549# store strings as UTF-8 + CharSet eCharSet = (nVal >= AUTOFORMAT_ID_680DR25) ? RTL_TEXTENCODING_UTF8 : rStream.GetStreamCharSet(); + rStream.ReadByteString( aName, eCharSet ); + if( AUTOFORMAT_DATA_ID_552 <= nVal ) + { + rStream >> nStrResId; + sal_uInt16 nId = RID_SVXSTR_TBLAFMT_BEGIN + nStrResId; + if( RID_SVXSTR_TBLAFMT_BEGIN <= nId && + nId < RID_SVXSTR_TBLAFMT_END ) + { + aName = SVX_RESSTR( nId ); + } + else + nStrResId = USHRT_MAX; + } + rStream >> b; bInclFont = b; + rStream >> b; bInclJustify = b; + rStream >> b; bInclFrame = b; + rStream >> b; bInclBackground = b; + rStream >> b; bInclValueFormat = b; + rStream >> b; bInclWidthHeight = b; + + bRet = 0 == rStream.GetError(); + + for( sal_uInt8 i = 0; i < 16; ++i ) + { + SwBoxAutoFmt* pFmt = new SwBoxAutoFmt; + bRet = pFmt->Load( rStream, rVersions, nVal ); + if( bRet ) + aBoxAutoFmt[ i ] = pFmt; + else + { + delete pFmt; + break; + } + } + } + return bRet; +} + +#ifdef READ_OLDVERS + +sal_Bool SwTableAutoFmt::LoadOld( SvStream& rStream, sal_uInt16 aLoadVer[] ) +{ + sal_Bool bRet = sal_True; + sal_uInt16 nVal = 0; + rStream >> nVal; + bRet = 0 == rStream.GetError(); + + if( bRet && ( AUTOFORMAT_OLD_DATA_ID == nVal )) + { + sal_Bool b; + rStream.ReadByteString( aName, rStream.GetStreamCharSet() ); + rStream >> b; bInclFont = b; + rStream >> b; bInclJustify = b; + rStream >> b; bInclFrame = b; + rStream >> b; bInclBackground = b; + bRet = (rStream.GetError() == 0); + + for( int i = 0; i < 16; i++) + { + SwBoxAutoFmt* pFmt = new SwBoxAutoFmt; + bRet = pFmt->LoadOld( rStream, aLoadVer ); + if( bRet ) + aBoxAutoFmt[ i ] = pFmt; + else + { + delete pFmt; + break; + } + } + } + return bRet; +} +#endif + + +sal_Bool SwTableAutoFmt::Save( SvStream& rStream ) const +{ + sal_uInt16 nVal = AUTOFORMAT_DATA_ID; + sal_Bool b; + rStream << nVal; + // --- from 680/dr25 on: #21549# store strings as UTF-8 + rStream.WriteByteString( aName, RTL_TEXTENCODING_UTF8 ); + rStream << nStrResId; + rStream << ( b = bInclFont ); + rStream << ( b = bInclJustify ); + rStream << ( b = bInclFrame ); + rStream << ( b = bInclBackground ); + rStream << ( b = bInclValueFormat ); + rStream << ( b = bInclWidthHeight ); + + sal_Bool bRet = 0 == rStream.GetError(); + + for( int i = 0; bRet && i < 16; ++i ) + { + SwBoxAutoFmt* pFmt = aBoxAutoFmt[ i ]; + if( !pFmt ) // nicht gesetzt -> default schreiben + { + // falls noch nicht vorhanden: + if( !pDfltBoxAutoFmt ) + pDfltBoxAutoFmt = new SwBoxAutoFmt; + pFmt = pDfltBoxAutoFmt; + } + bRet = pFmt->Save( rStream ); + } + return bRet; +} + + +SwTableAutoFmtTbl::SwTableAutoFmtTbl() +{ + String sNm; + SwTableAutoFmt* pNew = new SwTableAutoFmt( + SwStyleNameMapper::GetUIName( RES_POOLCOLL_STANDARD, sNm ) ); + + SwBoxAutoFmt aNew; + + sal_uInt8 i; + + Color aColor( COL_BLUE ); + SvxBrushItem aBrushItem( aColor, RES_BACKGROUND ); + aNew.SetBackground( aBrushItem ); + aNew.SetColor( SvxColorItem(Color( COL_WHITE ), RES_CHRATR_COLOR) ); + + for( i = 0; i < 4; ++i ) + pNew->SetBoxFmt( aNew, i ); + + // 70% Grau + aBrushItem.SetColor( RGB_COLORDATA( 0x4d, 0x4d, 0x4d ) ); + aNew.SetBackground( aBrushItem ); + for( i = 4; i <= 12; i += 4 ) + pNew->SetBoxFmt( aNew, i ); + + // 20% Grau + aBrushItem.SetColor( RGB_COLORDATA( 0xcc, 0xcc, 0xcc ) ); + aNew.SetBackground( aBrushItem ); + aColor.SetColor( COL_BLACK ); + aNew.SetColor( SvxColorItem( aColor, RES_CHRATR_COLOR) ); + for( i = 7; i <= 15; i += 4 ) + pNew->SetBoxFmt( aNew, i ); + for( i = 13; i <= 14; ++i ) + pNew->SetBoxFmt( aNew, i ); + + aBrushItem.SetColor( Color( COL_WHITE ) ); + aNew.SetBackground( aBrushItem ); + for( i = 5; i <= 6; ++i ) + pNew->SetBoxFmt( aNew, i ); + for( i = 9; i <= 10; ++i ) + pNew->SetBoxFmt( aNew, i ); + + + SvxBoxItem aBox( RES_BOX ); + aBox.SetDistance( 55 ); + SvxBorderLine aLn( &aColor, DEF_LINE_WIDTH_0 ); + aBox.SetLine( &aLn, BOX_LINE_LEFT ); + aBox.SetLine( &aLn, BOX_LINE_BOTTOM ); + + for( i = 0; i <= 15; ++i ) + { + aBox.SetLine( i <= 3 ? &aLn : 0, BOX_LINE_TOP ); + aBox.SetLine( (3 == ( i & 3 )) ? &aLn : 0, BOX_LINE_RIGHT ); + ((SwBoxAutoFmt&)pNew->GetBoxFmt( i )).SetBox( aBox ); + } + + Insert( pNew, Count() ); +} + +sal_Bool SwTableAutoFmtTbl::Load() +{ + sal_Bool bRet = sal_False; + String sNm( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( sAutoTblFmtName ))); + SvtPathOptions aOpt; + if( aOpt.SearchFile( sNm, SvtPathOptions::PATH_USERCONFIG )) + { + SfxMedium aStream( sNm, STREAM_STD_READ, sal_True ); + bRet = Load( *aStream.GetInStream() ); + } + else + bRet = sal_False; + return bRet; +} + +sal_Bool SwTableAutoFmtTbl::Save() const +{ + SvtPathOptions aPathOpt; + String sNm( aPathOpt.GetUserConfigPath() ); + sNm += INET_PATH_TOKEN; + sNm.AppendAscii( RTL_CONSTASCII_STRINGPARAM( sAutoTblFmtName )); + SfxMedium aStream(sNm, STREAM_STD_WRITE, sal_True ); + return Save( *aStream.GetOutStream() ) && aStream.Commit(); +} + +sal_Bool SwTableAutoFmtTbl::Load( SvStream& rStream ) +{ + sal_Bool bRet = 0 == rStream.GetError(); + if (bRet) + { + // Achtung hier muss ein allgemeiner Header gelesen werden + sal_uInt16 nVal = 0; + rStream >> nVal; + bRet = 0 == rStream.GetError(); + + if( bRet ) + { + SwAfVersions aVersions; + + if( nVal == AUTOFORMAT_ID_358 || + (AUTOFORMAT_ID_504 <= nVal && nVal <= AUTOFORMAT_ID) ) + { + sal_uInt16 nFileVers = SOFFICE_FILEFORMAT_40; + sal_uInt8 nChrSet, nCnt; + long nPos = rStream.Tell(); + rStream >> nCnt >> nChrSet; +// if( 4 <= nCnt ) +// rStream >> nFileVers; + if( rStream.Tell() != sal_uLong(nPos + nCnt) ) + { + ASSERT( !this, "Der Header enthaelt mehr/neuere Daten" ); + rStream.Seek( nPos + nCnt ); + } + rStream.SetStreamCharSet( (CharSet)nChrSet ); + rStream.SetVersion( nFileVers ); + } + + if( nVal == AUTOFORMAT_ID_358 || nVal == AUTOFORMAT_ID_X || + (AUTOFORMAT_ID_504 <= nVal && nVal <= AUTOFORMAT_ID) ) + { + aVersions.Load( rStream, nVal ); // Item-Versionen + + SwTableAutoFmt* pNew; + sal_uInt16 nAnz = 0; + rStream >> nAnz; + + bRet = 0 == rStream.GetError(); + + for( sal_uInt16 i = 0; i < nAnz; ++i ) + { + pNew = new SwTableAutoFmt( aEmptyStr ); + bRet = pNew->Load( rStream, aVersions ); + if( bRet ) + { + Insert( pNew, Count() ); + } + else + { + delete pNew; + break; + } + } + } +#ifdef READ_OLDVERS + else if( AUTOFORMAT_OLD_ID == nVal || AUTOFORMAT_OLD_ID1 == nVal ) + { + SwTableAutoFmt* pNew; + sal_uInt16 nAnz = 0; + rStream >> nAnz; + + sal_uInt16 aArr[ 12 ]; + memset( aArr, 0, 12 * sizeof( sal_uInt16 ) ); + if( AUTOFORMAT_OLD_ID1 == nVal ) + for( sal_uInt16 n = 0; n < 12; ++n ) + rStream >> aArr[ n ]; + + bRet = 0 == rStream.GetError(); + + for( sal_uInt16 i = 0; i < nAnz; ++i ) + { + pNew = new SwTableAutoFmt( aEmptyStr ); + bRet = pNew->LoadOld( rStream, aArr ); + if( bRet ) + { + Insert( pNew, Count() ); + } + else + { + delete pNew; + break; + } + } + } +#endif + } + } + return bRet; +} + + +sal_Bool SwTableAutoFmtTbl::Save( SvStream& rStream ) const +{ + sal_Bool bRet = 0 == rStream.GetError(); + if (bRet) + { + rStream.SetVersion( SOFFICE_FILEFORMAT_40 ); + + // Achtung hier muss ein allgemeiner Header gespeichert werden + sal_uInt16 nVal = AUTOFORMAT_ID; + rStream << nVal + << (sal_uInt8)2 // Anzahl von Zeichen des Headers incl. diesem + << (sal_uInt8)GetStoreCharSet( ::gsl_getSystemTextEncoding() ); +// << (sal_uInt8)4 // Anzahl von Zeichen des Headers incl. diesem +// << (sal_uInt8)::GetSystemCharSet() +// << (UNIT16)SOFFICE_FILEFORMAT_NOW; + bRet = 0 == rStream.GetError(); + + //----------------------------------------------------------- + // die VersionsNummer fuer alle Attribute schreiben + (*this)[ 0 ]->GetBoxFmt( 0 ).SaveVerionNo( rStream ); + + rStream << (sal_uInt16)(Count() - 1); + bRet = 0 == rStream.GetError(); + + for( sal_uInt16 i = 1; bRet && i < Count(); ++i ) + { + SwTableAutoFmt* pFmt = (*this)[ i ]; + bRet = pFmt->Save( rStream ); + } + } + rStream.Flush(); + return bRet; +} + + + diff --git a/sw/source/core/doc/tblcpy.cxx b/sw/source/core/doc/tblcpy.cxx new file mode 100644 index 000000000000..51e1d455beb5 --- /dev/null +++ b/sw/source/core/doc/tblcpy.cxx @@ -0,0 +1,1099 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <hintids.hxx> + +#define _ZFORLIST_DECLARE_TABLE +#include <svl/zforlist.hxx> +#include <frmfmt.hxx> +#include <doc.hxx> +#include <IDocumentUndoRedo.hxx> +#include <cntfrm.hxx> +#include <pam.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <fldbas.hxx> +#include <tblsel.hxx> +#include <tabfrm.hxx> +#include <poolfmt.hxx> +#include <cellatr.hxx> +#include <mvsave.hxx> +#include <docary.hxx> +#include <fmtanchr.hxx> +#include <hints.hxx> +#include <UndoTable.hxx> +#include <redline.hxx> +#include <fmtfsize.hxx> +#include <list> + +sal_Bool _FndCntntLine( const SwTableLine*& rpLine, void* pPara ); +sal_Bool _FndCntntBox( const SwTableBox*& rpBox, void* pPara ); +void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox, + SwTable& rDstTbl, SwTableBox* pDstBox, + sal_Bool bDelCntnt, SwUndoTblCpyTbl* pUndo ); + +// The following type will be used by table copy functions to describe +// the structure of tables (or parts of tables). +// It's for new table model only. + +namespace +{ + struct BoxSpanInfo + { + SwTableBox* mpBox; + SwTableBox* mpCopy; + sal_uInt16 mnColSpan; + bool mbSelected; + }; + + typedef std::vector< BoxSpanInfo > BoxStructure; + typedef std::vector< BoxStructure > LineStructure; + typedef std::list< sal_uLong > ColumnStructure; + + struct SubBox + { + SwTableBox *mpBox; + bool mbCovered; + }; + + typedef std::list< SubBox > SubLine; + typedef std::list< SubLine > SubTable; + + class TableStructure + { + public: + LineStructure maLines; + ColumnStructure maCols; + sal_uInt16 mnStartCol; + sal_uInt16 mnAddLine; + void addLine( sal_uInt16 &rLine, const SwTableBoxes&, const SwSelBoxes*, + bool bNewModel ); + void addBox( sal_uInt16 nLine, const SwSelBoxes*, SwTableBox *pBox, + sal_uLong &rnB, sal_uInt16 &rnC, ColumnStructure::iterator& rpCl, + BoxStructure::iterator& rpSel, bool &rbSel, bool bCover ); + void incColSpan( sal_uInt16 nLine, sal_uInt16 nCol ); + TableStructure( const SwTable& rTable ); + TableStructure( const SwTable& rTable, _FndBox &rFndBox, + const SwSelBoxes& rSelBoxes, + LineStructure::size_type nMinSize ); + LineStructure::size_type getLineCount() const + { return maLines.size(); } + void moreLines( const SwTable& rTable ); + void assignBoxes( const TableStructure &rSource ); + void copyBoxes( const SwTable& rSource, SwTable& rDstTbl, + SwUndoTblCpyTbl* pUndo ) const; + }; + + SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine, + SubTable::iterator pStartLn ); + + SubTable::iterator insertSubBox( SubTable& rSubTable, SwTableBox& rBox, + SubTable::iterator pStartLn, SubTable::iterator pEndLn ) + { + if( rBox.GetTabLines().Count() ) + { + SubTable::difference_type nSize = std::distance( pStartLn, pEndLn ); + if( nSize < rBox.GetTabLines().Count() ) + { + SubLine aSubLine; + SubLine::iterator pBox = pStartLn->begin(); + SubLine::iterator pEnd = pStartLn->end(); + while( pBox != pEnd ) + { + SubBox aSub; + aSub.mpBox = pBox->mpBox; + aSub.mbCovered = true; + aSubLine.push_back( aSub ); + ++pBox; + } + do + { + rSubTable.insert( pEndLn, aSubLine ); + } while( ++nSize < rBox.GetTabLines().Count() ); + } + for( sal_uInt16 nLine = 0; nLine < rBox.GetTabLines().Count(); ++nLine ) + pStartLn = insertSubLine( rSubTable, *rBox.GetTabLines()[nLine], + pStartLn ); + ASSERT( pStartLn == pEndLn, "Sub line confusion" ); + } + else + { + SubBox aSub; + aSub.mpBox = &rBox; + aSub.mbCovered = false; + while( pStartLn != pEndLn ) + { + pStartLn->push_back( aSub ); + aSub.mbCovered = true; + ++pStartLn; + } + } + return pStartLn; + } + + SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine, + SubTable::iterator pStartLn ) + { + SubTable::iterator pMax = pStartLn; + ++pMax; + SubTable::difference_type nMax = 1; + for( sal_uInt16 nBox = 0; nBox < rLine.GetTabBoxes().Count(); ++nBox ) + { + SubTable::iterator pTmp = insertSubBox( rSubTable, + *rLine.GetTabBoxes()[nBox], pStartLn, pMax ); + SubTable::difference_type nTmp = std::distance( pStartLn, pTmp ); + if( nTmp > nMax ) + { + pMax = pTmp; + nMax = nTmp; + } + } + return pMax; + } + + TableStructure::TableStructure( const SwTable& rTable ) : + maLines( rTable.GetTabLines().Count() ), mnStartCol(USHRT_MAX), + mnAddLine(0) + { + maCols.push_front(0); + const SwTableLines &rLines = rTable.GetTabLines(); + sal_uInt16 nCnt = 0; + for( sal_uInt16 nLine = 0; nLine < rLines.Count(); ++nLine ) + addLine( nCnt, rLines[nLine]->GetTabBoxes(), 0, rTable.IsNewModel() ); + } + + TableStructure::TableStructure( const SwTable& rTable, + _FndBox &rFndBox, const SwSelBoxes& rSelBoxes, + LineStructure::size_type nMinSize ) + : mnStartCol(USHRT_MAX), mnAddLine(0) + { + if( rFndBox.GetLines().Count() ) + { + bool bNoSelection = rSelBoxes.Count() < 2; + _FndLines &rFndLines = rFndBox.GetLines(); + maCols.push_front(0); + const SwTableLine* pLine = rFndLines[0]->GetLine(); + sal_uInt16 nStartLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + sal_uInt16 nEndLn = nStartLn; + if( rFndLines.Count() > 1 ) + { + pLine = rFndLines[ rFndLines.Count()-1 ]->GetLine(); + nEndLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + } + if( nStartLn < USHRT_MAX && nEndLn < USHRT_MAX ) + { + const SwTableLines &rLines = rTable.GetTabLines(); + if( bNoSelection && + (sal_uInt16)nMinSize > nEndLn - nStartLn + 1 ) + { + sal_uInt16 nNewEndLn = nStartLn + (sal_uInt16)nMinSize - 1; + if( nNewEndLn >= rLines.Count() ) + { + mnAddLine = nNewEndLn - rLines.Count() + 1; + nNewEndLn = rLines.Count() - 1; + } + while( nEndLn < nNewEndLn ) + { + SwTableLine *pLine2 = rLines[ ++nEndLn ]; + SwTableBox *pTmpBox = pLine2->GetTabBoxes()[0]; + _FndLine *pInsLine = new _FndLine( pLine2, &rFndBox ); + _FndBox *pFndBox = new _FndBox( pTmpBox, pInsLine ); + pInsLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, 0 ); + rFndLines.C40_INSERT( _FndLine, pInsLine, rFndLines.Count() ); + } + } + maLines.resize( nEndLn - nStartLn + 1 ); + const SwSelBoxes* pSelBoxes = &rSelBoxes; + sal_uInt16 nCnt = 0; + for( sal_uInt16 nLine = nStartLn; nLine <= nEndLn; ++nLine ) + { + addLine( nCnt, rLines[nLine]->GetTabBoxes(), + pSelBoxes, rTable.IsNewModel() ); + if( bNoSelection ) + pSelBoxes = 0; + } + } + if( bNoSelection && mnStartCol < USHRT_MAX ) + { + BoxStructure::iterator pC = maLines[0].begin(); + BoxStructure::iterator pEnd = maLines[0].end(); + sal_uInt16 nIdx = mnStartCol; + mnStartCol = 0; + while( nIdx && pC != pEnd ) + { + mnStartCol = mnStartCol + pC->mnColSpan; + --nIdx; + ++pC; + } + } + else + mnStartCol = USHRT_MAX; + } + } + + void TableStructure::addLine( sal_uInt16 &rLine, const SwTableBoxes& rBoxes, + const SwSelBoxes* pSelBoxes, bool bNewModel ) + { + bool bComplex = false; + if( !bNewModel ) + for( sal_uInt16 nBox = 0; !bComplex && nBox < rBoxes.Count(); ++nBox ) + bComplex = rBoxes[nBox]->GetTabLines().Count() > 0; + if( bComplex ) + { + SubTable aSubTable; + SubLine aSubLine; + aSubTable.push_back( aSubLine ); + SubTable::iterator pStartLn = aSubTable.begin(); + SubTable::iterator pEndLn = aSubTable.end(); + for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox ) + insertSubBox( aSubTable, *rBoxes[nBox], pStartLn, pEndLn ); + SubTable::size_type nSize = aSubTable.size(); + if( nSize ) + { + maLines.resize( maLines.size() + nSize - 1 ); + while( pStartLn != pEndLn ) + { + bool bSelected = false; + sal_uLong nBorder = 0; + sal_uInt16 nCol = 0; + maLines[rLine].reserve( pStartLn->size() ); + BoxStructure::iterator pSel = maLines[rLine].end(); + ColumnStructure::iterator pCol = maCols.begin(); + SubLine::iterator pBox = pStartLn->begin(); + SubLine::iterator pEnd = pStartLn->end(); + while( pBox != pEnd ) + { + addBox( rLine, pSelBoxes, pBox->mpBox, nBorder, nCol, + pCol, pSel, bSelected, pBox->mbCovered ); + ++pBox; + } + ++rLine; + ++pStartLn; + } + } + } + else + { + bool bSelected = false; + sal_uLong nBorder = 0; + sal_uInt16 nCol = 0; + maLines[rLine].reserve( rBoxes.Count() ); + ColumnStructure::iterator pCol = maCols.begin(); + BoxStructure::iterator pSel = maLines[rLine].end(); + for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox ) + addBox( rLine, pSelBoxes, rBoxes[nBox], nBorder, nCol, + pCol, pSel, bSelected, false ); + ++rLine; + } + } + + void TableStructure::addBox( sal_uInt16 nLine, const SwSelBoxes* pSelBoxes, + SwTableBox *pBox, sal_uLong &rnBorder, sal_uInt16 &rnCol, + ColumnStructure::iterator& rpCol, BoxStructure::iterator& rpSel, + bool &rbSelected, bool bCovered ) + { + BoxSpanInfo aInfo; + if( pSelBoxes && + USHRT_MAX != pSelBoxes->GetPos( pBox ) ) + { + aInfo.mbSelected = true; + if( mnStartCol == USHRT_MAX ) + { + mnStartCol = (sal_uInt16)maLines[nLine].size(); + if( pSelBoxes->Count() < 2 ) + { + pSelBoxes = 0; + aInfo.mbSelected = false; + } + } + } + else + aInfo.mbSelected = false; + rnBorder += pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + sal_uInt16 nLeftCol = rnCol; + while( rpCol != maCols.end() && *rpCol < rnBorder ) + { + ++rnCol; + ++rpCol; + } + if( rpCol == maCols.end() || *rpCol > rnBorder ) + { + maCols.insert( rpCol, rnBorder ); + --rpCol; + incColSpan( nLine, rnCol ); + } + aInfo.mnColSpan = rnCol - nLeftCol; + aInfo.mpCopy = 0; + aInfo.mpBox = bCovered ? 0 : pBox; + maLines[nLine].push_back( aInfo ); + if( aInfo.mbSelected ) + { + if( rbSelected ) + { + while( rpSel != maLines[nLine].end() ) + { + rpSel->mbSelected = true; + ++rpSel; + } + } + else + { + rpSel = maLines[nLine].end(); + rbSelected = true; + } + --rpSel; + } + } + + void TableStructure::moreLines( const SwTable& rTable ) + { + if( mnAddLine ) + { + const SwTableLines &rLines = rTable.GetTabLines(); + sal_uInt16 nLineCount = rLines.Count(); + if( nLineCount < mnAddLine ) + mnAddLine = nLineCount; + sal_uInt16 nLine = (sal_uInt16)maLines.size(); + maLines.resize( nLine + mnAddLine ); + while( mnAddLine ) + { + SwTableLine *pLine = rLines[ nLineCount - mnAddLine ]; + addLine( nLine, pLine->GetTabBoxes(), 0, rTable.IsNewModel() ); + --mnAddLine; + } + } + } + + void TableStructure::incColSpan( sal_uInt16 nLineMax, sal_uInt16 nNewCol ) + { + for( sal_uInt16 nLine = 0; nLine < nLineMax; ++nLine ) + { + BoxStructure::iterator pInfo = maLines[nLine].begin(); + BoxStructure::iterator pEnd = maLines[nLine].end(); + long nCol = pInfo->mnColSpan; + while( nNewCol > nCol && ++pInfo != pEnd ) + nCol += pInfo->mnColSpan; + if( pInfo != pEnd ) + ++(pInfo->mnColSpan); + } + } + + void TableStructure::assignBoxes( const TableStructure &rSource ) + { + LineStructure::const_iterator pFirstLine = rSource.maLines.begin(); + LineStructure::const_iterator pLastLine = rSource.maLines.end(); + if( pFirstLine == pLastLine ) + return; + LineStructure::const_iterator pCurrLine = pFirstLine; + LineStructure::size_type nLineCount = maLines.size(); + sal_uInt16 nFirstStartCol = 0; + { + BoxStructure::const_iterator pFirstBox = pFirstLine->begin(); + if( pFirstBox != pFirstLine->end() && pFirstBox->mpBox && + pFirstBox->mpBox->getDummyFlag() ) + nFirstStartCol = pFirstBox->mnColSpan; + } + for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine ) + { + BoxStructure::const_iterator pFirstBox = pCurrLine->begin(); + BoxStructure::const_iterator pLastBox = pCurrLine->end(); + sal_uInt16 nCurrStartCol = mnStartCol; + if( pFirstBox != pLastBox ) + { + BoxStructure::const_iterator pTmpBox = pLastBox; + --pTmpBox; + if( pTmpBox->mpBox && pTmpBox->mpBox->getDummyFlag() ) + --pLastBox; + if( pFirstBox != pLastBox && pFirstBox->mpBox && + pFirstBox->mpBox->getDummyFlag() ) + { + if( nCurrStartCol < USHRT_MAX ) + { + if( pFirstBox->mnColSpan > nFirstStartCol ) + nCurrStartCol = pFirstBox->mnColSpan - nFirstStartCol + + nCurrStartCol; + } + ++pFirstBox; + } + } + if( pFirstBox != pLastBox ) + { + BoxStructure::const_iterator pCurrBox = pFirstBox; + BoxStructure &rBox = maLines[nLine]; + BoxStructure::size_type nBoxCount = rBox.size(); + sal_uInt16 nCol = 0; + for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox ) + { + BoxSpanInfo& rInfo = rBox[nBox]; + nCol = nCol + rInfo.mnColSpan; + if( rInfo.mbSelected || nCol > nCurrStartCol ) + { + rInfo.mpCopy = pCurrBox->mpBox; + if( rInfo.mbSelected && rInfo.mpCopy->getDummyFlag() ) + { + ++pCurrBox; + if( pCurrBox == pLastBox ) + { + pCurrBox = pFirstBox; + if( pCurrBox->mpBox->getDummyFlag() ) + ++pCurrBox; + } + rInfo.mpCopy = pCurrBox->mpBox; + } + ++pCurrBox; + if( pCurrBox == pLastBox ) + { + if( rInfo.mbSelected ) + pCurrBox = pFirstBox; + else + { + rInfo.mbSelected = rInfo.mpCopy == 0; + break; + } + } + rInfo.mbSelected = rInfo.mpCopy == 0; + } + } + } + ++pCurrLine; + if( pCurrLine == pLastLine ) + pCurrLine = pFirstLine; + } + } + + void TableStructure::copyBoxes( const SwTable& rSource, SwTable& rDstTbl, + SwUndoTblCpyTbl* pUndo ) const + { + LineStructure::size_type nLineCount = maLines.size(); + for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine ) + { + const BoxStructure &rBox = maLines[nLine]; + BoxStructure::size_type nBoxCount = rBox.size(); + for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox ) + { + const BoxSpanInfo& rInfo = rBox[nBox]; + if( ( rInfo.mpCopy && !rInfo.mpCopy->getDummyFlag() ) + || rInfo.mbSelected ) + { + SwTableBox *pBox = rInfo.mpBox; + if( pBox && pBox->getRowSpan() > 0 ) + lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox, + sal_True, pUndo ); + /* Idea: If target cell is a covered cell, append content + to master cell. + sal_Bool bReplace = sal_True; + if( pBox->getRowSpan() < 0 ) + { + if( rInfo.mpCopy->getRowSpan() < 0 ) + continue; + pBox = &pBox->FindStartOfRowSpan( rDstTbl ); + bReplace = sal_False; + } + lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox, + bReplace, pUndo ); + */ + } + } + } + } +} + +// --------------------------------------------------------------- + +// kopiere die Tabelle in diese. +// Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt +// wird dabei geloescht. +// Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte +// Box einer "GrundLine". +// Ist auch keine Line mehr vorhanden, -> auch in die letzte Box +// einer "GrundLine" + + +void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox, + SwTable& rDstTbl, SwTableBox* pDstBox, + sal_Bool bDelCntnt, SwUndoTblCpyTbl* pUndo ) +{ + ASSERT( ( !pCpyBox || pCpyBox->GetSttNd() ) && pDstBox->GetSttNd(), + "Keine inhaltstragende Box" ); + + SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); + SwDoc* pDoc = rDstTbl.GetFrmFmt()->GetDoc(); + + // kopiere erst den neuen und loeschen dann den alten Inhalt + // (keine leeren Section erzeugen; werden sonst geloescht!) + std::auto_ptr< SwNodeRange > pRg( pCpyBox ? + new SwNodeRange ( *pCpyBox->GetSttNd(), 1, + *pCpyBox->GetSttNd()->EndOfSectionNode() ) : 0 ); + + SwNodeIndex aInsIdx( *pDstBox->GetSttNd(), bDelCntnt ? 1 : + pDstBox->GetSttNd()->EndOfSectionIndex() - + pDstBox->GetSttIdx() ); + + if( pUndo ) + pUndo->AddBoxBefore( *pDstBox, bDelCntnt ); + + bool bUndoRedline = pUndo && pDoc->IsRedlineOn(); + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodeIndex aSavePos( aInsIdx, -1 ); + if( pRg.get() ) + pCpyDoc->CopyWithFlyInFly( *pRg, 0, aInsIdx, sal_False ); + else + pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + aSavePos++; + + SwTableLine* pLine = pDstBox->GetUpper(); + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + sal_Bool bReplaceColl = sal_True; + if( bDelCntnt && !bUndoRedline ) + { + // zuerst die Fly loeschen, dann die entsprechenden Nodes + SwNodeIndex aEndNdIdx( *aInsIdx.GetNode().EndOfSectionNode() ); + + // Bookmarks usw. verschieben + { + SwPosition aMvPos( aInsIdx ); + SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious( &aMvPos.nNode ); + aMvPos.nContent.Assign( pCNd, pCNd->Len() ); + pDoc->CorrAbs( aInsIdx, aEndNdIdx, aMvPos, /*sal_True*/sal_False ); + } + + // stehen noch FlyFrames rum, loesche auch diese + for( sal_uInt16 n = 0; n < pDoc->GetSpzFrmFmts()->Count(); ++n ) + { + SwFrmFmt *const pFly = (*pDoc->GetSpzFrmFmts())[n]; + SwFmtAnchor const*const pAnchor = &pFly->GetAnchor(); + SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); + if (pAPos && + ((FLY_AT_PARA == pAnchor->GetAnchorId()) || + (FLY_AT_CHAR == pAnchor->GetAnchorId())) && + aInsIdx <= pAPos->nNode && pAPos->nNode <= aEndNdIdx ) + { + pDoc->DelLayoutFmt( pFly ); + } + } + + // ist DestBox eine Headline-Box und hat Tabellen-Vorlage gesetzt, + // dann NICHT die TabellenHeadline-Vorlage automatisch setzen + if( 1 < rDstTbl.GetTabLines().Count() && + pLine == rDstTbl.GetTabLines()[0] ) + { + SwCntntNode* pCNd = aInsIdx.GetNode().GetCntntNode(); + if( !pCNd ) + { + SwNodeIndex aTmp( aInsIdx ); + pCNd = pDoc->GetNodes().GoNext( &aTmp ); + } + + if( pCNd && + /*RES_POOLCOLL_TABLE == */ + RES_POOLCOLL_TABLE_HDLN != + pCNd->GetFmtColl()->GetPoolFmtId() ) + bReplaceColl = sal_False; + } + + pDoc->GetNodes().Delete( aInsIdx, aEndNdIdx.GetIndex() - aInsIdx.GetIndex() ); + } + + //b6341295: Table copy redlining will be managed by AddBoxAfter() + if( pUndo ) + pUndo->AddBoxAfter( *pDstBox, aInsIdx, bDelCntnt ); + + // heading + SwTxtNode *const pTxtNd = aSavePos.GetNode().GetTxtNode(); + if( pTxtNd ) + { + sal_uInt16 nPoolId = pTxtNd->GetTxtColl()->GetPoolFmtId(); + if( bReplaceColl && + (( 1 < rDstTbl.GetTabLines().Count() && + pLine == rDstTbl.GetTabLines()[0] ) + // gilt noch die Tabellen-Inhalt ?? + ? RES_POOLCOLL_TABLE == nPoolId + : RES_POOLCOLL_TABLE_HDLN == nPoolId ) ) + { + SwTxtFmtColl* pColl = pDoc->GetTxtCollFromPool( + static_cast<sal_uInt16>( + RES_POOLCOLL_TABLE == nPoolId + ? RES_POOLCOLL_TABLE_HDLN + : RES_POOLCOLL_TABLE ) ); + if( pColl ) // Vorlage umsetzen + { + SwPaM aPam( aSavePos ); + aPam.SetMark(); + aPam.Move( fnMoveForward, fnGoSection ); + pDoc->SetTxtFmtColl( aPam, pColl ); + } + } + + // loesche die akt. Formel/Format/Value Werte + if( SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_VALUE ) ) + { + pDstBox->ClaimFrmFmt()->ResetFmtAttr( RES_BOXATR_FORMAT, + RES_BOXATR_VALUE ); + } + + // kopiere die TabellenBoxAttribute - Formel/Format/Value + if( pCpyBox ) + { + SfxItemSet aBoxAttrSet( pCpyDoc->GetAttrPool(), RES_BOXATR_FORMAT, + RES_BOXATR_VALUE ); + aBoxAttrSet.Put( pCpyBox->GetFrmFmt()->GetAttrSet() ); + if( aBoxAttrSet.Count() ) + { + const SfxPoolItem* pItem; + SvNumberFormatter* pN = pDoc->GetNumberFormatter( sal_False ); + if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet. + GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) ) + { + sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx ); + if( nNewIdx != nOldIdx ) + aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx )); + } + pDstBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet ); + } + } + } +} + +sal_Bool SwTable::InsNewTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes, + SwUndoTblCpyTbl* pUndo ) +{ + SwDoc* pDoc = GetFrmFmt()->GetDoc(); + SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); + + SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); + + // analyse source structure + TableStructure aCopyStruct( rCpyTbl ); + + // analyse target structure (from start box) and selected substructure + _FndBox aFndBox( 0, 0 ); + { // get all boxes/lines + _FndPara aPara( rSelBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + TableStructure aTarget( *this, aFndBox, rSelBoxes, aCopyStruct.getLineCount() ); + + bool bClear = false; + if( aTarget.mnAddLine && IsNewModel() ) + { + SwSelBoxes aBoxes; + aBoxes.Insert( GetTabLines()[ GetTabLines().Count()-1 ]->GetTabBoxes()[0] ); + if( pUndo ) + pUndo->InsertRow( *this, aBoxes, aTarget.mnAddLine ); + else + InsertRow( pDoc, aBoxes, aTarget.mnAddLine, sal_True ); + + aTarget.moreLines( *this ); + bClear = true; + } + + // find mapping, if needed extend target table and/or selection + aTarget.assignBoxes( aCopyStruct ); + + { + // Change table formulas into relative representation + SwTableFmlUpdate aMsgHnt( &rCpyTbl ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + pCpyDoc->UpdateTblFlds( &aMsgHnt ); + } + + // delete frames + aFndBox.SetTableLines( *this ); + if( bClear ) + aFndBox.ClearLineBehind(); + aFndBox.DelFrms( *this ); + + // copy boxes + aTarget.copyBoxes( rCpyTbl, *this, pUndo ); + + // adjust row span attributes accordingly + + // make frames + aFndBox.MakeFrms( *this ); + + return sal_True; +} + +// --------------------------------------------------------------- + +// kopiere die Tabelle in diese. +// Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt +// wird dabei geloescht. +// Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte +// Box einer "GrundLine". +// Ist auch keine Line mehr vorhanden, -> auch in die letzte Box +// einer "GrundLine" + + +sal_Bool SwTable::InsTable( const SwTable& rCpyTbl, const SwNodeIndex& rSttBox, + SwUndoTblCpyTbl* pUndo ) +{ + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + SwDoc* pDoc = GetFrmFmt()->GetDoc(); + + SwTableNode* pTblNd = pDoc->IsIdxInTbl( rSttBox ); + + // suche erstmal die Box, in die kopiert werden soll: + SwTableBox* pMyBox = (SwTableBox*)GetTblBox( + rSttBox.GetNode().FindTableBoxStartNode()->GetIndex() ); + + ASSERT( pMyBox, "Index steht nicht in dieser Tabelle in einer Box" ); + + // loesche erstmal die Frames der Tabelle + _FndBox aFndBox( 0, 0 ); + aFndBox.DelFrms( pTblNd->GetTable() ); + + SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( &rCpyTbl ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + pCpyDoc->UpdateTblFlds( &aMsgHnt ); + } + + SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); + + sal_Bool bDelCntnt = sal_True; + const SwTableBox* pTmp; + + for( sal_uInt16 nLines = 0; nLines < rCpyTbl.GetTabLines().Count(); ++nLines ) + { + // hole die erste Box von der Copy-Line + const SwTableBox* pCpyBox = rCpyTbl.GetTabLines()[nLines] + ->GetTabBoxes()[0]; + while( pCpyBox->GetTabLines().Count() ) + pCpyBox = pCpyBox->GetTabLines()[0]->GetTabBoxes()[0]; + + do { + // kopiere erst den neuen und loeschen dann den alten Inhalt + // (keine leeren Section erzeugen, werden sonst geloescht!) + lcl_CpyBox( rCpyTbl, pCpyBox, *this, pMyBox, bDelCntnt, pUndo ); + + if( 0 == (pTmp = pCpyBox->FindNextBox( rCpyTbl, pCpyBox, sal_False ))) + break; // es folgt keine weitere Box mehr + pCpyBox = pTmp; + + if( 0 == ( pTmp = pMyBox->FindNextBox( *this, pMyBox, sal_False ))) + bDelCntnt = sal_False; // kein Platz mehr ?? + else + pMyBox = (SwTableBox*)pTmp; + + } while( sal_True ); + + // suche die oberste Line + SwTableLine* pNxtLine = pMyBox->GetUpper(); + while( pNxtLine->GetUpper() ) + pNxtLine = pNxtLine->GetUpper()->GetUpper(); + sal_uInt16 nPos = GetTabLines().C40_GETPOS( SwTableLine, pNxtLine ); + // gibt es eine naechste ?? + if( nPos + 1 >= GetTabLines().Count() ) + bDelCntnt = sal_False; // es gibt keine, alles in die letzte Box + else + { + // suche die naechste "Inhaltstragende Box" + pNxtLine = GetTabLines()[ nPos+1 ]; + pMyBox = pNxtLine->GetTabBoxes()[0]; + while( pMyBox->GetTabLines().Count() ) + pMyBox = pMyBox->GetTabLines()[0]->GetTabBoxes()[0]; + bDelCntnt = sal_True; + } + } + + aFndBox.MakeFrms( pTblNd->GetTable() ); // erzeuge die Frames neu + return sal_True; +} + + +sal_Bool SwTable::InsTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes, + SwUndoTblCpyTbl* pUndo ) +{ + ASSERT( rSelBoxes.Count(), "Missing selection" ) + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + if( IsNewModel() || rCpyTbl.IsNewModel() ) + return InsNewTable( rCpyTbl, rSelBoxes, pUndo ); + + ASSERT( !rCpyTbl.IsTblComplex(), "Table too complex" ) + + SwDoc* pDoc = GetFrmFmt()->GetDoc(); + SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); + + SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); + + SwTableBox *pTmpBox, *pSttBox = (SwTableBox*)rSelBoxes[0]; + + sal_uInt16 nLn, nBx; + _FndLine *pFLine, *pInsFLine = 0; + _FndBox aFndBox( 0, 0 ); + // suche alle Boxen / Lines + { + _FndPara aPara( rSelBoxes, &aFndBox ); + ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); + } + + // JP 06.09.96: Sonderfall - eine Box in der Tabelle -> in alle + // selektierten Boxen kopieren! + if( 1 != rCpyTbl.GetTabSortBoxes().Count() ) + { + SwTableLine* pSttLine = pSttBox->GetUpper(); + sal_uInt16 nSttBox = pSttLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); + sal_uInt16 nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine ); + _FndBox* pFndBox; + + sal_uInt16 nFndCnt = aFndBox.GetLines().Count(); + if( !nFndCnt ) + return sal_False; + + // teste ob genug Platz fuer die einzelnen Lines und Boxen ist: + sal_uInt16 nTstLns = 0; + pFLine = aFndBox.GetLines()[ 0 ]; + pSttLine = pFLine->GetLine(); + nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine ); + // sind ueberhaupt soviele Zeilen vorhanden + if( 1 == nFndCnt ) + { + // in der Tabelle noch genug Platz ?? + if( (GetTabLines().Count() - nSttLine ) < + rCpyTbl.GetTabLines().Count() ) + { + // sollte nicht mehr soviele Lines vorhanden sein, dann + // teste, ob man durch einfuegen neuer zum Ziel kommt. Aber + // nur wenn die SSelection eine Box umfasst !! + if( 1 < rSelBoxes.Count() ) + return sal_False; + + sal_uInt16 nNewLns = rCpyTbl.GetTabLines().Count() - + (GetTabLines().Count() - nSttLine ); + + // Dann teste mal ob die Anzahl der Boxen fuer die Lines reicht + SwTableLine* pLastLn = GetTabLines()[ GetTabLines().Count()-1 ]; + + pSttBox = pFLine->GetBoxes()[0]->GetBox(); + nSttBox = pFLine->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); + for( sal_uInt16 n = rCpyTbl.GetTabLines().Count() - nNewLns; + n < rCpyTbl.GetTabLines().Count(); ++n ) + { + SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ n ]; + + if( pLastLn->GetTabBoxes().Count() < nSttBox || + ( pLastLn->GetTabBoxes().Count() - nSttBox ) < + pCpyLn->GetTabBoxes().Count() ) + return sal_False; + + // Test auf Verschachtelungen + for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx ) + if( !( pTmpBox = pLastLn->GetTabBoxes()[ nSttBox + nBx ]) + ->GetSttNd() ) + return sal_False; + } + // es ist also Platz fuer das zu kopierende vorhanden, also + // fuege entsprechend neue Zeilen ein. + SwTableBox* pInsBox = pLastLn->GetTabBoxes()[ nSttBox ]; + ASSERT( pInsBox && pInsBox->GetSttNd(), + "kein CntntBox oder steht nicht in dieser Tabelle" ); + SwSelBoxes aBoxes; + + if( pUndo + ? !pUndo->InsertRow( *this, SelLineFromBox( pInsBox, + aBoxes, sal_True ), nNewLns ) + : !InsertRow( pDoc, SelLineFromBox( pInsBox, + aBoxes, sal_True ), nNewLns, sal_True ) ) + return sal_False; + } + + nTstLns = rCpyTbl.GetTabLines().Count(); // soviele Kopieren + } + else if( 0 == (nFndCnt % rCpyTbl.GetTabLines().Count()) ) + nTstLns = nFndCnt; + else + return sal_False; // kein Platz fuer die Zeilen + + for( nLn = 0; nLn < nTstLns; ++nLn ) + { + // Zeilen sind genug vorhanden, dann ueberpruefe die Boxen + // je Zeile + pFLine = aFndBox.GetLines()[ nLn % nFndCnt ]; + SwTableLine* pLine = pFLine->GetLine(); + pSttBox = pFLine->GetBoxes()[0]->GetBox(); + nSttBox = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); + if( nLn >= nFndCnt ) + { + // es sind im ClipBoard mehr Zeilen als selectiert wurden + pInsFLine = new _FndLine( GetTabLines()[ nSttLine + nLn ], + &aFndBox ); + pLine = pInsFLine->GetLine(); + } + SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ nLn % + rCpyTbl.GetTabLines().Count() ]; + + // zu wenig Zeilen selektiert ? + if( pInsFLine ) + { + // eine neue Zeile wird in die FndBox eingefuegt, + if( pLine->GetTabBoxes().Count() < nSttBox || + ( pLine->GetTabBoxes().Count() - nSttBox ) < + pFLine->GetBoxes().Count() ) + return sal_False; + + // Test auf Verschachtelungen + for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) + { + if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ]) + ->GetSttNd() ) + return sal_False; + // wenn Ok, fuege die Box in die FndLine zu + pFndBox = new _FndBox( pTmpBox, pInsFLine ); + pInsFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx ); + } + aFndBox.GetLines().C40_INSERT( _FndLine, pInsFLine, nLn ); + } + else if( pFLine->GetBoxes().Count() == 1 ) + { + if( pLine->GetTabBoxes().Count() < nSttBox || + ( pLine->GetTabBoxes().Count() - nSttBox ) < + pCpyLn->GetTabBoxes().Count() ) + return sal_False; + + // Test auf Verschachtelungen + for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx ) + { + if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ]) + ->GetSttNd() ) + return sal_False; + // wenn Ok, fuege die Box in die FndLine zu + if( nBx == pFLine->GetBoxes().Count() ) + { + pFndBox = new _FndBox( pTmpBox, pFLine ); + pFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx ); + } + } + } + else + { + // ueberpruefe die selektierten Boxen mit denen im Clipboard + // (n-Fach) + if( 0 != ( pFLine->GetBoxes().Count() % + pCpyLn->GetTabBoxes().Count() )) + return sal_False; + + // Test auf Verschachtelungen + for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) + if( !pFLine->GetBoxes()[ nBx ]->GetBox()->GetSttNd() ) + return sal_False; + } + } + + if( !aFndBox.GetLines().Count() ) + return sal_False; + } + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( &rCpyTbl ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + pCpyDoc->UpdateTblFlds( &aMsgHnt ); + } + + // loesche die Frames + aFndBox.SetTableLines( *this ); + aFndBox.DelFrms( *this ); + + if( 1 == rCpyTbl.GetTabSortBoxes().Count() ) + { + SwTableBox *pTmpBx = rCpyTbl.GetTabSortBoxes()[0]; + for( sal_uInt16 n = 0; n < rSelBoxes.Count(); ++n ) + lcl_CpyBox( rCpyTbl, pTmpBx, *this, + (SwTableBox*)rSelBoxes[n], sal_True, pUndo ); + } + else + for( nLn = 0; nLn < aFndBox.GetLines().Count(); ++nLn ) + { + pFLine = aFndBox.GetLines()[ nLn ]; + SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ + nLn % rCpyTbl.GetTabLines().Count() ]; + for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) + { + // Kopiere in pMyBox die pCpyBox + lcl_CpyBox( rCpyTbl, pCpyLn->GetTabBoxes()[ + nBx % pCpyLn->GetTabBoxes().Count() ], + *this, pFLine->GetBoxes()[ nBx ]->GetBox(), sal_True, pUndo ); + } + } + + aFndBox.MakeFrms( *this ); + return sal_True; +} + + + +sal_Bool _FndCntntBox( const SwTableBox*& rpBox, void* pPara ) +{ + SwTableBox* pBox = (SwTableBox*)rpBox; + if( rpBox->GetTabLines().Count() ) + pBox->GetTabLines().ForEach( &_FndCntntLine, pPara ); + else + ((SwSelBoxes*)pPara)->Insert( pBox ); + return sal_True; +} + + +sal_Bool _FndCntntLine( const SwTableLine*& rpLine, void* pPara ) +{ + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &_FndCntntBox, pPara ); + return sal_True; +} + + +// suche alle Inhaltstragenden-Boxen dieser Box +SwSelBoxes& SwTable::SelLineFromBox( const SwTableBox* pBox, + SwSelBoxes& rBoxes, sal_Bool bToTop ) const +{ + SwTableLine* pLine = (SwTableLine*)pBox->GetUpper(); + if( bToTop ) + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + // alle alten loeschen + rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); + pLine->GetTabBoxes().ForEach( &_FndCntntBox, &rBoxes ); + return rBoxes; +} + + diff --git a/sw/source/core/doc/tblrwcl.cxx b/sw/source/core/doc/tblrwcl.cxx new file mode 100644 index 000000000000..e4a522ce2960 --- /dev/null +++ b/sw/source/core/doc/tblrwcl.cxx @@ -0,0 +1,4770 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/chart2/XChartDocument.hpp> +#include <hintids.hxx> + +#define _ZFORLIST_DECLARE_TABLE +#include <editeng/brshitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/boxitem.hxx> +#include <tools/fract.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> +#include <doc.hxx> +#include <cntfrm.hxx> +#include <tabfrm.hxx> +#include <frmtool.hxx> +#include <pam.hxx> +#include <swtable.hxx> +#include <ndtxt.hxx> +#include <tblsel.hxx> +#include <fldbas.hxx> +#include <swundo.hxx> +#include <rowfrm.hxx> +#include <ddefld.hxx> +#include <hints.hxx> +#include <UndoTable.hxx> +#include <cellatr.hxx> +#include <mvsave.hxx> +#include <swtblfmt.hxx> +#include <swddetbl.hxx> +#include <poolfmt.hxx> +#include <tblrwcl.hxx> +#include <unochart.hxx> +#include <boost/shared_ptr.hpp> + +using namespace com::sun::star; +using namespace com::sun::star::uno; + + +#define COLFUZZY 20 +#define ROWFUZZY 10 + +using namespace ::com::sun::star; + +#ifndef DBG_UTIL +#define CHECK_TABLE(t) +#else +#ifdef DEBUG +#define CHECK_TABLE(t) (t).CheckConsistency(); +#else +#define CHECK_TABLE(t) +#endif +#endif + +typedef SwTableLine* SwTableLinePtr; +SV_DECL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr, 16, 16 ) +SV_IMPL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr ); + +SV_IMPL_PTRARR( _SwShareBoxFmts, SwShareBoxFmt* ) + +// fuers setzen der Frame-Formate an den Boxen reicht es, das aktuelle +// im Array zu suchen. Ist es vorhanden, so gebe das neue zurueck +struct _CpyTabFrm +{ + union { + SwTableBoxFmt *pFrmFmt; // fuer CopyCol + SwTwips nSize; // fuer DelCol + } Value; + SwTableBoxFmt *pNewFrmFmt; + + _CpyTabFrm( SwTableBoxFmt* pAktFrmFmt ) : pNewFrmFmt( 0 ) + { Value.pFrmFmt = pAktFrmFmt; } + + _CpyTabFrm& operator=( const _CpyTabFrm& ); + + sal_Bool operator==( const _CpyTabFrm& rCpyTabFrm ) + { return (sal_uLong)Value.nSize == (sal_uLong)rCpyTabFrm.Value.nSize; } + sal_Bool operator<( const _CpyTabFrm& rCpyTabFrm ) + { return (sal_uLong)Value.nSize < (sal_uLong)rCpyTabFrm.Value.nSize; } +}; + +struct CR_SetBoxWidth +{ + SwSelBoxes aBoxes; + SwSortTableLines aLines; + SvUShorts aLinesWidth; + SwShareBoxFmts aShareFmts; + SwTableNode* pTblNd; + SwUndoTblNdsChg* pUndo; + SwTwips nDiff, nSide, nMaxSize, nLowerDiff; + TblChgMode nMode; + sal_uInt16 nTblWidth, nRemainWidth, nBoxWidth; + sal_Bool bBigger, bLeft, bSplittBox, bAnyBoxFnd; + + CR_SetBoxWidth( sal_uInt16 eType, SwTwips nDif, SwTwips nSid, SwTwips nTblW, + SwTwips nMax, SwTableNode* pTNd ) + : pTblNd( pTNd ), + nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 ), + nTblWidth( (sal_uInt16)nTblW ), nRemainWidth( 0 ), nBoxWidth( 0 ), + bSplittBox( sal_False ), bAnyBoxFnd( sal_False ) + { + bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ); + bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER ); + nMode = pTblNd->GetTable().GetTblChgMode(); + } + CR_SetBoxWidth( const CR_SetBoxWidth& rCpy ) + : pTblNd( rCpy.pTblNd ), + pUndo( rCpy.pUndo ), + nDiff( rCpy.nDiff ), nSide( rCpy.nSide ), + nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ), + nMode( rCpy.nMode ), nTblWidth( rCpy.nTblWidth ), + nRemainWidth( rCpy.nRemainWidth ), nBoxWidth( nBoxWidth ), + bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ), + bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ) + { + aLines.Insert( &rCpy.aLines ); + aLinesWidth.Insert( &rCpy.aLinesWidth, 0 ); + } + + SwUndoTblNdsChg* CreateUndo( SwUndoId eUndoType ) + { + return pUndo = new SwUndoTblNdsChg( eUndoType, aBoxes, *pTblNd ); + } + + void LoopClear() + { + nLowerDiff = 0; nRemainWidth = 0; + } + + void AddBoxWidth( const SwTableBox& rBox, sal_uInt16 nWidth ) + { + SwTableLinePtr p = (SwTableLine*)rBox.GetUpper(); + sal_uInt16 nFndPos; + if( aLines.Insert( p, nFndPos )) + aLinesWidth.Insert( nWidth, nFndPos ); + else + aLinesWidth[ nFndPos ] = aLinesWidth[ nFndPos ] + nWidth; + } + + sal_uInt16 GetBoxWidth( const SwTableLine& rLn ) const + { + SwTableLinePtr p = (SwTableLine*)&rLn; + sal_uInt16 nFndPos; + if( aLines.Seek_Entry( p, &nFndPos ) ) + nFndPos = aLinesWidth[ nFndPos ]; + else + nFndPos = 0; + return nFndPos; + } +}; + +sal_Bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_DelSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_DelOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ); + +typedef sal_Bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, sal_Bool ); + +#if defined(DBG_UTIL) || defined( JP_DEBUG ) + +void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize ); + +#define CHECKBOXWIDTH \ + { \ + SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth(); \ + for( sal_uInt16 nTmp = 0; nTmp < aLines.Count(); ++nTmp ) \ + ::_CheckBoxWidth( *aLines[ nTmp ], nSize ); \ + } + +#define CHECKTABLELAYOUT \ + { \ + for ( sal_uInt16 i = 0; i < GetTabLines().Count(); ++i ) \ + { \ + SwFrmFmt* pFmt = GetTabLines()[i]->GetFrmFmt(); \ + SwClientIter aIter( *pFmt ); \ + SwClient* pLast = aIter.GoStart(); \ + if( pLast ) \ + { \ + do \ + { \ + SwFrm *pFrm = PTR_CAST( SwFrm, pLast ); \ + if ( pFrm && \ + ((SwRowFrm*)pFrm)->GetTabLine() == GetTabLines()[i] ) \ + { \ + ASSERT( pFrm->GetUpper()->IsTabFrm(), \ + "Table layout does not match table structure" ) \ + } \ + } while ( 0 != ( pLast = aIter++ ) ); \ + } \ + } \ + } + +#else + +#define CHECKBOXWIDTH +#define CHECKTABLELAYOUT + +#endif + + +struct CR_SetLineHeight +{ + SwSelBoxes aBoxes; + SwShareBoxFmts aShareFmts; + SwTableNode* pTblNd; + SwUndoTblNdsChg* pUndo; + SwTwips nMaxSpace, nMaxHeight; + TblChgMode nMode; + sal_uInt16 nLines; + sal_Bool bBigger, bTop, bSplittBox, bAnyBoxFnd; + + CR_SetLineHeight( sal_uInt16 eType, SwTableNode* pTNd ) + : pTblNd( pTNd ), pUndo( 0 ), + nMaxSpace( 0 ), nMaxHeight( 0 ), nLines( 0 ), + bSplittBox( sal_False ), bAnyBoxFnd( sal_False ) + { + bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ); + bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER ); + if( eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ) + bBigger = !bBigger; + nMode = pTblNd->GetTable().GetTblChgMode(); + } + CR_SetLineHeight( const CR_SetLineHeight& rCpy ) + : pTblNd( rCpy.pTblNd ), pUndo( rCpy.pUndo ), + nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ), + nMode( rCpy.nMode ), nLines( rCpy.nLines ), + bBigger( rCpy.bBigger ), bTop( rCpy.bTop ), + bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd ) + {} + + SwUndoTblNdsChg* CreateUndo( SwUndoId nUndoType ) + { + return pUndo = new SwUndoTblNdsChg( nUndoType, aBoxes, *pTblNd ); + } +}; + +sal_Bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ); +sal_Bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ); + +typedef sal_Bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, sal_Bool ); + +_CpyTabFrm& _CpyTabFrm::operator=( const _CpyTabFrm& rCpyTabFrm ) +{ + pNewFrmFmt = rCpyTabFrm.pNewFrmFmt; + Value = rCpyTabFrm.Value; + return *this; +} + +SV_DECL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm, 0, 50 ) +SV_IMPL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm ) + +void lcl_DelCpyTabFrmFmts( _CpyTabFrm& rArr ); + +// --------------------------------------------------------------- + +struct _CpyPara +{ + boost::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths; + SwDoc* pDoc; + SwTableNode* pTblNd; + _CpyTabFrms& rTabFrmArr; + SwTableLine* pInsLine; + SwTableBox* pInsBox; + sal_uLong nOldSize, nNewSize; // zum Korrigieren der Size-Attribute + sal_uLong nMinLeft, nMaxRight; + sal_uInt16 nCpyCnt, nInsPos; + sal_uInt16 nLnIdx, nBoxIdx; + sal_uInt8 nDelBorderFlag; + sal_Bool bCpyCntnt; + + _CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, _CpyTabFrms& rFrmArr, + sal_Bool bCopyContent = sal_True ) + : pDoc( pNd->GetDoc() ), pTblNd( pNd ), rTabFrmArr(rFrmArr), + pInsLine(0), pInsBox(0), nOldSize(0), nNewSize(0), + nMinLeft(ULONG_MAX), nMaxRight(0), + nCpyCnt(nCopies), nInsPos(0), + nLnIdx(0), nBoxIdx(0), + nDelBorderFlag(0), bCpyCntnt( bCopyContent ) + {} + _CpyPara( const _CpyPara& rPara, SwTableLine* pLine ) + : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd), + rTabFrmArr(rPara.rTabFrmArr), pInsLine(pLine), pInsBox(rPara.pInsBox), + nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ), + nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0), + nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ), + nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt ) + {} + _CpyPara( const _CpyPara& rPara, SwTableBox* pBox ) + : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd), + rTabFrmArr(rPara.rTabFrmArr), pInsLine(rPara.pInsLine), pInsBox(pBox), + nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize), + nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ), + nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx), + nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt ) + {} + void SetBoxWidth( SwTableBox* pBox ); +}; + + +sal_Bool lcl_CopyCol( const _FndBox*& rpFndBox, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // suche das FrmFmt im Array aller Frame-Formate + SwTableBox* pBox = (SwTableBox*)rpFndBox->GetBox(); + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pBox->GetFrmFmt() ); + + sal_uInt16 nFndPos; + if( pCpyPara->nCpyCnt ) + { + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // fuer das verschachtelte Kopieren sicher auch das neue Format + // als alt. + SwTableBoxFmt* pNewFmt = (SwTableBoxFmt*)pBox->ClaimFrmFmt(); + + // suche die selektierten Boxen in der Line: + _FndLine* pCmpLine = NULL; + SwFmtFrmSize aFrmSz( pNewFmt->GetFrmSize() ); + + bool bDiffCount = false; + if( pBox->GetTabLines().Count() ) + { + pCmpLine = rpFndBox->GetLines()[ 0 ]; + if ( pCmpLine->GetBoxes().Count() != pCmpLine->GetLine()->GetTabBoxes().Count() ) + bDiffCount = true; + } + + if( bDiffCount ) + { + // die erste Line sollte reichen + _FndBoxes& rFndBoxes = pCmpLine->GetBoxes(); + long nSz = 0; + for( sal_uInt16 n = rFndBoxes.Count(); n; ) + nSz += rFndBoxes[ --n ]->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + aFrmSz.SetWidth( aFrmSz.GetWidth() - + nSz / ( pCpyPara->nCpyCnt + 1 ) ); + pNewFmt->SetFmtAttr( aFrmSz ); + aFrmSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) ); + + // fuer die neue Box ein neues Format mit der Groesse anlegen! + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pNewFmt->GetDoc()-> + MakeTableLineFmt(); + *aFindFrm.pNewFrmFmt = *pNewFmt; + aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz ); + } + else + { + aFrmSz.SetWidth( aFrmSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) ); + pNewFmt->SetFmtAttr( aFrmSz ); + + aFindFrm.pNewFrmFmt = pNewFmt; + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + aFindFrm.Value.pFrmFmt = pNewFmt; + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + } + else + { + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; +// aFindFrm.pNewFrmFmt->Add( pBox ); + pBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt ); + } + } + else + { + if( pCpyPara->nDelBorderFlag && + pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; + else + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + } + + if( rpFndBox->GetLines().Count() ) + { + pBox = new SwTableBox( aFindFrm.pNewFrmFmt, + rpFndBox->GetLines().Count(), pCpyPara->pInsLine ); + pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++); + _CpyPara aPara( *pCpyPara, pBox ); + aPara.nDelBorderFlag &= 7; + + ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyRow, &aPara ); + } + else + { + ::_InsTblBox( pCpyPara->pDoc, pCpyPara->pTblNd, pCpyPara->pInsLine, + aFindFrm.pNewFrmFmt, pBox, pCpyPara->nInsPos++ ); + + const _FndBoxes& rFndBxs = rpFndBox->GetUpper()->GetBoxes(); + if( 8 > pCpyPara->nDelBorderFlag + ? pCpyPara->nDelBorderFlag + : rpFndBox == rFndBxs[ rFndBxs.Count() - 1 ] ) + { + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + if( 8 > pCpyPara->nDelBorderFlag + ? rBoxItem.GetTop() + : rBoxItem.GetRight() ) + { + aFindFrm.Value.pFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + + SvxBoxItem aNew( rBoxItem ); + if( 8 > pCpyPara->nDelBorderFlag ) + aNew.SetLine( 0, BOX_LINE_TOP ); + else + aNew.SetLine( 0, BOX_LINE_RIGHT ); + + if( 1 == pCpyPara->nDelBorderFlag || + 8 == pCpyPara->nDelBorderFlag ) + { + // es wird dahinter kopiert, bei allen Boxen die + // TopBorderLine loeschen + pBox = pCpyPara->pInsLine->GetTabBoxes()[ + pCpyPara->nInsPos - 1 ]; + } + + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + + // ansonsten wird davor kopiert und die erste Line behaelt + // die TopLine und an der originalen wird sie entfernt + pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); + + if( !pCpyPara->nCpyCnt ) + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + } + } + return sal_True; +} + +sal_Bool lcl_CopyRow( const _FndLine*& rpFndLine, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(), + rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox ); + if( pCpyPara->pInsBox ) + { + pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ ); + } + else + { + pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCpyPara->nInsPos++ ); + } + + _CpyPara aPara( *pCpyPara, pNewLine ); + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyCol, &aPara ); + + pCpyPara->nDelBorderFlag &= 0xf8; + return sal_True; +} + +//----------------------------------------------------------- + +void lcl_InsCol( _FndLine* pFndLn, _CpyPara& rCpyPara, sal_uInt16 nCpyCnt, + sal_Bool bBehind ) +{ + // Bug 29124: nicht nur in den Grundlines kopieren. Wenns geht, so weit + // runter wie moeglich. + _FndBox* pFBox; + if( 1 == pFndLn->GetBoxes().Count() && + !( pFBox = pFndLn->GetBoxes()[ 0 ] )->GetBox()->GetSttNd() ) + { + // eine Box mit mehreren Lines, also in diese Lines einfuegen + for( sal_uInt16 n = 0; n < pFBox->GetLines().Count(); ++n ) + lcl_InsCol( pFBox->GetLines()[ n ], rCpyPara, nCpyCnt, bBehind ); + } + else + { + rCpyPara.pInsLine = pFndLn->GetLine(); + SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ? + pFndLn->GetBoxes().Count()-1 : 0 ]->GetBox(); + rCpyPara.nInsPos = pFndLn->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + if( bBehind ) + ++rCpyPara.nInsPos; + + for( sal_uInt16 n = 0; n < nCpyCnt; ++n ) + { + if( n + 1 == nCpyCnt && bBehind ) + rCpyPara.nDelBorderFlag = 9; + else + rCpyPara.nDelBorderFlag = 8; + pFndLn->GetBoxes().ForEach( &lcl_CopyCol, &rCpyPara ); + } + } +} + +SwRowFrm* GetRowFrm( SwTableLine& rLine ) +{ + SwClientIter aIter( *rLine.GetFrmFmt() ); + for( SwClient* pFrm = aIter.First( TYPE( SwRowFrm )); pFrm; + pFrm = aIter.Next() ) + if( ((SwRowFrm*)pFrm)->GetTabLine() == &rLine ) + return (SwRowFrm*)pFrm; + return 0; +} + + +sal_Bool SwTable::InsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind ) +{ + ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + sal_Bool bRes = sal_True; + if( IsNewModel() ) + bRes = NewInsertCol( pDoc, rBoxes, nCnt, bBehind ); + else + { + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + aFndBox.SetTableLines( *this ); + aFndBox.DelFrms( *this ); + + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, nCnt, aTabFrmArr ); + + for( sal_uInt16 n = 0; n < aFndBox.GetLines().Count(); ++n ) + lcl_InsCol( aFndBox.GetLines()[ n ], aCpyPara, nCnt, bBehind ); + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + GCLines(); + + //Layout updaten + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + bRes = sal_True; + } + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD && nCnt) + pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind ); + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + return bRes; +} + +sal_Bool SwTable::_InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, + sal_uInt16 nCnt, sal_Bool bBehind ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + _FndBox* pFndBox = &aFndBox; + { + _FndLine* pFndLine; + while( 1 == pFndBox->GetLines().Count() && + 1 == ( pFndLine = pFndBox->GetLines()[ 0 ])->GetBoxes().Count() ) + { + // nicht zu weit runter, eine Line mit Boxen muss nachbleiben!! + _FndBox* pTmpBox = pFndLine->GetBoxes()[ 0 ]; + if( pTmpBox->GetLines().Count() ) + pFndBox = pTmpBox; + else + break; + } + } + + //Lines fuer das Layout-Update herausuchen. + const sal_Bool bLayout = !IsNewModel() && + 0 != SwClientIter( *GetFrmFmt() ).First( TYPE(SwTabFrm) ); + + if ( bLayout ) + { + aFndBox.SetTableLines( *this ); + if( pFndBox != &aFndBox ) + aFndBox.DelFrms( *this ); + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + } + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr ); + + SwTableLine* pLine = pFndBox->GetLines()[ bBehind ? + pFndBox->GetLines().Count()-1 : 0 ]->GetLine(); + if( &aFndBox == pFndBox ) + aCpyPara.nInsPos = GetTabLines().C40_GETPOS( SwTableLine, pLine ); + else + { + aCpyPara.pInsBox = pFndBox->GetBox(); + aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().C40_GETPOS( SwTableLine, pLine ); + } + + if( bBehind ) + { + ++aCpyPara.nInsPos; + aCpyPara.nDelBorderFlag = 1; + } + else + aCpyPara.nDelBorderFlag = 2; + + for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt ) + { + if( bBehind ) + aCpyPara.nDelBorderFlag = 1; + pFndBox->GetLines().ForEach( &lcl_CopyRow, &aCpyPara ); + } + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + if( !pDoc->IsInReading() ) + GCLines(); + + //Layout updaten + if ( bLayout ) + { + if( pFndBox != &aFndBox ) + aFndBox.MakeFrms( *this ); + else + aFndBox.MakeNewFrms( *this, nCnt, bBehind ); + } + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + if (pPCD && nCnt) + pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind ); + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + return sal_True; +} + +sal_Bool _FndBoxAppendRowLine( const SwTableLine*& rpLine, void* pPara ); + +sal_Bool _FndBoxAppendRowBox( const SwTableBox*& rpBox, void* pPara ) +{ + _FndPara* pFndPara = (_FndPara*)pPara; + _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine ); + if( rpBox->GetTabLines().Count() ) + { + _FndPara aPara( *pFndPara, pFndBox ); + pFndBox->GetBox()->GetTabLines().ForEach( &_FndBoxAppendRowLine, &aPara ); + if( !pFndBox->GetLines().Count() ) + delete pFndBox; + } + else + pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, + pFndPara->pFndLine->GetBoxes().Count() ); + return sal_True; +} + +sal_Bool _FndBoxAppendRowLine( const SwTableLine*& rpLine, void* pPara ) +{ + _FndPara* pFndPara = (_FndPara*)pPara; + _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox ); + _FndPara aPara( *pFndPara, pFndLine ); + pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxAppendRowBox, &aPara ); + if( pFndLine->GetBoxes().Count() ) + { + pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine, + pFndPara->pFndBox->GetLines().Count() ); + } + else + delete pFndLine; + return sal_True; +} + + +sal_Bool SwTable::AppendRow( SwDoc* pDoc, sal_uInt16 nCnt ) +{ + SwTableNode* pTblNd = (SwTableNode*)aSortCntBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + const SwTableLine* pLLine = GetTabLines()[ GetTabLines().Count()-1 ]; + + const SwSelBoxes* pBxs = 0; // Dummy !!! + _FndPara aPara( *pBxs, &aFndBox ); + + _FndBoxAppendRowLine( pLLine, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + const sal_Bool bLayout = 0 != SwClientIter( *GetFrmFmt() ).First( TYPE(SwTabFrm) ); + if( bLayout ) + { + aFndBox.SetTableLines( *this ); + // TL_CHART2: nothing to be done since chart2 currently does not want to + // get notified about new rows/cols. + } + + _CpyTabFrms aTabFrmArr; + _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr ); + aCpyPara.nInsPos = GetTabLines().Count(); + aCpyPara.nDelBorderFlag = 1; + + for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt ) + { + aCpyPara.nDelBorderFlag = 1; + aFndBox.GetLines().ForEach( &lcl_CopyRow, &aCpyPara ); + } + + // dann raeume die Struktur dieser Line noch mal auf, generell alle + if( !pDoc->IsInReading() ) + GCLines(); + + //Layout updaten + if ( bLayout ) + { + aFndBox.MakeNewFrms( *this, nCnt, sal_True ); + } + // TL_CHART2: need to inform chart of probably changed cell names + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + return sal_True; +} + + +void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset, + sal_Bool bFirst, SwShareBoxFmts& rShareFmts ); + +void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const long nOffset, + sal_Bool bFirst, SwShareBoxFmts& rShareFmts ) +{ + for ( sal_uInt16 i = 0; i < rLines.Count(); ++i ) + ::lcl_LastBoxSetWidth( rLines[i]->GetTabBoxes(), nOffset, bFirst, + rShareFmts ); +} + +void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset, + sal_Bool bFirst, SwShareBoxFmts& rShareFmts ) +{ + SwTableBox& rBox = *rBoxes[ bFirst ? 0 : rBoxes.Count() - 1 ]; + if( !rBox.GetSttNd() ) + ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset, + bFirst, rShareFmts ); + + //Die Box anpassen + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(); + SwFmtFrmSize aNew( pBoxFmt->GetFrmSize() ); + aNew.SetWidth( aNew.GetWidth() + nOffset ); + SwFrmFmt *pFmt = rShareFmts.GetFormat( *pBoxFmt, aNew ); + if( pFmt ) + rBox.ChgFrmFmt( (SwTableBoxFmt*)pFmt ); + else + { + pFmt = rBox.ClaimFrmFmt(); + + pFmt->LockModify(); + pFmt->SetFmtAttr( aNew ); + pFmt->UnlockModify(); + + rShareFmts.AddFormat( *pBoxFmt, *pFmt ); + } +} + +void _DeleteBox( SwTable& rTbl, SwTableBox* pBox, SwUndo* pUndo, + sal_Bool bCalcNewSize, const sal_Bool bCorrBorder, + SwShareBoxFmts* pShareFmts ) +{ + do { + SwTwips nBoxSz = bCalcNewSize ? + pBox->GetFrmFmt()->GetFrmSize().GetWidth() : 0; + SwTableLine* pLine = pBox->GetUpper(); + SwTableBoxes& rTblBoxes = pLine->GetTabBoxes(); + sal_uInt16 nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox ); + SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper(); + + // Sonderbehandlung fuer Umrandung: + if( bCorrBorder && 1 < rTblBoxes.Count() ) + { + sal_Bool bChgd = sal_False; + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + + if( rBoxItem.GetLeft() || rBoxItem.GetRight() ) + { + //JP 02.04.97: 1.Teil fuer Bug 36271 + // zuerst die linken/rechten Kanten + if( nDelPos + 1 < rTblBoxes.Count() ) + { + SwTableBox* pNxtBox = rTblBoxes[ nDelPos + 1 ]; + const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox(); + + SwTableBox* pPrvBox = nDelPos ? rTblBoxes[ nDelPos - 1 ] : 0; + + if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() && + ( !pPrvBox || !pPrvBox->GetFrmFmt()->GetBox().GetRight()) ) + { + SvxBoxItem aTmp( rNxtBoxItem ); + aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft() + : rBoxItem.GetRight(), + BOX_LINE_LEFT ); + if( pShareFmts ) + pShareFmts->SetAttr( *pNxtBox, aTmp ); + else + pNxtBox->ClaimFrmFmt()->SetFmtAttr( aTmp ); + bChgd = sal_True; + } + } + if( !bChgd && nDelPos ) + { + SwTableBox* pPrvBox = rTblBoxes[ nDelPos - 1 ]; + const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox(); + + SwTableBox* pNxtBox = nDelPos + 1 < rTblBoxes.Count() + ? rTblBoxes[ nDelPos + 1 ] : 0; + + if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() && + ( !pNxtBox || !pNxtBox->GetFrmFmt()->GetBox().GetLeft()) ) + { + SvxBoxItem aTmp( rPrvBoxItem ); + aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft() + : rBoxItem.GetRight(), + BOX_LINE_RIGHT ); + if( pShareFmts ) + pShareFmts->SetAttr( *pPrvBox, aTmp ); + else + pPrvBox->ClaimFrmFmt()->SetFmtAttr( aTmp ); + } + } + } + + } + + // erst die Box, dann die Nodes loeschen!! + SwStartNode* pSttNd = (SwStartNode*)pBox->GetSttNd(); + if( pShareFmts ) + pShareFmts->RemoveFormat( *rTblBoxes[ nDelPos ]->GetFrmFmt() ); + rTblBoxes.DeleteAndDestroy( nDelPos ); + + if( pSttNd ) + { + // ist das UndoObject zum speichern der Section vorbereitet? + if( pUndo && pUndo->IsDelBox() ) + ((SwUndoTblNdsChg*)pUndo)->SaveSection( pSttNd ); + else + pSttNd->GetDoc()->DeleteSection( pSttNd ); + } + + // auch die Zeile noch loeschen ?? + if( rTblBoxes.Count() ) + { + // dann passe noch die Frame-SSize an + sal_Bool bLastBox = nDelPos == rTblBoxes.Count(); + if( bLastBox ) + --nDelPos; + pBox = rTblBoxes[nDelPos]; + if( bCalcNewSize ) + { + SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() ); + aNew.SetWidth( aNew.GetWidth() + nBoxSz ); + if( pShareFmts ) + pShareFmts->SetSize( *pBox, aNew ); + else + pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); + + if( !pBox->GetSttNd() ) + { + // dann muss es auch rekursiv in allen Zeilen, in allen + // Zellen erfolgen! + SwShareBoxFmts aShareFmts; + ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz, + !bLastBox, + pShareFmts ? *pShareFmts + : aShareFmts ); + } + } + break; // nichts mehr loeschen + } + // loesche die Line aus Tabelle/Box + if( !pUpperBox ) + { + // dann loesche auch noch die Line aus der Tabelle + nDelPos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine ); + if( pShareFmts ) + pShareFmts->RemoveFormat( *rTbl.GetTabLines()[ nDelPos ]->GetFrmFmt() ); + rTbl.GetTabLines().DeleteAndDestroy( nDelPos ); + break; // mehr kann nicht geloescht werden + } + + // dann loesche auch noch die Line + pBox = pUpperBox; + nDelPos = pBox->GetTabLines().C40_GETPOS( SwTableLine, pLine ); + if( pShareFmts ) + pShareFmts->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrmFmt() ); + pBox->GetTabLines().DeleteAndDestroy( nDelPos ); + } while( !pBox->GetTabLines().Count() ); +} + +SwTableBox* lcl_FndNxtPrvDelBox( const SwTableLines& rTblLns, + SwTwips nBoxStt, SwTwips nBoxWidth, + sal_uInt16 nLinePos, sal_Bool bNxt, + SwSelBoxes* pAllDelBoxes, sal_uInt16* pCurPos ) +{ + SwTableBox* pFndBox = 0; + do { + if( bNxt ) + ++nLinePos; + else + --nLinePos; + SwTableLine* pLine = rTblLns[ nLinePos ]; + SwTwips nFndBoxWidth = 0; + SwTwips nFndWidth = nBoxStt + nBoxWidth; + sal_uInt16 nBoxCnt = pLine->GetTabBoxes().Count(); + + pFndBox = pLine->GetTabBoxes()[ 0 ]; + for( sal_uInt16 n = 0; 0 < nFndWidth && n < nBoxCnt; ++n ) + { + pFndBox = pLine->GetTabBoxes()[ n ]; + nFndWidth -= (nFndBoxWidth = pFndBox->GetFrmFmt()-> + GetFrmSize().GetWidth()); + } + + // suche die erste ContentBox + while( !pFndBox->GetSttNd() ) + { + const SwTableLines& rLowLns = pFndBox->GetTabLines(); + if( bNxt ) + pFndBox = rLowLns[ 0 ]->GetTabBoxes()[ 0 ]; + else + pFndBox = rLowLns[ rLowLns.Count() - 1 ]->GetTabBoxes()[ 0 ]; + } + + if( Abs( nFndWidth ) > COLFUZZY || + Abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY ) + pFndBox = 0; + else if( pAllDelBoxes ) + { + // falls der Vorganger auch geloscht wird, ist nicht zu tun + sal_uInt16 nFndPos; + if( !pAllDelBoxes->Seek_Entry( pFndBox, &nFndPos ) ) + break; + + // sonst noch mal weitersuchen + // Die Box muessen wir aber nicht nochmal abpruefen + pFndBox = 0; + if( nFndPos <= *pCurPos ) + --*pCurPos; + pAllDelBoxes->Remove( nFndPos ); + } + } while( bNxt ? ( nLinePos + 1 < rTblLns.Count() ) : nLinePos ); + return pFndBox; +} + +void lcl_SaveUpperLowerBorder( SwTable& rTbl, const SwTableBox& rBox, + SwShareBoxFmts& rShareFmts, + SwSelBoxes* pAllDelBoxes = 0, + sal_uInt16* pCurPos = 0 ) +{ +//JP 16.04.97: 2.Teil fuer Bug 36271 + sal_Bool bChgd = sal_False; + const SwTableLine* pLine = rBox.GetUpper(); + const SwTableBoxes& rTblBoxes = pLine->GetTabBoxes(); + const SwTableBox* pUpperBox = &rBox; + sal_uInt16 nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pUpperBox ); + pUpperBox = rBox.GetUpper()->GetUpper(); + const SvxBoxItem& rBoxItem = rBox.GetFrmFmt()->GetBox(); + + // dann die unteren/oberen Kanten + if( rBoxItem.GetTop() || rBoxItem.GetBottom() ) + { + bChgd = sal_False; + const SwTableLines* pTblLns; + if( pUpperBox ) + pTblLns = &pUpperBox->GetTabLines(); + else + pTblLns = &rTbl.GetTabLines(); + + sal_uInt16 nLnPos = pTblLns->GetPos( pLine ); + + // bestimme die Attr.Position der akt. zu loeschenden Box + // und suche dann in der unteren / oberen Line die entspr. + // Gegenstuecke + SwTwips nBoxStt = 0; + for( sal_uInt16 n = 0; n < nDelPos; ++n ) + nBoxStt += rTblBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + SwTwips nBoxWidth = rBox.GetFrmFmt()->GetFrmSize().GetWidth(); + + SwTableBox *pPrvBox = 0, *pNxtBox = 0; + if( nLnPos ) // Vorgaenger? + pPrvBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth, + nLnPos, sal_False, pAllDelBoxes, pCurPos ); + + if( nLnPos + 1 < pTblLns->Count() ) // Nachfolger? + pNxtBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth, + nLnPos, sal_True, pAllDelBoxes, pCurPos ); + + if( pNxtBox && pNxtBox->GetSttNd() ) + { + const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox(); + if( !rNxtBoxItem.GetTop() && ( !pPrvBox || + !pPrvBox->GetFrmFmt()->GetBox().GetBottom()) ) + { + SvxBoxItem aTmp( rNxtBoxItem ); + aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop() + : rBoxItem.GetBottom(), + BOX_LINE_TOP ); + rShareFmts.SetAttr( *pNxtBox, aTmp ); + bChgd = sal_True; + } + } + if( !bChgd && pPrvBox && pPrvBox->GetSttNd() ) + { + const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox(); + if( !rPrvBoxItem.GetTop() && ( !pNxtBox || + !pNxtBox->GetFrmFmt()->GetBox().GetTop()) ) + { + SvxBoxItem aTmp( rPrvBoxItem ); + aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop() + : rBoxItem.GetBottom(), + BOX_LINE_BOTTOM ); + rShareFmts.SetAttr( *pPrvBox, aTmp ); + } + } + + } +} + + +sal_Bool SwTable::DeleteSel( + SwDoc* pDoc + , + const SwSelBoxes& rBoxes, + const SwSelBoxes* pMerged, SwUndo* pUndo, + const sal_Bool bDelMakeFrms, const sal_Bool bCorrBorder ) +{ + ASSERT( pDoc, "No doc?" ); + SwTableNode* pTblNd = 0; + if( rBoxes.Count() ) + { + pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + } + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + if ( bDelMakeFrms ) + { + if( pMerged && pMerged->Count() ) + aFndBox.SetTableLines( *pMerged, *this ); + else if( rBoxes.Count() ) + aFndBox.SetTableLines( rBoxes, *this ); + aFndBox.DelFrms( *this ); + } + + SwShareBoxFmts aShareFmts; + + // erst die Umrandung umsetzen, dann loeschen + if( bCorrBorder ) + { + SwSelBoxes aBoxes; + aBoxes.Insert( &rBoxes ); + for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n ) + ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFmts, + &aBoxes, &n ); + } + + PrepareDelBoxes( rBoxes ); + + SwChartDataProvider *pPCD = pDoc->GetChartDataProvider(); + // + // delete boxes from last to first + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + sal_uInt16 nIdx = rBoxes.Count() - 1 - n; + + // first adapt the data-sequence for chart if necessary + // (needed to move the implementation cursor properly to it's new + // position which can't be done properly if the cell is already gone) + if (pPCD && pTblNd) + pPCD->DeleteBox( &pTblNd->GetTable(), *rBoxes[nIdx] ); + + // ... then delete the boxes + _DeleteBox( *this, rBoxes[nIdx], pUndo, sal_True, bCorrBorder, &aShareFmts ); + } + + // dann raeume die Struktur aller Lines auf + GCLines(); + + if( bDelMakeFrms && aFndBox.AreLinesToRestore( *this ) ) + aFndBox.MakeFrms( *this ); + + // TL_CHART2: now inform chart that sth has changed + pDoc->UpdateCharts( GetFrmFmt()->GetName() ); + + CHECKTABLELAYOUT + CHECK_TABLE( *this ) + + return sal_True; +} + + +// --------------------------------------------------------------- + +sal_Bool SwTable::OldSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, + sal_Bool bSameHeight ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + // If the rows should get the same (min) height, we first have + // to store the old row heights before deleting the frames + long* pRowHeights = 0; + if ( bSameHeight ) + { + pRowHeights = new long[ rBoxes.Count() ]; + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( rBoxes.GetData() + n ); + const SwRowFrm* pRow = GetRowFrm( *pSelBox->GetUpper() ); + ASSERT( pRow, "wo ist der Frm von der SwTableLine?" ) + SWRECTFN( pRow ) + pRowHeights[ n ] = (pRow->Frm().*fnRect->fnGetHeight)(); + } + } + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( rBoxes, *this ); + aFndBox.DelFrms( *this ); + + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( rBoxes.GetData() + n ); + ASSERT( pSelBox, "Box steht nicht in der Tabelle" ); + + // dann fuege in die Box nCnt neue Zeilen ein + SwTableLine* pInsLine = pSelBox->GetUpper(); + SwTableBoxFmt* pFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt(); + + // Hoehe der Line beachten, gegebenenfalls neu setzen + SwFmtFrmSize aFSz( pInsLine->GetFrmFmt()->GetFrmSize() ); + if ( bSameHeight && ATT_VAR_SIZE == aFSz.GetHeightSizeType() ) + aFSz.SetHeightSizeType( ATT_MIN_SIZE ); + + sal_Bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight; + if ( bChgLineSz ) + aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) / + (nCnt + 1) ); + + SwTableBox* pNewBox = new SwTableBox( pFrmFmt, nCnt, pInsLine ); + sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox ); + pInsLine->GetTabBoxes().Remove( nBoxPos ); // alte loeschen + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pNewBox, nBoxPos ); + + // Hintergrund- / Rand Attribut loeschen + SwTableBox* pLastBox = pSelBox; // zum verteilen der TextNodes !! + // sollte Bereiche in der Box stehen, dann bleibt sie so bestehen + // !! FALLS DAS GEAENDERT WIRD MUSS DAS UNDO ANGEPASST WERDEN !!! + sal_Bool bMoveNodes = sal_True; + { + sal_uLong nSttNd = pLastBox->GetSttIdx() + 1, + nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex(); + while( nSttNd < nEndNd ) + if( !pDoc->GetNodes()[ nSttNd++ ]->IsTxtNode() ) + { + bMoveNodes = sal_False; + break; + } + } + + SwTableBoxFmt* pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt(); + sal_Bool bChkBorder = 0 != pCpyBoxFrmFmt->GetBox().GetTop(); + if( bChkBorder ) + pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt(); + + for( sal_uInt16 i = 0; i <= nCnt; ++i ) + { + // also erstmal eine neue Linie in der neuen Box + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pNewBox ); + if( bChgLineSz ) + { + pNewLine->ClaimFrmFmt()->SetFmtAttr( aFSz ); + } + + pNewBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, i ); + // dann eine neue Box in der Line + if( !i ) // haenge die originale Box ein + { + pSelBox->SetUpper( pNewLine ); + pNewLine->GetTabBoxes().C40_INSERT( SwTableBox, pSelBox, 0 ); + } + else + { + ::_InsTblBox( pDoc, pTblNd, pNewLine, pCpyBoxFrmFmt, + pLastBox, 0 ); + + if( bChkBorder ) + { + pCpyBoxFrmFmt = (SwTableBoxFmt*)pNewLine->GetTabBoxes()[ 0 ]->ClaimFrmFmt(); + SvxBoxItem aTmp( pCpyBoxFrmFmt->GetBox() ); + aTmp.SetLine( 0, BOX_LINE_TOP ); + pCpyBoxFrmFmt->SetFmtAttr( aTmp ); + bChkBorder = sal_False; + } + + if( bMoveNodes ) + { + const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode(); + if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() ) + { + // TextNodes verschieben + SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd ); + pLastBox = pNewLine->GetTabBoxes()[0]; // neu setzen + SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 ); + pDoc->GetNodes()._MoveNodes(aRg, pDoc->GetNodes(), aInsPos, sal_False); + pDoc->GetNodes().Delete( aInsPos, 1 ); // den leeren noch loeschen + } + } + } + } + // in Boxen mit Lines darf es nur noch Size/Fillorder geben + pFrmFmt = (SwTableBoxFmt*)pNewBox->ClaimFrmFmt(); + pFrmFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); + pFrmFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 ); + } + + delete[] pRowHeights; + + GCLines(); + + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + return sal_True; +} + +sal_Bool SwTable::SplitCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt ) +{ + ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + SwSelBoxes aSelBoxes; + aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count()); + ExpandSelection( aSelBoxes ); + + //Lines fuer das Layout-Update herausuchen. + _FndBox aFndBox( 0, 0 ); + aFndBox.SetTableLines( aSelBoxes, *this ); + aFndBox.DelFrms( *this ); + + _CpyTabFrms aFrmArr; + SvPtrarr aLastBoxArr; + sal_uInt16 nFndPos; + for( sal_uInt16 n = 0; n < aSelBoxes.Count(); ++n ) + { + SwTableBox* pSelBox = *( aSelBoxes.GetData() + n ); + ASSERT( pSelBox, "Box steht nicht in der Tabelle" ); + + // We don't want to split small table cells into very very small cells + if( pSelBox->GetFrmFmt()->GetFrmSize().GetWidth()/( nCnt + 1 ) < 10 ) + continue; + + // dann teile die Box nCnt in nCnt Boxen + SwTableLine* pInsLine = pSelBox->GetUpper(); + sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox ); + + // suche das FrmFmt im Array aller Frame-Formate + SwTableBoxFmt* pLastBoxFmt; + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pSelBox->GetFrmFmt() ); + if( !aFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // aender das FrmFmt + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt(); + SwTwips nBoxSz = aFindFrm.pNewFrmFmt->GetFrmSize().GetWidth(); + SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 ); + aFindFrm.pNewFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + nNewBoxSz, 0 ) ); + aFrmArr.Insert( aFindFrm ); + + pLastBoxFmt = aFindFrm.pNewFrmFmt; + if( nBoxSz != ( nNewBoxSz * (nCnt + 1))) + { + // es bleibt ein Rest, also muss fuer die letzte Box ein + // eigenes Format definiert werden + pLastBoxFmt = new SwTableBoxFmt( *aFindFrm.pNewFrmFmt ); + pLastBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, + nBoxSz - ( nNewBoxSz * nCnt ), 0 ) ); + } + void* p = pLastBoxFmt; + aLastBoxArr.Insert( p, nFndPos ); + } + else + { + aFindFrm = aFrmArr[ nFndPos ]; + pSelBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt ); + pLastBoxFmt = (SwTableBoxFmt*)aLastBoxArr[ nFndPos ]; + } + + // dann fuege mal an der Position die neuen Boxen ein + for( sal_uInt16 i = 1; i < nCnt; ++i ) + ::_InsTblBox( pDoc, pTblNd, pInsLine, aFindFrm.pNewFrmFmt, + pSelBox, nBoxPos + i ); // dahinter einfuegen + + ::_InsTblBox( pDoc, pTblNd, pInsLine, pLastBoxFmt, + pSelBox, nBoxPos + nCnt ); // dahinter einfuegen + + // Sonderbehandlung fuer die Umrandung: + const SvxBoxItem& aSelBoxItem = aFindFrm.pNewFrmFmt->GetBox(); + if( aSelBoxItem.GetRight() ) + { + pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrmFmt(); + + SvxBoxItem aTmp( aSelBoxItem ); + aTmp.SetLine( 0, BOX_LINE_RIGHT ); + aFindFrm.pNewFrmFmt->SetFmtAttr( aTmp ); + + // und dann das Format aus dem "cache" entfernen + for( sal_uInt16 i = aFrmArr.Count(); i; ) + { + const _CpyTabFrm& rCTF = aFrmArr[ --i ]; + if( rCTF.pNewFrmFmt == aFindFrm.pNewFrmFmt || + rCTF.Value.pFrmFmt == aFindFrm.pNewFrmFmt ) + { + aFrmArr.Remove( i ); + aLastBoxArr.Remove( i ); + } + } + } + } + + //Layout updaten + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + return sal_True; +} + +// --------------------------------------------------------------- + +/* + ----------------------- >> MERGE << ------------------------ + Algorithmus: + ist in der _FndBox nur eine Line angegeben, nehme die Line + und teste die Anzahl der Boxen + - ist mehr als 1 Box angegeben, so wird auf Boxenebene zusammen- + gefasst, d.H. die neue Box wird so Breit wie die alten. + - Alle Lines die ueber/unter dem Bereich liegen werden in die + Box als Line + Box mit Lines eingefuegt + - Alle Lines die vor/hinter dem Bereich liegen werden in + die Boxen Left/Right eingetragen + + ----------------------- >> MERGE << ------------------------ +*/ + +void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd, + SwTableLines& rLines, + SwTableBox* pInsBox, + sal_uInt16 nPos = USHRT_MAX ) +{ + for( sal_uInt16 n = nStt; n < nEnd; ++n ) + rLines[n]->SetUpper( pInsBox ); + if( USHRT_MAX == nPos ) + nPos = pInsBox->GetTabLines().Count(); + pInsBox->GetTabLines().Insert( &rLines, nPos, nStt, nEnd ); + rLines.Remove( nStt, nEnd - nStt ); +} + +void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd, + SwTableBoxes& rBoxes, + SwTableLine* pInsLine, + sal_uInt16 nPos = USHRT_MAX ) +{ + for( sal_uInt16 n = nStt; n < nEnd; ++n ) + rBoxes[n]->SetUpper( pInsLine ); + if( USHRT_MAX == nPos ) + nPos = pInsLine->GetTabBoxes().Count(); + pInsLine->GetTabBoxes().Insert( &rBoxes, nPos, nStt, nEnd ); + rBoxes.Remove( nStt, nEnd - nStt ); +} + +void lcl_CalcWidth( SwTableBox* pBox ) +{ + // Annahme: jede Line in der Box ist gleich gross + SwFrmFmt* pFmt = pBox->ClaimFrmFmt(); + ASSERT( pBox->GetTabLines().Count(), "Box hat keine Lines" ); + + SwTableLine* pLine = pBox->GetTabLines()[0]; + ASSERT( pLine, "Box steht in keiner Line" ); + + long nWidth = 0; + for( sal_uInt16 n = 0; n < pLine->GetTabBoxes().Count(); ++n ) + nWidth += pLine->GetTabBoxes()[n]->GetFrmFmt()->GetFrmSize().GetWidth(); + + pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); + + // in Boxen mit Lines darf es nur noch Size/Fillorder geben + pFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 ); + pFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 ); +} + + + +struct _InsULPara +{ + SwTableNode* pTblNd; + SwTableLine* pInsLine; + SwTableBox* pInsBox; + sal_Bool bUL_LR : 1; // Upper-Lower(sal_True) oder Left-Right(sal_False) ? + sal_Bool bUL : 1; // Upper-Left(sal_True) oder Lower-Right(sal_False) ? + + SwTableBox* pLeftBox; + SwTableBox* pRightBox; + SwTableBox* pMergeBox; + + _InsULPara( SwTableNode* pTNd, sal_Bool bUpperLower, sal_Bool bUpper, + SwTableBox* pLeft, SwTableBox* pMerge, SwTableBox* pRight, + SwTableLine* pLine=0, SwTableBox* pBox=0 ) + : pTblNd( pTNd ), pInsLine( pLine ), pInsBox( pBox ), + pLeftBox( pLeft ), pRightBox( pRight ), pMergeBox( pMerge ) + { bUL_LR = bUpperLower; bUL = bUpper; } + + void SetLeft( SwTableBox* pBox=0 ) + { bUL_LR = sal_False; bUL = sal_True; if( pBox ) pInsBox = pBox; } + void SetRight( SwTableBox* pBox=0 ) + { bUL_LR = sal_False; bUL = sal_False; if( pBox ) pInsBox = pBox; } + void SetUpper( SwTableLine* pLine=0 ) + { bUL_LR = sal_True; bUL = sal_True; if( pLine ) pInsLine = pLine; } + void SetLower( SwTableLine* pLine=0 ) + { bUL_LR = sal_True; bUL = sal_False; if( pLine ) pInsLine = pLine; } +}; + + +sal_Bool lcl_Merge_MoveBox( const _FndBox*& rpFndBox, void* pPara ) +{ + _InsULPara* pULPara = (_InsULPara*)pPara; + SwTableBoxes* pBoxes; + + sal_uInt16 nStt = 0, nEnd = rpFndBox->GetLines().Count(); + sal_uInt16 nInsPos = USHRT_MAX; + if( !pULPara->bUL_LR ) // Left/Right + { + sal_uInt16 nPos; + SwTableBox* pFndBox = (SwTableBox*)rpFndBox->GetBox(); + pBoxes = &pFndBox->GetUpper()->GetTabBoxes(); + if( pULPara->bUL ) // Left ? + { + // gibt es noch davor Boxen, dann move sie + if( 0 != ( nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) ) + lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine ); + } + else // Right + // gibt es noch dahinter Boxen, dann move sie + if( (nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) +1 < pBoxes->Count() ) + { + nInsPos = pULPara->pInsLine->GetTabBoxes().Count(); + lcl_CpyBoxes( nPos+1, pBoxes->Count(), + *pBoxes, pULPara->pInsLine ); + } + } + // Upper/Lower und gehts noch tiefer ?? + else if( rpFndBox->GetLines().Count() ) + { + // suche nur die Line, ab der Verschoben werden muss + nStt = pULPara->bUL ? 0 : rpFndBox->GetLines().Count()-1; + nEnd = nStt+1; + } + + pBoxes = &pULPara->pInsLine->GetTabBoxes(); + + // geht es noch eine weitere Stufe runter? + if( rpFndBox->GetBox()->GetTabLines().Count() ) + { + SwTableBox* pBox = new SwTableBox( + (SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt(), 0, pULPara->pInsLine ); + _InsULPara aPara( *pULPara ); + aPara.pInsBox = pBox; + ((_FndBox*)rpFndBox)->GetLines().ForEach( nStt, nEnd, + &lcl_Merge_MoveLine, &aPara ); + if( pBox->GetTabLines().Count() ) + { + if( USHRT_MAX == nInsPos ) + nInsPos = pBoxes->Count(); + pBoxes->C40_INSERT( SwTableBox, pBox, nInsPos ); + lcl_CalcWidth( pBox ); // bereche die Breite der Box + } + else + delete pBox; + } + return sal_True; +} + +sal_Bool lcl_Merge_MoveLine( const _FndLine*& rpFndLine, void* pPara ) +{ + _InsULPara* pULPara = (_InsULPara*)pPara; + SwTableLines* pLines; + + sal_uInt16 nStt = 0, nEnd = rpFndLine->GetBoxes().Count(); + sal_uInt16 nInsPos = USHRT_MAX; + if( pULPara->bUL_LR ) // UpperLower ? + { + sal_uInt16 nPos; + SwTableLine* pFndLn = (SwTableLine*)rpFndLine->GetLine(); + pLines = pFndLn->GetUpper() ? + &pFndLn->GetUpper()->GetTabLines() : + &pULPara->pTblNd->GetTable().GetTabLines(); + + SwTableBox* pLBx = rpFndLine->GetBoxes()[0]->GetBox(); + SwTableBox* pRBx = rpFndLine->GetBoxes()[ + rpFndLine->GetBoxes().Count()-1]->GetBox(); + sal_uInt16 nLeft = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pLBx ); + sal_uInt16 nRight = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pRBx ); + +// if( ( nLeft && nRight+1 < pFndLn->GetTabBoxes().Count() ) || +// ( !nLeft && nRight+1 >= pFndLn->GetTabBoxes().Count() ) ) + if( !nLeft || nRight == pFndLn->GetTabBoxes().Count() ) + { + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + { + nInsPos = pULPara->pInsBox->GetTabLines().Count(); + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pULPara->pInsBox ); + } + } + else if( nLeft ) + { + // es gibt links noch weitere Boxen, also setze Left- + // und Merge-Box in eine Box und Line, fuege davor/dahinter + // eine Line mit Box ein, in die die oberen/unteren Lines + // eingefuegt werden + SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper(); + SwTableBox* pLMBox = new SwTableBox( + (SwTableBoxFmt*)pULPara->pLeftBox->GetFrmFmt(), 0, pInsLine ); + SwTableLine* pLMLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pLMBox ); + pLMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + + pLMBox->GetTabLines().C40_INSERT( SwTableLine, pLMLn, 0 ); + + lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn ); + + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLMBox, 0 ); + + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pLMBox ); + lcl_CalcWidth( pLMBox ); // bereche die Breite der Box + } + else if( nRight+1 < pFndLn->GetTabBoxes().Count() ) + { + // es gibt rechts noch weitere Boxen, also setze Right- + // und Merge-Box in eine Box und Line, fuege davor/dahinter + // eine Line mit Box ein, in die die oberen/unteren Lines + // eingefuegt werden + SwTableLine* pInsLine = pULPara->pRightBox->GetUpper(); + SwTableBox* pRMBox; + if( pULPara->pLeftBox->GetUpper() == pInsLine ) + { + pRMBox = new SwTableBox( + (SwTableBoxFmt*)pULPara->pRightBox->GetFrmFmt(), 0, pInsLine ); + SwTableLine* pRMLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pRMBox ); + pRMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + pRMBox->GetTabLines().C40_INSERT( SwTableLine, pRMLn, 0 ); + + lcl_CpyBoxes( 1, 3, pInsLine->GetTabBoxes(), pRMLn ); + + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 ); + } + else + { + // Left und Merge wurden schon zusammengefuegt, also move + // Right auch mit in die Line + + pInsLine = pULPara->pLeftBox->GetUpper(); + sal_uInt16 nMvPos = pULPara->pRightBox->GetUpper()->GetTabBoxes(). + C40_GETPOS( SwTableBox, pULPara->pRightBox ); + lcl_CpyBoxes( nMvPos, nMvPos+1, + pULPara->pRightBox->GetUpper()->GetTabBoxes(), + pInsLine ); + pRMBox = pInsLine->GetUpper(); + + // sind schon Lines vorhanden, dann muessen diese in eine + // neue Line und Box + nMvPos = pRMBox->GetTabLines().C40_GETPOS( SwTableLine, pInsLine ); + if( pULPara->bUL ? nMvPos + : nMvPos+1 < pRMBox->GetTabLines().Count() ) + { + // alle Lines zu einer neuen Line und Box zusammenfassen + SwTableLine* pNewLn = new SwTableLine( + (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pRMBox ); + pNewLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + pRMBox->GetTabLines().C40_INSERT( SwTableLine, pNewLn, + pULPara->bUL ? nMvPos : nMvPos+1 ); + pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn ); + pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 ); + + sal_uInt16 nPos1, nPos2; + if( pULPara->bUL ) + nPos1 = 0, + nPos2 = nMvPos; + else + nPos1 = nMvPos+2, + nPos2 = pNewLn->GetUpper()->GetTabLines().Count(); + + lcl_CpyLines( nPos1, nPos2, + pNewLn->GetUpper()->GetTabLines(), pRMBox ); + lcl_CalcWidth( pRMBox ); // bereche die Breite der Box + + pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn ); + pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, + pNewLn->GetTabBoxes().Count() ); + } + } + if( pULPara->bUL ) // Upper ? + { + // gibt es noch davor Zeilen, dann move sie + if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) ) + lcl_CpyLines( 0, nPos, *pLines, pRMBox, 0 ); + } + else + // gibt es noch dahinter Zeilen, dann move sie + if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() ) + lcl_CpyLines( nPos+1, pLines->Count(), *pLines, + pRMBox ); + lcl_CalcWidth( pRMBox ); // bereche die Breite der Box + } + else { + ASSERT( sal_False , "Was denn nun" ); + } + } + // Left/Right + else + { + // suche nur die Line, ab der Verschoben werden muss + nStt = pULPara->bUL ? 0 : rpFndLine->GetBoxes().Count()-1; + nEnd = nStt+1; + } + pLines = &pULPara->pInsBox->GetTabLines(); + + SwTableLine* pNewLine = new SwTableLine( + (SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(), 0, pULPara->pInsBox ); + _InsULPara aPara( *pULPara ); // kopieren + aPara.pInsLine = pNewLine; + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( nStt, nEnd, + &lcl_Merge_MoveBox, &aPara ); + if( pNewLine->GetTabBoxes().Count() ) + { + if( USHRT_MAX == nInsPos ) + nInsPos = pLines->Count(); + pLines->C40_INSERT( SwTableLine, pNewLine, nInsPos ); + } + else + delete pNewLine; + + return sal_True; +} + + +sal_Bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes, + SwTableBox* pMergeBox, SwUndoTblMerge* pUndo ) +{ + ASSERT( rBoxes.Count() && pMergeBox, "keine gueltigen Werte" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return sal_False; + + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + // TL_CHART2: splitting/merging of a number of cells or rows will usually make + // the table to complex to be handled with chart. + // Thus we tell the charts to use their own data provider and forget about this table + pDoc->CreateChartInternalDataProviders( this ); + + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + if( pUndo ) + pUndo->SetSelBoxes( rBoxes ); + + //Lines fuer das Layout-Update herausuchen. + aFndBox.SetTableLines( *this ); + aFndBox.DelFrms( *this ); + + _FndBox* pFndBox = &aFndBox; + while( 1 == pFndBox->GetLines().Count() && + 1 == pFndBox->GetLines()[0]->GetBoxes().Count() ) + pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0]; + + SwTableLine* pInsLine = new SwTableLine( + (SwTableLineFmt*)pFndBox->GetLines()[0]->GetLine()->GetFrmFmt(), 0, + !pFndBox->GetUpper() ? 0 : pFndBox->GetBox() ); + pInsLine->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE ); + + // trage die neue Line ein + SwTableLines* pLines = pFndBox->GetUpper() ? + &pFndBox->GetBox()->GetTabLines() : &GetTabLines(); + + SwTableLine* pNewLine = pFndBox->GetLines()[0]->GetLine(); + sal_uInt16 nInsPos = pLines->C40_GETPOS( SwTableLine, pNewLine ); + pLines->C40_INSERT( SwTableLine, pInsLine, nInsPos ); + + SwTableBox* pLeftBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); + SwTableBox* pRightBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine ); + pMergeBox->SetUpper( pInsLine ); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLeftBox, 0 ); + pLeftBox->ClaimFrmFmt(); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pMergeBox, 1 ); + pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRightBox, 2 ); + pRightBox->ClaimFrmFmt(); + + // in diese kommen alle Lines, die ueber dem selektierten Bereich stehen + // Sie bilden also eine Upper/Lower Line + _InsULPara aPara( pTblNd, sal_True, sal_True, pLeftBox, pMergeBox, pRightBox, pInsLine ); + + // move die oben/unten ueberhaengenden Lines vom selektierten Bereich + pFndBox->GetLines()[0]->GetBoxes().ForEach( &lcl_Merge_MoveBox, + &aPara ); + aPara.SetLower( pInsLine ); + sal_uInt16 nEnd = pFndBox->GetLines().Count()-1; + pFndBox->GetLines()[nEnd]->GetBoxes().ForEach( &lcl_Merge_MoveBox, + &aPara ); + + // move die links/rechts hereinreichenden Boxen vom selektierten Bereich + aPara.SetLeft( pLeftBox ); + pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); + + aPara.SetRight( pRightBox ); + pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara ); + + if( !pLeftBox->GetTabLines().Count() ) + _DeleteBox( *this, pLeftBox, 0, sal_False, sal_False ); + else + { + lcl_CalcWidth( pLeftBox ); // bereche die Breite der Box + if( pUndo && pLeftBox->GetSttNd() ) + pUndo->AddNewBox( pLeftBox->GetSttIdx() ); + } + if( !pRightBox->GetTabLines().Count() ) + _DeleteBox( *this, pRightBox, 0, sal_False, sal_False ); + else + { + lcl_CalcWidth( pRightBox ); // bereche die Breite der Box + if( pUndo && pRightBox->GetSttNd() ) + pUndo->AddNewBox( pRightBox->GetSttIdx() ); + } + + DeleteSel( pDoc, rBoxes, 0, 0, sal_False, sal_False ); + + // dann raeume die Struktur dieser Line noch mal auf: + // generell alle Aufraeumen + GCLines(); + + GetTabLines()[0]->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 ); + + aFndBox.MakeFrms( *this ); + + CHECKBOXWIDTH + CHECKTABLELAYOUT + + return sal_True; +} + +// --------------------------------------------------------------- + +void lcl_CheckRowSpan( SwTable &rTbl ) +{ + sal_uInt16 nLineCount = rTbl.GetTabLines().Count(); + sal_uInt16 nMaxSpan = nLineCount; + long nMinSpan = 1; + while( nMaxSpan ) + { + SwTableLine* pLine = rTbl.GetTabLines()[ nLineCount - nMaxSpan ]; + for( sal_uInt16 nBox = 0; nBox < pLine->GetTabBoxes().Count(); ++nBox ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[nBox]; + long nRowSpan = pBox->getRowSpan(); + if( nRowSpan > nMaxSpan ) + pBox->setRowSpan( nMaxSpan ); + else if( nRowSpan < nMinSpan ) + pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan ); + } + --nMaxSpan; + nMinSpan = -nMaxSpan; + } +} + +sal_uInt16 lcl_GetBoxOffset( const _FndBox& rBox ) +{ + // suche die erste Box + const _FndBox* pFirstBox = &rBox; + while( pFirstBox->GetLines().Count() ) + pFirstBox = pFirstBox->GetLines()[ 0 ]->GetBoxes()[ 0 ]; + + sal_uInt16 nRet = 0; + // dann ueber die Lines nach oben die Position bestimmen + const SwTableBox* pBox = pFirstBox->GetBox(); + do { + const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes(); + const SwTableBox* pCmp; + for( sal_uInt16 n = 0; pBox != ( pCmp = rBoxes[ n ] ); ++n ) + nRet = nRet + (sal_uInt16) pCmp->GetFrmFmt()->GetFrmSize().GetWidth(); + pBox = pBox->GetUpper()->GetUpper(); + } while( pBox ); + return nRet; +} + +sal_uInt16 lcl_GetLineWidth( const _FndLine& rLine ) +{ + sal_uInt16 nRet = 0; + for( sal_uInt16 n = rLine.GetBoxes().Count(); n; ) + nRet = nRet + (sal_uInt16)rLine.GetBoxes()[ --n ]->GetBox()->GetFrmFmt() + ->GetFrmSize().GetWidth(); + return nRet; +} + +void lcl_CalcNewWidths( const _FndLines& rFndLines, _CpyPara& rPara ) +{ + rPara.pWidths.reset(); + sal_uInt16 nLineCount = rFndLines.Count(); + if( nLineCount ) + { + rPara.pWidths = boost::shared_ptr< std::vector< std::vector< sal_uLong > > > + ( new std::vector< std::vector< sal_uLong > >( nLineCount )); + // First we collect information about the left/right borders of all + // selected cells + for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) + { + std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ]; + const _FndLine *pFndLine = rFndLines[ nLine ]; + if( pFndLine && pFndLine->GetBoxes().Count() ) + { + const SwTableLine *pLine = pFndLine->GetLine(); + if( pLine && pLine->GetTabBoxes().Count() ) + { + sal_uInt16 nBoxCount = pLine->GetTabBoxes().Count(); + sal_uLong nPos = 0; + // The first selected box... + const SwTableBox *pSel = pFndLine->GetBoxes()[0]->GetBox(); + sal_uInt16 nBox = 0; + // Sum up the width of all boxes before the first selected box + while( nBox < nBoxCount ) + { + SwTableBox* pBox = pLine->GetTabBoxes()[nBox++]; + if( pBox != pSel ) + nPos += pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + else + break; + } + // nPos is now the left border of the first selceted box + if( rPara.nMinLeft > nPos ) + rPara.nMinLeft = nPos; + nBoxCount = pFndLine->GetBoxes().Count(); + rWidth = std::vector< sal_uLong >( nBoxCount+2 ); + rWidth[ 0 ] = nPos; + // Add now the widths of all selected boxes and store + // the positions in the vector + for( nBox = 0; nBox < nBoxCount; ) + { + nPos += pFndLine->GetBoxes()[nBox] + ->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + rWidth[ ++nBox ] = nPos; + } + // nPos: The right border of the last selected box + if( rPara.nMaxRight < nPos ) + rPara.nMaxRight = nPos; + if( nPos <= rWidth[ 0 ] ) + rWidth.clear(); + } + } + } + } + // Second step: calculate the new widths for the copied cells + sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft; + if( nSelSize ) + { + for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine ) + { + std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ]; + sal_uInt16 nCount = (sal_uInt16)rWidth.size(); + if( nCount > 2 ) + { + rWidth[ nCount - 1 ] = rPara.nMaxRight; + sal_uLong nLastPos = 0; + for( sal_uInt16 nBox = 0; nBox < nCount; ++nBox ) + { + sal_uInt64 nNextPos = rWidth[ nBox ]; + nNextPos -= rPara.nMinLeft; + nNextPos *= rPara.nNewSize; + nNextPos /= nSelSize; + rWidth[ nBox ] = (sal_uLong)(nNextPos - nLastPos); + nLastPos = (sal_uLong)nNextPos; + } + } + } + } +} + +sal_Bool lcl_CopyBoxToDoc( const _FndBox*& rpFndBox, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // Calculation of new size + sal_uLong nRealSize; + sal_uLong nDummy1 = 0; + sal_uLong nDummy2 = 0; + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + { + if( pCpyPara->nBoxIdx == 1 ) + nDummy1 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][0]; + nRealSize = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++]; + if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx].size()-1 ) + nDummy2 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx]; + } + else + { + nRealSize = pCpyPara->nNewSize; + nRealSize *= rpFndBox->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + nRealSize /= pCpyPara->nOldSize; + } + + sal_uLong nSize; + bool bDummy = nDummy1 > 0; + if( bDummy ) + nSize = nDummy1; + else + { + nSize = nRealSize; + nRealSize = 0; + } + do + { + // suche das Frame-Format in der Liste aller Frame-Formate + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt() ); + + SwFmtFrmSize aFrmSz; + sal_uInt16 nFndPos; + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ) || + ( aFrmSz = ( aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]).pNewFrmFmt-> + GetFrmSize()).GetWidth() != (SwTwips)nSize ) + { + // es ist noch nicht vorhanden, also kopiere es + aFindFrm.pNewFrmFmt = pCpyPara->pDoc->MakeTableBoxFmt(); + aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndBox->GetBox()->GetFrmFmt() ); + if( !pCpyPara->bCpyCntnt ) + aFindFrm.pNewFrmFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE ); + aFrmSz.SetWidth( nSize ); + aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz ); + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + + SwTableBox* pBox; + if( rpFndBox->GetLines().Count() ) + { + pBox = new SwTableBox( aFindFrm.pNewFrmFmt, + rpFndBox->GetLines().Count(), pCpyPara->pInsLine ); + pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++ ); + _CpyPara aPara( *pCpyPara, pBox ); + aPara.nNewSize = nSize; // hole die Groesse + ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + } + else + { + // erzeuge eine leere Box + pCpyPara->pDoc->GetNodes().InsBoxen( pCpyPara->pTblNd, pCpyPara->pInsLine, + aFindFrm.pNewFrmFmt, + (SwTxtFmtColl*)pCpyPara->pDoc->GetDfltTxtFmtColl(), + 0, pCpyPara->nInsPos ); + pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ]; + if( bDummy ) + pBox->setDummyFlag( true ); + else if( pCpyPara->bCpyCntnt ) + { + // dann kopiere mal den Inhalt in diese leere Box + pBox->setRowSpan( rpFndBox->GetBox()->getRowSpan() ); + + // der Inhalt kopiert wird, dann koennen auch Formeln&Values + // kopiert werden. + { + SfxItemSet aBoxAttrSet( pCpyPara->pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE ); + aBoxAttrSet.Put( rpFndBox->GetBox()->GetFrmFmt()->GetAttrSet() ); + if( aBoxAttrSet.Count() ) + { + const SfxPoolItem* pItem; + SvNumberFormatter* pN = pCpyPara->pDoc->GetNumberFormatter( sal_False ); + if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet. + GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) ) + { + sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); + sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx ); + if( nNewIdx != nOldIdx ) + aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx )); + } + pBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet ); + } + } + SwDoc* pFromDoc = rpFndBox->GetBox()->GetFrmFmt()->GetDoc(); + SwNodeRange aCpyRg( *rpFndBox->GetBox()->GetSttNd(), 1, + *rpFndBox->GetBox()->GetSttNd()->EndOfSectionNode() ); + SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 ); + + pFromDoc->CopyWithFlyInFly( aCpyRg, 0, aInsIdx, sal_False ); + // den initialen TextNode loeschen + pCpyPara->pDoc->GetNodes().Delete( aInsIdx, 1 ); + } + ++pCpyPara->nInsPos; + } + if( nRealSize ) + { + bDummy = false; + nSize = nRealSize; + nRealSize = 0; + } + else + { + bDummy = true; + nSize = nDummy2; + nDummy2 = 0; + } + } + while( nSize ); + return sal_True; +} + +sal_Bool lcl_CopyLineToDoc( const _FndLine*& rpFndLine, void* pPara ) +{ + _CpyPara* pCpyPara = (_CpyPara*)pPara; + + // suche das Format in der Liste aller Formate + _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndLine->GetLine()->GetFrmFmt() ); + sal_uInt16 nFndPos; + if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos )) + { + // es ist noch nicht vorhanden, also kopiere es + aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pCpyPara->pDoc->MakeTableLineFmt(); + aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndLine->GetLine()->GetFrmFmt() ); + pCpyPara->rTabFrmArr.Insert( aFindFrm ); + } + else + aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]; + + SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)aFindFrm.pNewFrmFmt, + rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox ); + if( pCpyPara->pInsBox ) + { + pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ ); + } + else + { + pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine, + pCpyPara->nInsPos++ ); + } + + _CpyPara aPara( *pCpyPara, pNewLine ); + + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + { + aPara.nOldSize = 0; // will not be used + aPara.nBoxIdx = 1; + } + else if( rpFndLine->GetBoxes().Count() == + rpFndLine->GetLine()->GetTabBoxes().Count() ) + { + // hole die Size vom Parent + const SwFrmFmt* pFmt; + + if( rpFndLine->GetLine()->GetUpper() ) + pFmt = rpFndLine->GetLine()->GetUpper()->GetFrmFmt(); + else + pFmt = pCpyPara->pTblNd->GetTable().GetFrmFmt(); + aPara.nOldSize = pFmt->GetFrmSize().GetWidth(); + } + else + // errechne sie + for( sal_uInt16 n = 0; n < rpFndLine->GetBoxes().Count(); ++n ) + aPara.nOldSize += rpFndLine->GetBoxes()[n] + ->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth(); + + ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyBoxToDoc, &aPara ); + if( pCpyPara->pTblNd->GetTable().IsNewModel() ) + ++pCpyPara->nLnIdx; + return sal_True; +} + +sal_Bool SwTable::CopyHeadlineIntoTable( SwTableNode& rTblNd ) +{ + // suche alle Boxen / Lines + SwSelBoxes aSelBoxes; + SwTableBox* pBox = GetTabSortBoxes()[ 0 ]; + pBox = GetTblBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 ); + SelLineFromBox( pBox, aSelBoxes, sal_True ); + + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( aSelBoxes, &aFndBox ); + ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( this ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + GetFrmFmt()->GetDoc()->UpdateTblFlds( &aMsgHnt ); + } + + _CpyTabFrms aCpyFmt; + _CpyPara aPara( &rTblNd, 1, aCpyFmt, sal_True ); + aPara.nNewSize = aPara.nOldSize = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth(); + // dann kopiere mal + if( IsNewModel() ) + lcl_CalcNewWidths( aFndBox.GetLines(), aPara ); + aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + if( rTblNd.GetTable().IsNewModel() ) + { // The copied line must not contain any row span attributes > 1 + SwTableLine* pLine = rTblNd.GetTable().GetTabLines()[0]; + sal_uInt16 nColCount = pLine->GetTabBoxes().Count(); + ASSERT( nColCount, "Empty Table Line" ) + for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol ) + { + SwTableBox* pTableBox = pLine->GetTabBoxes()[nCurrCol]; + ASSERT( pTableBox, "Missing Table Box" ); + pTableBox->setRowSpan( 1 ); + } + } + + return sal_True; +} + +sal_Bool SwTable::MakeCopy( SwDoc* pInsDoc, const SwPosition& rPos, + const SwSelBoxes& rSelBoxes, sal_Bool bCpyNds, + sal_Bool bCpyName ) const +{ + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rSelBoxes, &aFndBox ); + ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); + } + if( !aFndBox.GetLines().Count() ) + return sal_False; + + // erst die Poolvorlagen fuer die Tabelle kopieren, damit die dann + // wirklich kopiert und damit die gueltigen Werte haben. + SwDoc* pSrcDoc = GetFrmFmt()->GetDoc(); + if( pSrcDoc != pInsDoc ) + { + pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE ) ); + pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ) ); + } + + SwTable* pNewTbl = (SwTable*)pInsDoc->InsertTable( + SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ), + rPos, 1, 1, GetFrmFmt()->GetHoriOrient().GetHoriOrient(), + 0, 0, sal_False, IsNewModel() ); + if( !pNewTbl ) + return sal_False; + + SwNodeIndex aIdx( rPos.nNode, -1 ); + SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); + aIdx++; + ASSERT( pTblNd, "wo ist denn nun der TableNode?" ); + + pTblNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() ); + + if( IS_TYPE( SwDDETable, this )) + { + // es wird eine DDE-Tabelle kopiert + // ist im neuen Dokument ueberhaupt der FeldTyp vorhanden ? + SwFieldType* pFldType = pInsDoc->InsertFldType( + *((SwDDETable*)this)->GetDDEFldType() ); + ASSERT( pFldType, "unbekannter FieldType" ); + + // tauschen am Node den Tabellen-Pointer aus + pNewTbl = new SwDDETable( *pNewTbl, + (SwDDEFieldType*)pFldType ); + pTblNd->SetNewTable( pNewTbl, sal_False ); + } + + pNewTbl->GetFrmFmt()->CopyAttrs( *GetFrmFmt() ); + pNewTbl->SetTblChgMode( GetTblChgMode() ); + + //Vernichten der Frms die bereits angelegt wurden. + pTblNd->DelFrms(); + + { + // Tabellen-Formeln in die relative Darstellung umwandeln + SwTableFmlUpdate aMsgHnt( this ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + pSrcDoc->UpdateTblFlds( &aMsgHnt ); + } + + SwTblNumFmtMerge aTNFM( *pSrcDoc, *pInsDoc ); + + // Namen auch kopieren oder neuen eindeutigen erzeugen + if( bCpyName ) + pNewTbl->GetFrmFmt()->SetName( GetFrmFmt()->GetName() ); + + _CpyTabFrms aCpyFmt; + _CpyPara aPara( pTblNd, 1, aCpyFmt, bCpyNds ); + aPara.nNewSize = aPara.nOldSize = GetFrmFmt()->GetFrmSize().GetWidth(); + + if( IsNewModel() ) + lcl_CalcNewWidths( aFndBox.GetLines(), aPara ); + // dann kopiere mal + aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara ); + + // dann setze oben und unten noch die "richtigen" Raender: + { + _FndLine* pFndLn = aFndBox.GetLines()[ 0 ]; + SwTableLine* pLn = pFndLn->GetLine(); + const SwTableLine* pTmp = pLn; + sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp ); + if( USHRT_MAX != nLnPos && nLnPos ) + { + // es gibt eine Line davor + SwCollectTblLineBoxes aLnPara( sal_False, HEADLINE_BORDERCOPY ); + + pLn = GetTabLines()[ nLnPos - 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara ); + + if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ), + lcl_GetLineWidth( *pFndLn )) ) + { + aLnPara.SetValues( sal_True ); + pLn = pNewTbl->GetTabLines()[ 0 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara ); + } + } + + pFndLn = aFndBox.GetLines()[ aFndBox.GetLines().Count() -1 ]; + pLn = pFndLn->GetLine(); + pTmp = pLn; + nLnPos = GetTabLines().GetPos( pTmp ); + if( nLnPos < GetTabLines().Count() - 1 ) + { + // es gibt eine Line dahinter + SwCollectTblLineBoxes aLnPara( sal_True, HEADLINE_BORDERCOPY ); + + pLn = GetTabLines()[ nLnPos + 1 ]; + pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara ); + + if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ), + lcl_GetLineWidth( *pFndLn )) ) + { + aLnPara.SetValues( sal_False ); + pLn = pNewTbl->GetTabLines()[ pNewTbl->GetTabLines().Count()-1 ]; + pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara ); + } + } + } + + // die initiale Box muss noch geloescht werden + _DeleteBox( *pNewTbl, pNewTbl->GetTabLines()[ + pNewTbl->GetTabLines().Count() - 1 ]->GetTabBoxes()[0], + 0, sal_False, sal_False ); + + if( pNewTbl->IsNewModel() ) + lcl_CheckRowSpan( *pNewTbl ); + // Mal kurz aufraeumen: + pNewTbl->GCLines(); + + pTblNd->MakeFrms( &aIdx ); // erzeuge die Frames neu + + CHECKTABLELAYOUT + + return sal_True; +} + + + +// --------------------------------------------------------------- + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableLine::FindNextBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const +{ + const SwTableLine* pLine = this; // fuer M800 + SwTableBox* pBox; + sal_uInt16 nFndPos; + if( GetTabBoxes().Count() && pSrchBox && + USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) && + nFndPos + 1 != GetTabBoxes().Count() ) + { + pBox = GetTabBoxes()[ nFndPos + 1 ]; + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + return pBox; + } + + if( GetUpper() ) + { + nFndPos = GetUpper()->GetTabLines().GetPos( pLine ); + ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" ); + // gibts eine weitere Line + if( nFndPos+1 >= GetUpper()->GetTabLines().Count() ) + return GetUpper()->GetUpper()->FindNextBox( rTbl, GetUpper(), bOvrTblLns ); + pLine = GetUpper()->GetTabLines()[nFndPos+1]; + } + else if( bOvrTblLns ) // ueber die "GrundLines" einer Tabelle ? + { + // suche in der Tabelle nach der naechsten Line + nFndPos = rTbl.GetTabLines().GetPos( pLine ); + if( nFndPos + 1 >= rTbl.GetTabLines().Count() ) + return 0; // es gibt keine weitere Box mehr + + pLine = rTbl.GetTabLines()[ nFndPos+1 ]; + } + else + return 0; + + if( pLine->GetTabBoxes().Count() ) + { + pBox = pLine->GetTabBoxes()[0]; + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + return pBox; + } + return pLine->FindNextBox( rTbl, 0, bOvrTblLns ); +} + +// suche ab dieser Line nach der vorherigen Box +SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const +{ + const SwTableLine* pLine = this; // fuer M800 + SwTableBox* pBox; + sal_uInt16 nFndPos; + if( GetTabBoxes().Count() && pSrchBox && + USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) && + nFndPos ) + { + pBox = GetTabBoxes()[ nFndPos - 1 ]; + while( pBox->GetTabLines().Count() ) + { + pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1]; + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + } + return pBox; + } + + if( GetUpper() ) + { + nFndPos = GetUpper()->GetTabLines().GetPos( pLine ); + ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" ); + // gibts eine weitere Line + if( !nFndPos ) + return GetUpper()->GetUpper()->FindPreviousBox( rTbl, GetUpper(), bOvrTblLns ); + pLine = GetUpper()->GetTabLines()[nFndPos-1]; + } + else if( bOvrTblLns ) // ueber die "GrundLines" einer Tabelle ? + { + // suche in der Tabelle nach der naechsten Line + nFndPos = rTbl.GetTabLines().GetPos( pLine ); + if( !nFndPos ) + return 0; // es gibt keine weitere Box mehr + + pLine = rTbl.GetTabLines()[ nFndPos-1 ]; + } + else + return 0; + + if( pLine->GetTabBoxes().Count() ) + { + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + while( pBox->GetTabLines().Count() ) + { + pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1]; + pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1]; + } + return pBox; + } + return pLine->FindPreviousBox( rTbl, 0, bOvrTblLns ); +} + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableBox::FindNextBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const +{ + if( !pSrchBox && !GetTabLines().Count() ) + return (SwTableBox*)this; + return GetUpper()->FindNextBox( rTbl, pSrchBox ? pSrchBox : this, + bOvrTblLns ); + +} + +// suche ab dieser Line nach der naechsten Box mit Inhalt +SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTbl, + const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const +{ + if( !pSrchBox && !GetTabLines().Count() ) + return (SwTableBox*)this; + return GetUpper()->FindPreviousBox( rTbl, pSrchBox ? pSrchBox : this, + bOvrTblLns ); +} + + +sal_Bool lcl_BoxSetHeadCondColl( const SwTableBox*& rpBox, void* ) +{ + // in der HeadLine sind die Absaetze mit BedingtenVorlage anzupassen + const SwStartNode* pSttNd = rpBox->GetSttNd(); + if( pSttNd ) + pSttNd->CheckSectionCondColl(); + else + ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_LineSetHeadCondColl, 0 ); + return sal_True; +} + +sal_Bool lcl_LineSetHeadCondColl( const SwTableLine*& rpLine, void* ) +{ + ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 ); + return sal_True; +} + +/* */ + +SwTwips lcl_GetDistance( SwTableBox* pBox, sal_Bool bLeft ) +{ + sal_Bool bFirst = sal_True; + SwTwips nRet = 0; + SwTableLine* pLine; + while( pBox && 0 != ( pLine = pBox->GetUpper() ) ) + { + sal_uInt16 nStt = 0, nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + + if( bFirst && !bLeft ) + ++nPos; + bFirst = sal_False; + + while( nStt < nPos ) + nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrmFmt() + ->GetFrmSize().GetWidth(); + pBox = pLine->GetUpper(); + } + return nRet; +} + +sal_Bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + sal_Bool bGreaterBox = sal_False; + + if( bCheck ) + { + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, + nDist, sal_True )) + return sal_False; + + // dann noch mal alle "ContentBoxen" sammeln + if( ( 0 != ( bGreaterBox = TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) || + ( !rParam.bBigger && ( Abs( nDist + (( rParam.nMode && rParam.bLeft ) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) ) ) + { + rParam.bAnyBoxFnd = sal_True; + SwTwips nLowerDiff; + if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode ) + { + // die "anderen Boxen" wurden angepasst, + // also sich um diesen Betrag aendern + nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + nLowerDiff = rParam.nDiff - nLowerDiff; + } + else + nLowerDiff = rParam.nDiff; + + if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY ) + return sal_False; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, nDist, sal_False ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + + if( nLowerDiff || + ( 0 != ( bGreaterBox = !nOldLower && TBLFIX_CHGABS != rParam.nMode && + ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) || + ( Abs( nDist + ( (rParam.nMode && rParam.bLeft) ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY )) + { + // in dieser Spalte ist der Cursor - also verkleinern / vergroessern + SwFmtFrmSize aNew( rSz ); + + if( !nLowerDiff ) + { + if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode ) + { + // die "anderen Boxen" wurden angepasst, + // also sich um diesen Betrag aendern + nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + nLowerDiff = rParam.nDiff - nLowerDiff; + } + else + nLowerDiff = rParam.nDiff; + } + + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth + nLowerDiff ); + else + aNew.SetWidth( nWidth - nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + break; + } + } + + if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide ) + break; + + nDist += nWidth; + + // wenns groesser wird, dann wars das + if( ( TBLFIX_CHGABS == rParam.nMode || !rParam.bLeft ) && + nDist >= rParam.nSide ) + break; + } + return sal_True; +} + +sal_Bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], + rParam, nDist, sal_True )) + return sal_False; + + if( rParam.bBigger && ( TBLFIX_CHGABS == rParam.nMode + ? Abs( nDist - rParam.nSide ) < COLFUZZY + : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY + : nDist >= rParam.nSide - COLFUZZY )) ) + { + rParam.bAnyBoxFnd = sal_True; + SwTwips nDiff; + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nDiff = nWidth; + nDiff *= rParam.nDiff; + nDiff /= rParam.nMaxSize; + } + else + nDiff = rParam.nDiff; + + if( nWidth < nDiff || nWidth - nDiff < MINLAY ) + return sal_False; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], rParam, + nDist, sal_False ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff || + ( TBLFIX_CHGABS == rParam.nMode + ? Abs( nDist - rParam.nSide ) < COLFUZZY + : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY + : nDist >= rParam.nSide - COLFUZZY) + ) ) + { + SwFmtFrmSize aNew( rSz ); + + if( !nLowerDiff ) + { + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nLowerDiff = nWidth; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nMaxSize; + } + else + nLowerDiff = rParam.nDiff; + } + + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth - nLowerDiff ); + else + aNew.SetWidth( nWidth + nLowerDiff ); + + rParam.aShareFmts.SetSize( *pBox, aNew ); + } + } + + nDist += nWidth; + if( ( TBLFIX_CHGABS == rParam.nMode || rParam.bLeft ) && + nDist > rParam.nSide ) + break; + } + return sal_True; +} + +/**/ + +sal_Bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + sal_uInt16 n, nCmp; + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwTableBoxFmt* pFmt = (SwTableBoxFmt*)pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, + nDist, sal_True )) + return sal_False; + + // dann noch mal alle "ContentBoxen" sammeln + if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY ) + nCmp = 1; + else if( nDist + ( rParam.bLeft ? 0 : nWidth/2 ) > rParam.nSide ) + nCmp = 2; + else + nCmp = 0; + + if( nCmp ) + { + rParam.bAnyBoxFnd = sal_True; + if( pFmt->GetProtect().IsCntntProtected() ) + return sal_False; + + if( rParam.bSplittBox && + nWidth - rParam.nDiff <= COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + return sal_False; + + if( pBox->GetSttNd() ) + rParam.aBoxes.Insert( pBox ); + + break; + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, nDist, sal_False ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff ) + nCmp = 1; + else if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth ) + - rParam.nSide ) < COLFUZZY ) + nCmp = 2; + else if( nDist + nWidth / 2 > rParam.nSide ) + nCmp = 3; + else + nCmp = 0; + + if( nCmp ) + { + // in dieser Spalte ist der Cursor - also verkleinern / vergroessern + if( 1 == nCmp ) + { + if( !rParam.bSplittBox ) + { + // die akt. Box auf + SwFmtFrmSize aNew( rSz ); + aNew.SetWidth( nWidth + rParam.nDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + } + } + else + { + ASSERT( pBox->GetSttNd(), "Das muss eine EndBox sein!"); + + if( !rParam.bLeft && 3 != nCmp ) + ++n; + + ::_InsTblBox( pFmt->GetDoc(), rParam.pTblNd, + pLine, pFmt, pBox, n ); + + SwTableBox* pNewBox = rBoxes[ n ]; + SwFmtFrmSize aNew( rSz ); + aNew.SetWidth( rParam.nDiff ); + rParam.aShareFmts.SetSize( *pNewBox, aNew ); + + // Sonderfall: kein Platz in den anderen Boxen + // aber in der Zelle + if( rParam.bSplittBox ) + { + // die akt. Box auf + SwFmtFrmSize aNewSize( rSz ); + aNewSize.SetWidth( nWidth - rParam.nDiff ); + rParam.aShareFmts.SetSize( *pBox, aNewSize ); + } + + // Sonderbehandlung fuer Umrandung die Rechte muss + // entfernt werden + { + const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox(); + if( rBoxItem.GetRight() ) + { + SvxBoxItem aTmp( rBoxItem ); + aTmp.SetLine( 0, BOX_LINE_RIGHT ); + rParam.aShareFmts.SetAttr( rParam.bLeft + ? *pNewBox + : *pBox, aTmp ); + } + } + } + + rParam.nLowerDiff = rParam.nDiff; + break; + } + } + + if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide ) + break; + + nDist += nWidth; + } + return sal_True; +} + +sal_Bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + // Sonderfall: kein Platz in den anderen Boxen aber in der Zelle + if( rParam.bSplittBox ) + return sal_True; + + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + sal_uInt16 n; + + // Tabelle fix, proport. + if( !rParam.nRemainWidth && TBLFIX_CHGPROP == rParam.nMode ) + { + // dann die richtige Breite suchen, auf die sich die relative + // Breitenanpassung bezieht. + SwTwips nTmpDist = nDist; + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTwips nWidth = rBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + if( (nTmpDist + nWidth / 2 ) > rParam.nSide ) + { + rParam.nRemainWidth = rParam.bLeft + ? sal_uInt16(nTmpDist) + : sal_uInt16(rParam.nTblWidth - nTmpDist); + break; + } + nTmpDist += nWidth; + } + } + + for( n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + SwTwips nWidth = rSz.GetWidth(); + + if( bCheck ) + { + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + if( !::lcl_InsOtherBox( pBox->GetTabLines()[ i ], + rParam, nDist, sal_True )) + return sal_False; + + if( + rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide && + (TBLFIX_CHGABS != rParam.nMode || + (n < rBoxes.Count() && + (nDist + nWidth + rBoxes[ n+1 ]-> + GetFrmFmt()->GetFrmSize().GetWidth() / 2) + > rParam.nSide) )) + : (nDist + nWidth / 2 ) > rParam.nSide + ) + { + rParam.bAnyBoxFnd = sal_True; + SwTwips nDiff; + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nDiff = nWidth; + nDiff *= rParam.nDiff; + nDiff /= rParam.nRemainWidth; + + if( nWidth < nDiff || nWidth - nDiff < MINLAY ) + return sal_False; + } + else + { + nDiff = rParam.nDiff; + + // teste ob die linke oder rechte Box gross genug + // ist, um den Platz abzugeben! + // es wird davor oder dahinter eine Box eingefuegt! + SwTwips nTmpWidth = nWidth; + if( rParam.bLeft && pBox->GetUpper()->GetUpper() ) + { + const SwTableBox* pTmpBox = pBox; + sal_uInt16 nBoxPos = n; + while( !nBoxPos && pTmpBox->GetUpper()->GetUpper() ) + { + pTmpBox = pTmpBox->GetUpper()->GetUpper(); + nBoxPos = pTmpBox->GetUpper()->GetTabBoxes().GetPos( pTmpBox ); + } +// if( nBoxPos ) + nTmpWidth = pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth(); +// else +// nTmpWidth = 0; + } + + if( nTmpWidth < nDiff || nTmpWidth - nDiff < MINLAY ) + return sal_False; + break; + } + } + } + else + { + SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff; + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + { + rParam.nLowerDiff = 0; + lcl_InsOtherBox( pBox->GetTabLines()[ i ], rParam, + nDist, sal_False ); + + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + } + rParam.nLowerDiff = nOldLower; + + if( nLowerDiff || + (rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide && + (TBLFIX_CHGABS != rParam.nMode || + (n < rBoxes.Count() && + (nDist + nWidth + rBoxes[ n+1 ]-> + GetFrmFmt()->GetFrmSize().GetWidth() / 2) + > rParam.nSide) )) + : (nDist + nWidth / 2 ) > rParam.nSide )) + { + if( !nLowerDiff ) + { + if( TBLFIX_CHGPROP == rParam.nMode ) // Tabelle fix, proport. + { + // relativ berechnen + nLowerDiff = nWidth; + nLowerDiff *= rParam.nDiff; + nLowerDiff /= rParam.nRemainWidth; + } + else + nLowerDiff = rParam.nDiff; + } + + SwFmtFrmSize aNew( rSz ); + rParam.nLowerDiff += nLowerDiff; + + if( rParam.bBigger ) + aNew.SetWidth( nWidth - nLowerDiff ); + else + aNew.SetWidth( nWidth + nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( TBLFIX_CHGABS == rParam.nMode ) + break; + } + } + + nDist += nWidth; + } + return sal_True; +} + + +// das Ergebnis des Positions Vergleiches +// POS_BEFORE, // Box liegt davor +// POS_BEHIND, // Box liegt dahinter +// POS_INSIDE, // Box liegt vollstaendig in Start/End +// POS_OUTSIDE, // Box ueberlappt Start/End vollstaendig +// POS_EQUAL, // Box und Start/End sind gleich +// POS_OVERLAP_BEFORE, // Box ueberlappt den Start +// POS_OVERLAP_BEHIND // Box ueberlappt das Ende + +SwComparePosition _CheckBoxInRange( sal_uInt16 nStt, sal_uInt16 nEnd, + sal_uInt16 nBoxStt, sal_uInt16 nBoxEnd ) +{ +// COLFUZZY noch beachten!! + SwComparePosition nRet; + if( nBoxStt + COLFUZZY < nStt ) + { + if( nBoxEnd > nStt + COLFUZZY ) + { + if( nBoxEnd >= nEnd + COLFUZZY ) + nRet = POS_OUTSIDE; + else + nRet = POS_OVERLAP_BEFORE; + } + else + nRet = POS_BEFORE; + } + else if( nEnd > nBoxStt + COLFUZZY ) + { + if( nEnd + COLFUZZY >= nBoxEnd ) + { + if( COLFUZZY > Abs( long(nEnd) - long(nBoxEnd) ) && + COLFUZZY > Abs( long(nStt) - long(nBoxStt) ) ) + nRet = POS_EQUAL; + else + nRet = POS_INSIDE; + } + else + nRet = POS_OVERLAP_BEHIND; + } + else + nRet = POS_BEHIND; + + return nRet; +} + +void lcl_DelSelBox_CorrLowers( SwTableLine& rLine, CR_SetBoxWidth& rParam, + SwTwips nWidth ) +{ + // 1. Schritt die eigene Breite feststellen + SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + SwTwips nBoxWidth = 0; + sal_uInt16 n; + + for( n = rBoxes.Count(); n; ) + nBoxWidth += rBoxes[ --n ]->GetFrmFmt()->GetFrmSize().GetWidth(); + + if( COLFUZZY < Abs( nWidth - nBoxWidth )) + { + // sie muessen also angepasst werden + for( n = rBoxes.Count(); n; ) + { + SwTableBox* pBox = rBoxes[ --n ]; + SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() ); + long nDiff = aNew.GetWidth(); + nDiff *= nWidth; + nDiff /= nBoxWidth; + aNew.SetWidth( nDiff ); + + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( !pBox->GetSttNd() ) + { + // hat selbst auch Lower, also auch die anpassen + for( sal_uInt16 i = pBox->GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *pBox->GetTabLines()[ --i ], + rParam, nDiff ); + } + } + } +} + +void lcl_ChgBoxSize( SwTableBox& rBox, CR_SetBoxWidth& rParam, + const SwFmtFrmSize& rOldSz, + sal_uInt16& rDelWidth, SwTwips nDist ) +{ + long nDiff = 0; + sal_Bool bSetSize = sal_False; + + switch( rParam.nMode ) + { + case TBLFIX_CHGABS: // Tabelle feste Breite, den Nachbar andern + nDiff = rDelWidth + rParam.nLowerDiff; + bSetSize = sal_True; + break; + + case TBLFIX_CHGPROP: // Tabelle feste Breite, alle Nachbarn aendern + if( !rParam.nRemainWidth ) + { + // dann kurz berechnen: + if( rParam.bLeft ) + rParam.nRemainWidth = sal_uInt16(nDist); + else + rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist); + } + + // relativ berechnen + nDiff = rOldSz.GetWidth(); + nDiff *= rDelWidth + rParam.nLowerDiff; + nDiff /= rParam.nRemainWidth; + + bSetSize = sal_True; + break; + + case TBLVAR_CHGABS: // Tabelle variable, alle Nachbarn aendern + if( COLFUZZY < Abs( rParam.nBoxWidth - + ( rDelWidth + rParam.nLowerDiff ))) + { + nDiff = rDelWidth + rParam.nLowerDiff - rParam.nBoxWidth; + if( 0 < nDiff ) + rDelWidth = rDelWidth - sal_uInt16(nDiff); + else + rDelWidth = rDelWidth + sal_uInt16(-nDiff); + bSetSize = sal_True; + } + break; + } + + if( bSetSize ) + { + SwFmtFrmSize aNew( rOldSz ); + aNew.SetWidth( aNew.GetWidth() + nDiff ); + rParam.aShareFmts.SetSize( rBox, aNew ); + + // dann leider nochmals die Lower anpassen + for( sal_uInt16 i = rBox.GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *rBox.GetTabLines()[ --i ], rParam, + aNew.GetWidth() ); + } +} + +sal_Bool lcl_DeleteBox_Rekursiv( CR_SetBoxWidth& rParam, SwTableBox& rBox, + sal_Bool bCheck ) +{ + sal_Bool bRet = sal_True; + if( rBox.GetSttNd() ) + { + if( bCheck ) + { + rParam.bAnyBoxFnd = sal_True; + if( rBox.GetFrmFmt()->GetProtect().IsCntntProtected() ) + bRet = sal_False; + else + { + SwTableBox* pBox = &rBox; + rParam.aBoxes.Insert( pBox ); + } + } + else + ::_DeleteBox( rParam.pTblNd->GetTable(), &rBox, + rParam.pUndo, sal_False, sal_True, &rParam.aShareFmts ); + } + else + { + // die muessen leider alle sequentiel ueber die + // Contentboxen geloescht werden + for( sal_uInt16 i = rBox.GetTabLines().Count(); i; ) + { + SwTableLine& rLine = *rBox.GetTabLines()[ --i ]; + for( sal_uInt16 n = rLine.GetTabBoxes().Count(); n; ) + if( !::lcl_DeleteBox_Rekursiv( rParam, + *rLine.GetTabBoxes()[ --n ], bCheck )) + return sal_False; + } + } + return bRet; +} + +sal_Bool lcl_DelSelBox( SwTableLine* pTabLine, CR_SetBoxWidth& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + SwTableBoxes& rBoxes = pTabLine->GetTabBoxes(); + sal_uInt16 n, nCntEnd, nBoxChkStt, nBoxChkEnd, nDelWidth = 0; + if( rParam.bLeft ) + { + n = rBoxes.Count(); + nCntEnd = 0; + nBoxChkStt = (sal_uInt16)rParam.nSide; + nBoxChkEnd = static_cast<sal_uInt16>(rParam.nSide + rParam.nBoxWidth); + } + else + { + n = 0; + nCntEnd = rBoxes.Count(); + nBoxChkStt = static_cast<sal_uInt16>(rParam.nSide - rParam.nBoxWidth); + nBoxChkEnd = (sal_uInt16)rParam.nSide; + } + + + while( n != nCntEnd ) + { + SwTableBox* pBox; + if( rParam.bLeft ) + pBox = rBoxes[ --n ]; + else + pBox = rBoxes[ n++ ]; + + SwFrmFmt* pFmt = pBox->GetFrmFmt(); + const SwFmtFrmSize& rSz = pFmt->GetFrmSize(); + long nWidth = rSz.GetWidth(); + sal_Bool bDelBox = sal_False, bChgLowers = sal_False; + + // die Boxenbreite testen und entpsrechend reagieren + SwComparePosition ePosType = ::_CheckBoxInRange( + nBoxChkStt, nBoxChkEnd, + sal_uInt16(rParam.bLeft ? nDist - nWidth : nDist), + sal_uInt16(rParam.bLeft ? nDist : nDist + nWidth)); + + switch( ePosType ) + { + case POS_BEFORE: + if( bCheck ) + { + if( rParam.bLeft ) + return sal_True; + } + else if( rParam.bLeft ) + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + break; + + case POS_BEHIND: + if( bCheck ) + { + if( !rParam.bLeft ) + return sal_True; + } + else if( !rParam.bLeft ) + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + break; + + case POS_OUTSIDE: // Box ueberlappt Start/End vollstaendig + case POS_INSIDE: // Box liegt vollstaendig in Start/End + case POS_EQUAL: // Box und Start/End sind gleich + bDelBox = sal_True; + break; + + case POS_OVERLAP_BEFORE: // Box ueberlappt den Start + if( nBoxChkStt <= ( nDist + (rParam.bLeft ? - nWidth / 2 + : nWidth / 2 ))) + { + if( !pBox->GetSttNd() ) + bChgLowers = sal_True; + else + bDelBox = sal_True; + } + else if( !bCheck && rParam.bLeft ) + { + if( !pBox->GetSttNd() ) + bChgLowers = sal_True; + else + { + ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist ); + if( TBLFIX_CHGABS == rParam.nMode ) + n = nCntEnd; + } + } + break; + + case POS_OVERLAP_BEHIND: // Box ueberlappt das Ende + // JP 10.02.99: + // generell loeschen oder wie beim OVERLAP_Before nur die, die + // bis zur Haelfte in die "Loesch-"Box reicht ??? + if( !pBox->GetSttNd() ) + bChgLowers = sal_True; + else + bDelBox = sal_True; + break; + default: break; + } + + if( bDelBox ) + { + nDelWidth = nDelWidth + sal_uInt16(nWidth); + if( bCheck ) + { + // die letzte/erste Box kann nur bei Tbl-Var geloescht werden, + // wenn diese so gross ist, wie die Aenderung an der Tabelle + if( (( TBLVAR_CHGABS != rParam.nMode || + nDelWidth != rParam.nBoxWidth ) && + COLFUZZY > Abs( rParam.bLeft + ? nWidth - nDist + : (nDist + nWidth - rParam.nTblWidth ))) + || !::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ) ) + return sal_False; + + if( pFmt->GetProtect().IsCntntProtected() ) + return sal_False; + } + else + { + ::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ); + + if( !rParam.bLeft ) + --n, --nCntEnd; + } + } + else if( bChgLowers ) + { + sal_Bool bFirst = sal_True, bCorrLowers = sal_False; + long nLowerDiff = 0; + long nOldLower = rParam.nLowerDiff; + sal_uInt16 nOldRemain = rParam.nRemainWidth; + sal_uInt16 i; + + for( i = pBox->GetTabLines().Count(); i; ) + { + rParam.nLowerDiff = nDelWidth + nOldLower; + rParam.nRemainWidth = nOldRemain; + SwTableLine* pLine = pBox->GetTabLines()[ --i ]; + if( !::lcl_DelSelBox( pLine, rParam, nDist, bCheck )) + return sal_False; + + // gibt es die Box und die darin enthaltenen Lines noch?? + if( n < rBoxes.Count() && + pBox == rBoxes[ rParam.bLeft ? n : n-1 ] && + i < pBox->GetTabLines().Count() && + pLine == pBox->GetTabLines()[ i ] ) + { + if( !bFirst && !bCorrLowers && + COLFUZZY < Abs( nLowerDiff - rParam.nLowerDiff ) ) + bCorrLowers = sal_True; + + // die groesste "loesch" Breite entscheidet, aber nur wenn + // nicht die gesamte Line geloescht wurde + if( nLowerDiff < rParam.nLowerDiff ) + nLowerDiff = rParam.nLowerDiff; + + bFirst = sal_False; + } + } + rParam.nLowerDiff = nOldLower; + rParam.nRemainWidth = nOldRemain; + + // wurden alle Boxen geloescht? Dann ist die DelBreite natuerlich + // die Boxenbreite + if( !nLowerDiff ) + nLowerDiff = nWidth; + + // DelBreite anpassen!! + nDelWidth = nDelWidth + sal_uInt16(nLowerDiff); + + if( !bCheck ) + { + // wurde die Box schon entfernt? + if( n > rBoxes.Count() || + pBox != rBoxes[ ( rParam.bLeft ? n : n-1 ) ] ) + { + // dann beim Loeschen nach rechts die Laufvar. anpassen + if( !rParam.bLeft ) + --n, --nCntEnd; + } + else + { + // sonst muss die Groesse der Box angepasst werden + SwFmtFrmSize aNew( rSz ); + sal_Bool bCorrRel = sal_False; + + if( TBLVAR_CHGABS != rParam.nMode ) + { + switch( ePosType ) + { + case POS_OVERLAP_BEFORE: // Box ueberlappt den Start + if( TBLFIX_CHGPROP == rParam.nMode ) + bCorrRel = rParam.bLeft; + else if( rParam.bLeft ) // TBLFIX_CHGABS + { + nLowerDiff = nLowerDiff - nDelWidth; + bCorrLowers = sal_True; + n = nCntEnd; + } + break; + + case POS_OVERLAP_BEHIND: // Box ueberlappt das Ende + if( TBLFIX_CHGPROP == rParam.nMode ) + bCorrRel = !rParam.bLeft; + else if( !rParam.bLeft ) // TBLFIX_CHGABS + { + nLowerDiff = nLowerDiff - nDelWidth; + bCorrLowers = sal_True; + n = nCntEnd; + } + break; + + default: + ASSERT( !pBox, "hier sollte man nie hinkommen" ); + break; + } + } + + if( bCorrRel ) + { + if( !rParam.nRemainWidth ) + { + // dann kurz berechnen: + if( rParam.bLeft ) + rParam.nRemainWidth = sal_uInt16(nDist - nLowerDiff); + else + rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist + - nLowerDiff ); + } + + long nDiff = aNew.GetWidth() - nLowerDiff; + nDiff *= nDelWidth + rParam.nLowerDiff; + nDiff /= rParam.nRemainWidth; + + aNew.SetWidth( aNew.GetWidth() - nLowerDiff + nDiff ); + } + else + aNew.SetWidth( aNew.GetWidth() - nLowerDiff ); + rParam.aShareFmts.SetSize( *pBox, aNew ); + + if( bCorrLowers ) + { + // dann leider nochmals die Lower anpassen + for( i = pBox->GetTabLines().Count(); i; ) + ::lcl_DelSelBox_CorrLowers( *pBox-> + GetTabLines()[ --i ], rParam, aNew.GetWidth() ); + } + } + } + } + + if( rParam.bLeft ) + nDist -= nWidth; + else + nDist += nWidth; + } + rParam.nLowerDiff = nDelWidth; + return sal_True; +} + +// Dummy Funktion fuer die Methode SetColWidth +sal_Bool lcl_DelOtherBox( SwTableLine* , CR_SetBoxWidth& , SwTwips , sal_Bool ) +{ + return sal_True; +} + +/**/ + +void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam ) +{ + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox* pBox = rBoxes[ n ]; + + SwFmtFrmSize aSz( pBox->GetFrmFmt()->GetFrmSize() ); + SwTwips nWidth = aSz.GetWidth(); + nWidth *= rParam.nDiff; + nWidth /= rParam.nMaxSize; + aSz.SetWidth( nWidth ); + rParam.aShareFmts.SetSize( *pBox, aSz ); + + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + ::lcl_AjustLines( pBox->GetTabLines()[ i ], rParam ); + } +} + +#if defined(DBG_UTIL) || defined( JP_DEBUG ) + +void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize ) +{ + const SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + + SwTwips nAktSize = 0; + // checke doch mal ob die Tabellen korrekte Breiten haben + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + const SwTableBox* pBox = rBoxes[ n ]; + const SwTwips nBoxW = pBox->GetFrmFmt()->GetFrmSize().GetWidth(); + nAktSize += nBoxW; + + for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i ) + _CheckBoxWidth( *pBox->GetTabLines()[ i ], nBoxW ); + } + + if( Abs( nAktSize - nSize ) > ( COLFUZZY * rBoxes.Count() ) ) + { + DBG_ERROR( "Boxen der Line zu klein/gross" ); +#if defined( WNT ) && defined( JP_DEBUG ) + __asm int 3; +#endif + } +} + +#endif + +_FndBox* lcl_SaveInsDelData( CR_SetBoxWidth& rParam, SwUndo** ppUndo, + SwTableSortBoxes& rTmpLst, SwTwips nDistStt ) +{ + // suche alle Boxen / Lines + SwTable& rTbl = rParam.pTblNd->GetTable(); + + if( !rParam.aBoxes.Count() ) + { + // erstmal die Boxen besorgen ! + if( rParam.bBigger ) + for( sal_uInt16 n = 0; n < rTbl.GetTabLines().Count(); ++n ) + ::lcl_DelSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, sal_True ); + else + for( sal_uInt16 n = 0; n < rTbl.GetTabLines().Count(); ++n ) + ::lcl_InsSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, sal_True ); + } + + // loeschen der gesamten Tabelle verhindern + if( rParam.bBigger && rParam.aBoxes.Count() == + rTbl.GetTabSortBoxes().Count() ) + return 0; + + _FndBox* pFndBox = new _FndBox( 0, 0 ); + if( rParam.bBigger ) + pFndBox->SetTableLines( rParam.aBoxes, rTbl ); + else + { + _FndPara aPara( rParam.aBoxes, pFndBox ); + rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" ); + pFndBox->SetTableLines( rTbl ); + + if( ppUndo ) + rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + //Lines fuer das Layout-Update herausuchen. + pFndBox->DelFrms( rTbl ); + + // TL_CHART2: this function gest called from SetColWidth exclusively, + // thus it is currently speculated that nothing needs to be done here. + // Note: that SetColWidth is currently not completely understood though :-( + + return pFndBox; +} + +sal_Bool SwTable::SetColWidth( SwTableBox& rAktBox, sal_uInt16 eType, + SwTwips nAbsDiff, SwTwips nRelDiff, SwUndo** ppUndo ) +{ + SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen + + const SwFmtFrmSize& rSz = GetFrmFmt()->GetFrmSize(); + const SvxLRSpaceItem& rLR = GetFrmFmt()->GetLRSpace(); + + _FndBox* pFndBox = 0; // fuers Einfuegen/Loeschen + SwTableSortBoxes aTmpLst( 0, 5 ); // fuers Undo + sal_Bool bBigger, + bRet = sal_False, + bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ), + bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ); + sal_uInt16 n; + sal_uLong nBoxIdx = rAktBox.GetSttIdx(); + + // bestimme die akt. Kante der Box + // wird nur fuer die Breitenmanipulation benoetigt! + const SwTwips nDist = ::lcl_GetDistance( &rAktBox, bLeft ); + SwTwips nDistStt = 0; + CR_SetBoxWidth aParam( eType, nRelDiff, nDist, rSz.GetWidth(), + bLeft ? nDist : rSz.GetWidth() - nDist, + (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() ); + bBigger = aParam.bBigger; + + FN_lcl_SetBoxWidth fnSelBox, fnOtherBox; + if( bInsDel ) + { + if( bBigger ) + { + fnSelBox = lcl_DelSelBox; + fnOtherBox = lcl_DelOtherBox; + aParam.nBoxWidth = (sal_uInt16)rAktBox.GetFrmFmt()->GetFrmSize().GetWidth(); + if( bLeft ) + nDistStt = rSz.GetWidth(); + } + else + { + fnSelBox = lcl_InsSelBox; + fnOtherBox = lcl_InsOtherBox; + } + } + else + { + fnSelBox = lcl_SetSelBoxWidth; + fnOtherBox = lcl_SetOtherBoxWidth; + } + + + switch( eType & 0xff ) + { + case nsTblChgWidthHeightType::WH_COL_RIGHT: + case nsTblChgWidthHeightType::WH_COL_LEFT: + if( TBLVAR_CHGABS == eTblChgMode ) + { + if( bInsDel ) + bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + sal_Bool bChgLRSpace = sal_True; + if( bBigger ) + { + if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) && + !rSz.GetWidthPercent() ) + { + bRet = rSz.GetWidth() < USHRT_MAX - nRelDiff; + bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff + : rLR.GetRight() >= nAbsDiff; + } + else + bRet = bLeft ? rLR.GetLeft() >= nAbsDiff + : rLR.GetRight() >= nAbsDiff; + + if( !bRet && bInsDel && + // auf der anderen Seite Platz? + ( bLeft ? rLR.GetRight() >= nAbsDiff + : rLR.GetLeft() >= nAbsDiff )) + { + bRet = sal_True; bLeft = !bLeft; + } + + if( !bRet ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGPROP; + + bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff, + ppUndo ); + eTblChgMode = eOld; + return bRet; + } + } + else + { + bRet = sal_True; + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True )) + { + bRet = sal_False; + break; + } + } + } + + if( bRet ) + { + if( bInsDel ) + { + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, + aTmpLst, nDistStt ); + if( aParam.bBigger && aParam.aBoxes.Count() == + aSortCntBoxes.Count() ) + { + // dies gesamte Tabelle soll geloescht werden!! + GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes ); + return sal_False; + } + + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_COL_DELETE + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True ); + + long nFrmWidth = LONG_MAX; + LockModify(); + SwFmtFrmSize aSz( rSz ); + SvxLRSpaceItem aLR( rLR ); + if( bBigger ) + { + // falls die Tabelle keinen Platz zum Wachsen hat, dann + // muessen wir welchen schaffen! + if( aSz.GetWidth() + nRelDiff > USHRT_MAX ) + { + // dann mal herunterbrechen auf USHRT_MAX / 2 + CR_SetBoxWidth aTmpPara( 0, aSz.GetWidth() / 2, + 0, aSz.GetWidth(), aSz.GetWidth(), aParam.pTblNd ); + for( sal_uInt16 nLn = 0; nLn < aLines.Count(); ++nLn ) + ::lcl_AjustLines( aLines[ nLn ], aTmpPara ); + aSz.SetWidth( aSz.GetWidth() / 2 ); + aParam.nDiff = nRelDiff /= 2; + aParam.nSide /= 2; + aParam.nMaxSize /= 2; + } + + if( bLeft ) + aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) ); + else + aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) ); + } + else if( bLeft ) + aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) ); + else + aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) ); + + if( bChgLRSpace ) + GetFrmFmt()->SetFmtAttr( aLR ); + const SwFmtHoriOrient& rHOri = GetFrmFmt()->GetHoriOrient(); + if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() || + (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) || + (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight())) + { + SwFmtHoriOrient aHOri( rHOri ); + aHOri.SetHoriOrient( text::HoriOrientation::NONE ); + GetFrmFmt()->SetFmtAttr( aHOri ); + + // sollte die Tabelle noch auf relativen Werten + // (USHRT_MAX) stehen dann muss es jetzt auf absolute + // umgerechnet werden. Bug 61494 + if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) && + !rSz.GetWidthPercent() ) + { + SwTabFrm* pTabFrm = (SwTabFrm*)SwClientIter( + *GetFrmFmt() ).First( TYPE( SwTabFrm )); + if( pTabFrm && + pTabFrm->Prt().Width() != rSz.GetWidth() ) + { + nFrmWidth = pTabFrm->Prt().Width(); + if( bBigger ) + nFrmWidth += nAbsDiff; + else + nFrmWidth -= nAbsDiff; + } + } + } + + if( bBigger ) + aSz.SetWidth( aSz.GetWidth() + nRelDiff ); + else + aSz.SetWidth( aSz.GetWidth() - nRelDiff ); + + if( rSz.GetWidthPercent() ) + aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) / + ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft()))); + + GetFrmFmt()->SetFmtAttr( aSz ); + aParam.nTblWidth = sal_uInt16( aSz.GetWidth() ); + + UnlockModify(); + + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False ); + } + + // sollte die Tabelle noch auf relativen Werten + // (USHRT_MAX) stehen dann muss es jetzt auf absolute + // umgerechnet werden. Bug 61494 + if( LONG_MAX != nFrmWidth ) + { + SwFmtFrmSize aAbsSz( aSz ); + aAbsSz.SetWidth( nFrmWidth ); + GetFrmFmt()->SetFmtAttr( aAbsSz ); + } + } + } + else if( bInsDel || + ( bLeft ? nDist : Abs( rSz.GetWidth() - nDist ) > COLFUZZY ) ) + { + bRet = sal_True; + if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel ) + aParam.bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + if( bInsDel ) + { + if( aParam.bBigger ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True )) + { + bRet = sal_False; + break; + } + } + } + else + { + if( 0 != ( bRet = bLeft ? nDist != 0 + : ( rSz.GetWidth() - nDist ) > COLFUZZY ) ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnOtherBox)( aLines[ n ], aParam, 0, sal_True )) + { + bRet = sal_False; + break; + } + } + if( bRet && !aParam.bAnyBoxFnd ) + bRet = sal_False; + } + + if( !bRet && rAktBox.GetFrmFmt()->GetFrmSize().GetWidth() + - nRelDiff > COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + { + // dann den Platz von der akt. Zelle nehmen + aParam.bSplittBox = sal_True; + // aber das muss auch mal getestet werden! + bRet = sal_True; + + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True )) + { + bRet = sal_False; + break; + } + } + } + } + } + else if( aParam.bBigger ) + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnOtherBox)( aLines[ n ], aParam, 0, sal_True )) + { + bRet = sal_False; + break; + } + } + } + else + { + for( n = 0; n < aLines.Count(); ++n ) + { + aParam.LoopClear(); + if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True )) + { + bRet = sal_False; + break; + } + } + } + + // wenn ja, dann setzen + if( bRet ) + { + CR_SetBoxWidth aParam1( aParam ); + if( bInsDel ) + { + aParam1.bBigger = !aParam.bBigger; + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, + aTmpLst, nDistStt ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_TABLE_DELBOX + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True ); + + if( bInsDel + ? ( TBLFIX_CHGABS == eTblChgMode ? bLeft : bLeft ) + : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) ) + { + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + aParam1.LoopClear(); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False ); + (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, sal_False ); + } + } + else + for( n = aLines.Count(); n; ) + { + --n; + aParam.LoopClear(); + aParam1.LoopClear(); + (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, sal_False ); + (*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False ); + } + } + } + break; + + case nsTblChgWidthHeightType::WH_CELL_RIGHT: + case nsTblChgWidthHeightType::WH_CELL_LEFT: + if( TBLVAR_CHGABS == eTblChgMode ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> Nachbarn + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGABS; + + bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff, + ppUndo ); + eTblChgMode = eOld; + return bRet; + } + else if( bInsDel || ( bLeft ? nDist + : (rSz.GetWidth() - nDist) > COLFUZZY )) + { + if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel ) + aParam.bBigger = !bBigger; + + // erstmal testen, ob ueberhaupt Platz ist + SwTableBox* pBox = &rAktBox; + SwTableLine* pLine = rAktBox.GetUpper(); + while( pLine->GetUpper() ) + { + sal_uInt16 nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox ); + if( bLeft ? nPos : nPos + 1 != pLine->GetTabBoxes().Count() ) + break; + + pBox = pLine->GetUpper(); + pLine = pBox->GetUpper(); + } + + if( pLine->GetUpper() ) + { + // dann muss die Distanz wieder korriegiert werden! + aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), sal_True ); + + if( bLeft ) + aParam.nMaxSize = aParam.nSide; + else + aParam.nMaxSize = pLine->GetUpper()->GetFrmFmt()-> + GetFrmSize().GetWidth() - aParam.nSide; + } + + // erstmal testen, ob ueberhaupt Platz ist + if( bInsDel ) + { + if( 0 != ( bRet = bLeft ? nDist != 0 + : ( rSz.GetWidth() - nDist ) > COLFUZZY ) && + !aParam.bBigger ) + { + bRet = (*fnOtherBox)( pLine, aParam, 0, sal_True ); + if( bRet && !aParam.bAnyBoxFnd ) + bRet = sal_False; + } + + if( !bRet && !aParam.bBigger && rAktBox.GetFrmFmt()-> + GetFrmSize().GetWidth() - nRelDiff > COLFUZZY + + ( 567 / 2 /* min. 0,5 cm Platz lassen*/) ) + { + // dann den Platz von der akt. Zelle nehmen + aParam.bSplittBox = sal_True; + bRet = sal_True; + } + } + else + { + FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox; + bRet = (*fnTmp)( pLine, aParam, nDistStt, sal_True ); + } + + // wenn ja, dann setzen + if( bRet ) + { + CR_SetBoxWidth aParam1( aParam ); + if( bInsDel ) + { + aParam1.bBigger = !aParam.bBigger; + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst, nDistStt ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + aParam.bBigger ? UNDO_TABLE_DELBOX + : UNDO_TABLE_INSCOL ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True ); + + if( bInsDel + ? ( TBLFIX_CHGABS == eTblChgMode ? (bBigger && bLeft) : bLeft ) + : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) ) + { + (*fnSelBox)( pLine, aParam, nDistStt, sal_False ); + (*fnOtherBox)( pLine, aParam1, nDistStt, sal_False ); + } + else + { + (*fnOtherBox)( pLine, aParam1, nDistStt, sal_False ); + (*fnSelBox)( pLine, aParam, nDistStt, sal_False ); + } + } + } + break; + + } + + if( pFndBox ) + { + // dann raeume die Struktur aller Lines auf + GCLines(); + + //Layout updaten + if( !bBigger || pFndBox->AreLinesToRestore( *this ) ) + pFndBox->MakeFrms( *this ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + // The function name hints that nothing needs to be done, on the other + // hand there is a case where sth gets deleted. :-( + + delete pFndBox; + + if( ppUndo && *ppUndo ) + { + aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType, + nAbsDiff, nRelDiff ); + if( !aParam.bBigger ) + aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst ); + } + } + + if( bRet ) + { + CHECKBOXWIDTH + CHECKTABLELAYOUT + } + + return bRet; +} +/* */ + +_FndBox* lcl_SaveInsDelData( CR_SetLineHeight& rParam, SwUndo** ppUndo, + SwTableSortBoxes& rTmpLst ) +{ + // suche alle Boxen / Lines + SwTable& rTbl = rParam.pTblNd->GetTable(); + + ASSERT( rParam.aBoxes.Count(), "ohne Boxen ist nichts zu machen!" ); + + // loeschen der gesamten Tabelle verhindern + if( !rParam.bBigger && rParam.aBoxes.Count() == + rTbl.GetTabSortBoxes().Count() ) + return 0; + + _FndBox* pFndBox = new _FndBox( 0, 0 ); + if( !rParam.bBigger ) + pFndBox->SetTableLines( rParam.aBoxes, rTbl ); + else + { + _FndPara aPara( rParam.aBoxes, pFndBox ); + rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); + ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" ); + pFndBox->SetTableLines( rTbl ); + + if( ppUndo ) + rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() ); + } + + //Lines fuer das Layout-Update heraussuchen. + pFndBox->DelFrms( rTbl ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + + return pFndBox; +} + +void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight, + sal_Bool bMinSize ) +{ + SwLayoutFrm* pLineFrm = GetRowFrm( rLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + SwFrmFmt* pFmt = rLine.ClaimFrmFmt(); + + SwTwips nMyNewH, nMyOldH = pLineFrm->Frm().Height(); + if( !nOldHeight ) // die BaseLine und absolut + nMyNewH = nMyOldH + nNewHeight; + else + { + // moeglichst genau rechnen + Fraction aTmp( nMyOldH ); + aTmp *= Fraction( nNewHeight, nOldHeight ); + aTmp += Fraction( 1, 2 ); // ggfs. aufrunden + nMyNewH = aTmp; + } + + SwFrmSize eSize = ATT_MIN_SIZE; + if( !bMinSize && + ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrm ) + ROWFUZZY )) + eSize = ATT_FIX_SIZE; + + pFmt->SetFmtAttr( SwFmtFrmSize( eSize, 0, nMyNewH ) ); + + // erst alle inneren anpassen + SwTableBoxes& rBoxes = rLine.GetTabBoxes(); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTableBox& rBox = *rBoxes[ n ]; + for( sal_uInt16 i = 0; i < rBox.GetTabLines().Count(); ++i ) + SetLineHeight( *rBox.GetTabLines()[ i ], nMyOldH, nMyNewH, bMinSize ); + } +} + +sal_Bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + sal_Bool bRet = sal_True; + if( !bCheck ) + { + // Zeilenhoehe einstellen + SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist, + rParam.bBigger ); + } + else if( !rParam.bBigger ) + { + // anhand der alten Size die neue relative errechnen + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + SwTwips nRstHeight = CalcRowRstHeight( pLineFrm ); + if( (nRstHeight + ROWFUZZY) < nDist ) + bRet = sal_False; + } + return bRet; +} + +sal_Bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + sal_Bool bRet = sal_True; + if( bCheck ) + { + if( rParam.bBigger ) + { + // anhand der alten Size die neue relative errechnen + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + if( TBLFIX_CHGPROP == rParam.nMode ) + { + nDist *= pLineFrm->Frm().Height(); + nDist /= rParam.nMaxHeight; + } + bRet = nDist <= CalcRowRstHeight( pLineFrm ); + } + } + else + { + // Zeilenhoehe einstellen + // pLine ist die nachfolgende / vorhergehende -> also anpassen + if( TBLFIX_CHGPROP == rParam.nMode ) + { + SwLayoutFrm* pLineFrm = GetRowFrm( *pLine ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + + // aus der alten Size die neue relative errechnen + // Wird die selektierte Box groesser ueber den MaxSpace anpassen, + // sonst ueber die MaxHeight + if( 1 /*!rParam.bBigger*/ ) + { + nDist *= pLineFrm->Frm().Height(); + nDist /= rParam.nMaxHeight; + } + else + { + // aus der alten Size die neue relative errechnen + nDist *= CalcRowRstHeight( pLineFrm ); + nDist /= rParam.nMaxSpace; + } + } + SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist, + !rParam.bBigger ); + } + return bRet; +} + +sal_Bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam, + SwTwips nDist, sal_Bool bCheck ) +{ + sal_Bool bRet = sal_True; + if( !bCheck ) + { + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + SwDoc* pDoc = pLine->GetFrmFmt()->GetDoc(); + if( !rParam.bBigger ) + { + sal_uInt16 n; + + for( n = rBoxes.Count(); n; ) + ::lcl_SaveUpperLowerBorder( rParam.pTblNd->GetTable(), + *rBoxes[ --n ], + rParam.aShareFmts ); + for( n = rBoxes.Count(); n; ) + ::_DeleteBox( rParam.pTblNd->GetTable(), + rBoxes[ --n ], rParam.pUndo, sal_False, + sal_False, &rParam.aShareFmts ); + } + else + { + // Zeile einfuegen + SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)pLine->GetFrmFmt(), + rBoxes.Count(), pLine->GetUpper() ); + SwTableLines* pLines; + if( pLine->GetUpper() ) + pLines = &pLine->GetUpper()->GetTabLines(); + else + pLines = &rParam.pTblNd->GetTable().GetTabLines(); + sal_uInt16 nPos = pLines->C40_GETPOS( SwTableLine, pLine ); + if( !rParam.bTop ) + ++nPos; + pLines->C40_INSERT( SwTableLine, pNewLine, nPos ); + + SwFrmFmt* pNewFmt = pNewLine->ClaimFrmFmt(); + pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nDist ) ); + + // und noch mal die Anzahl Boxen erzeugen + SwTableBoxes& rNewBoxes = pNewLine->GetTabBoxes(); + for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n ) + { + SwTwips nWidth = 0; + SwTableBox* pOld = rBoxes[ n ]; + if( !pOld->GetSttNd() ) + { + // keine normale "Content"-Box also auf die 1. naechste + // Box zurueckfallen + nWidth = pOld->GetFrmFmt()->GetFrmSize().GetWidth(); + while( !pOld->GetSttNd() ) + pOld = pOld->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ]; + } + ::_InsTblBox( pDoc, rParam.pTblNd, pNewLine, + (SwTableBoxFmt*)pOld->GetFrmFmt(), pOld, n ); + + // Sonderbehandlung fuer Umrandung die Obere muss + // entfernt werden + const SvxBoxItem& rBoxItem = pOld->GetFrmFmt()->GetBox(); + if( rBoxItem.GetTop() ) + { + SvxBoxItem aTmp( rBoxItem ); + aTmp.SetLine( 0, BOX_LINE_TOP ); + rParam.aShareFmts.SetAttr( rParam.bTop + ? *pOld + : *rNewBoxes[ n ], aTmp ); + } + + if( nWidth ) + rParam.aShareFmts.SetAttr( *rNewBoxes[ n ], + SwFmtFrmSize( ATT_FIX_SIZE, nWidth, 0 ) ); + } + } + } + else + { + // Boxen einsammeln! + SwTableBoxes& rBoxes = pLine->GetTabBoxes(); + for( sal_uInt16 n = rBoxes.Count(); n; ) + { + SwTableBox* pBox = rBoxes[ --n ]; + if( pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) + return sal_False; + + if( pBox->GetSttNd() ) + rParam.aBoxes.Insert( pBox ); + else + { + for( sal_uInt16 i = pBox->GetTabLines().Count(); i; ) + lcl_InsDelSelLine( pBox->GetTabLines()[ --i ], + rParam, 0, sal_True ); + } + } + } + return bRet; +} + +sal_Bool SwTable::SetRowHeight( SwTableBox& rAktBox, sal_uInt16 eType, + SwTwips nAbsDiff, SwTwips nRelDiff,SwUndo** ppUndo ) +{ + SwTableLine* pLine = rAktBox.GetUpper(); + + SwTableLine* pBaseLine = pLine; + while( pBaseLine->GetUpper() ) + pBaseLine = pBaseLine->GetUpper()->GetUpper(); + + _FndBox* pFndBox = 0; // fuers Einfuegen/Loeschen + SwTableSortBoxes aTmpLst( 0, 5 ); // fuers Undo + sal_Bool bBigger, + bRet = sal_False, + bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || + nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ), + bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL ); + sal_uInt16 n, nBaseLinePos = GetTabLines().C40_GETPOS( SwTableLine, pBaseLine ); + sal_uLong nBoxIdx = rAktBox.GetSttIdx(); + + CR_SetLineHeight aParam( eType, + (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() ); + bBigger = aParam.bBigger; + + FN_lcl_SetLineHeight fnSelLine, fnOtherLine = lcl_SetOtherLineHeight; + if( bInsDel ) + fnSelLine = lcl_InsDelSelLine; + else + fnSelLine = lcl_SetSelLineHeight; + + SwTableLines* pLines = &aLines; + + // wie kommt man an die Hoehen heran? + switch( eType & 0xff ) + { + case nsTblChgWidthHeightType::WH_CELL_TOP: + case nsTblChgWidthHeightType::WH_CELL_BOTTOM: + if( pLine == pBaseLine ) + break; // dann geht es nicht! + + // ist eine verschachtelte Line (Box!) + pLines = &pLine->GetUpper()->GetTabLines(); + nBaseLinePos = pLines->C40_GETPOS( SwTableLine, pLine ); + pBaseLine = pLine; + // kein break! + + case nsTblChgWidthHeightType::WH_ROW_TOP: + case nsTblChgWidthHeightType::WH_ROW_BOTTOM: + { + if( bInsDel && !bBigger ) // um wieviel wird es Hoeher? + { + nAbsDiff = GetRowFrm( *pBaseLine )->Frm().Height(); + } + + if( TBLVAR_CHGABS == eTblChgMode ) + { + // erstmal testen, ob ueberhaupt Platz ist + if( bBigger ) + { + bRet = sal_True; +// was ist mit Top, was ist mit Tabelle im Rahmen oder in Kopf-/Fusszeile +// mit fester Hoehe ?? + if( !bRet ) + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLFIX_CHGPROP; + + bRet = SetRowHeight( rAktBox, eType, nAbsDiff, + nRelDiff, ppUndo ); + + eTblChgMode = eOld; + return bRet; + } + } + else + bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, sal_True ); + + if( bRet ) + { + if( bInsDel ) + { + if( !aParam.aBoxes.Count() ) + ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ], + aParam, 0, sal_True ); + + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ); + + // #110525# delete complete table when last row is + // deleted + if( !bBigger && + aParam.aBoxes.Count() == aSortCntBoxes.Count() ) + { + GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes ); + return sal_False; + } + + + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + bBigger ? UNDO_TABLE_INSROW + : UNDO_ROW_DELETE ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True ); + + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, sal_False ); + } + } + else + { + bRet = sal_True; + sal_uInt16 nStt, nEnd; + if( bTop ) + nStt = 0, nEnd = nBaseLinePos; + else + nStt = nBaseLinePos + 1, nEnd = pLines->Count(); + + // die akt. Hoehe der Lines besorgen + if( TBLFIX_CHGPROP == eTblChgMode ) + { + for( n = nStt; n < nEnd; ++n ) + { + SwLayoutFrm* pLineFrm = GetRowFrm( *(*pLines)[ n ] ); + ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" ); + aParam.nMaxSpace += CalcRowRstHeight( pLineFrm ); + aParam.nMaxHeight += pLineFrm->Frm().Height(); + } + if( bBigger && aParam.nMaxSpace < nAbsDiff ) + bRet = sal_False; + } + else + { + if( bTop ? nEnd : nStt < nEnd ) + { + if( bTop ) + nStt = nEnd - 1; + else + nEnd = nStt + 1; + } + else + bRet = sal_False; + } + + if( bRet ) + { + if( bBigger ) + { + for( n = nStt; n < nEnd; ++n ) + { + if( !(*fnOtherLine)( (*pLines)[ n ], aParam, + nAbsDiff, sal_True )) + { + bRet = sal_False; + break; + } + } + } + else + bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, sal_True ); + } + + if( bRet ) + { + // dann mal anpassen + if( bInsDel ) + { + if( !aParam.aBoxes.Count() ) + ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ], + aParam, 0, sal_True ); + pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst ); + if( ppUndo ) + *ppUndo = aParam.CreateUndo( + bBigger ? UNDO_TABLE_INSROW + : UNDO_ROW_DELETE ); + } + else if( ppUndo ) + *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True ); + + CR_SetLineHeight aParam1( aParam ); + if( TBLFIX_CHGPROP == eTblChgMode && !bBigger && + !aParam.nMaxSpace ) + { + // dann muss der gesamte Platz auf alle Lines + // gleichmaessig verteilt werden. Dafuer wird die + // Anzahl benoetigt + aParam1.nLines = nEnd - nStt; + } + + if( bTop ) + { + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, sal_False ); + for( n = nStt; n < nEnd; ++n ) + (*fnOtherLine)( (*pLines)[ n ], aParam1, + nAbsDiff, sal_False ); + } + else + { + for( n = nStt; n < nEnd; ++n ) + (*fnOtherLine)( (*pLines)[ n ], aParam1, + nAbsDiff, sal_False ); + (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam, + nAbsDiff, sal_False ); + } + } + else + { + // dann sich selbst rekursiv aufrufen; nur mit + // einem anderen Mode -> proprotional + TblChgMode eOld = eTblChgMode; + eTblChgMode = TBLVAR_CHGABS; + + bRet = SetRowHeight( rAktBox, eType, nAbsDiff, + nRelDiff, ppUndo ); + + eTblChgMode = eOld; + pFndBox = 0; + } + } + } + break; + } + + if( pFndBox ) + { + // dann raeume die Struktur aller Lines auf + GCLines(); + + //Layout updaten + if( bBigger || pFndBox->AreLinesToRestore( *this ) ) + pFndBox->MakeFrms( *this ); + + // TL_CHART2: it is currently unclear if sth has to be done here. + + delete pFndBox; + + if( ppUndo && *ppUndo ) + { + aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType, + nAbsDiff, nRelDiff ); + if( bBigger ) + aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst ); + } + } + + CHECKTABLELAYOUT + + return bRet; +} + +/* */ + +SwFrmFmt* SwShareBoxFmt::GetFormat( long nWidth ) const +{ + SwFrmFmt *pRet = 0, *pTmp; + for( sal_uInt16 n = aNewFmts.Count(); n; ) + if( ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])->GetFrmSize().GetWidth() + == nWidth ) + { + pRet = pTmp; + break; + } + return pRet; +} + +SwFrmFmt* SwShareBoxFmt::GetFormat( const SfxPoolItem& rItem ) const +{ + const SfxPoolItem* pItem; + sal_uInt16 nWhich = rItem.Which(); + SwFrmFmt *pRet = 0, *pTmp; + const SfxPoolItem& rFrmSz = pOldFmt->GetFmtAttr( RES_FRM_SIZE, sal_False ); + for( sal_uInt16 n = aNewFmts.Count(); n; ) + if( SFX_ITEM_SET == ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])-> + GetItemState( nWhich, sal_False, &pItem ) && *pItem == rItem && + pTmp->GetFmtAttr( RES_FRM_SIZE, sal_False ) == rFrmSz ) + { + pRet = pTmp; + break; + } + return pRet; +} + +void SwShareBoxFmt::AddFormat( const SwFrmFmt& rNew ) +{ + void* pFmt = (void*)&rNew; + aNewFmts.Insert( pFmt, aNewFmts.Count() ); +} + +sal_Bool SwShareBoxFmt::RemoveFormat( const SwFrmFmt& rFmt ) +{ + // returnt sal_True, wenn geloescht werden kann + if( pOldFmt == &rFmt ) + return sal_True; + + void* p = (void*)&rFmt; + sal_uInt16 nFnd = aNewFmts.GetPos( p ); + if( USHRT_MAX != nFnd ) + aNewFmts.Remove( nFnd ); + return 0 == aNewFmts.Count(); +} + +SwShareBoxFmts::~SwShareBoxFmts() +{ +} + +SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, long nWidth ) const +{ + sal_uInt16 nPos; + return Seek_Entry( rFmt, &nPos ) + ? aShareArr[ nPos ]->GetFormat( nWidth ) + : 0; +} +SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, + const SfxPoolItem& rItem ) const +{ + sal_uInt16 nPos; + return Seek_Entry( rFmt, &nPos ) + ? aShareArr[ nPos ]->GetFormat( rItem ) + : 0; +} + +void SwShareBoxFmts::AddFormat( const SwFrmFmt& rOld, const SwFrmFmt& rNew ) +{ + // wenn das Format nicht geshared ist, braucht es auch nicht in die + // Liste aufgenommen werden. Denn es gibt keinen 2. der es sucht. +//leider werden auch die CellFrms gefunden +// if( !rOld.IsLastDepend() ) + { + sal_uInt16 nPos; + SwShareBoxFmt* pEntry; + if( !Seek_Entry( rOld, &nPos )) + { + pEntry = new SwShareBoxFmt( rOld ); + aShareArr.C40_INSERT( SwShareBoxFmt, pEntry, nPos ); + } + else + pEntry = aShareArr[ nPos ]; + + pEntry->AddFormat( rNew ); + } +} +void SwShareBoxFmts::ChangeFrmFmt( SwTableBox* pBox, SwTableLine* pLn, + SwFrmFmt& rFmt ) +{ + SwClient aCl; + SwFrmFmt* pOld = 0; + if( pBox ) + { + pOld = pBox->GetFrmFmt(); + pOld->Add( &aCl ); + pBox->ChgFrmFmt( (SwTableBoxFmt*)&rFmt ); + } + else if( pLn ) + { + pOld = pLn->GetFrmFmt(); + pOld->Add( &aCl ); + pLn->ChgFrmFmt( (SwTableLineFmt*)&rFmt ); + } + if( pOld && pOld->IsLastDepend() ) + { + RemoveFormat( *pOld ); + delete pOld; + } +} + +void SwShareBoxFmts::SetSize( SwTableBox& rBox, const SwFmtFrmSize& rSz ) +{ + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(), + *pRet = GetFormat( *pBoxFmt, rSz.GetWidth() ); + if( pRet ) + ChangeFrmFmt( &rBox, 0, *pRet ); + else + { + pRet = rBox.ClaimFrmFmt(); + pRet->SetFmtAttr( rSz ); + AddFormat( *pBoxFmt, *pRet ); + } +} + +void SwShareBoxFmts::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem ) +{ + SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(), + *pRet = GetFormat( *pBoxFmt, rItem ); + if( pRet ) + ChangeFrmFmt( &rBox, 0, *pRet ); + else + { + pRet = rBox.ClaimFrmFmt(); + pRet->SetFmtAttr( rItem ); + AddFormat( *pBoxFmt, *pRet ); + } +} + +void SwShareBoxFmts::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem ) +{ + SwFrmFmt *pLineFmt = rLine.GetFrmFmt(), + *pRet = GetFormat( *pLineFmt, rItem ); + if( pRet ) + ChangeFrmFmt( 0, &rLine, *pRet ); + else + { + pRet = rLine.ClaimFrmFmt(); + pRet->SetFmtAttr( rItem ); + AddFormat( *pLineFmt, *pRet ); + } +} + +void SwShareBoxFmts::RemoveFormat( const SwFrmFmt& rFmt ) +{ + for( sal_uInt16 i = aShareArr.Count(); i; ) + if( aShareArr[ --i ]->RemoveFormat( rFmt )) + aShareArr.DeleteAndDestroy( i ); +} + +sal_Bool SwShareBoxFmts::Seek_Entry( const SwFrmFmt& rFmt, sal_uInt16* pPos ) const +{ + sal_uLong nIdx = (sal_uLong)&rFmt; + sal_uInt16 nO = aShareArr.Count(), nM, nU = 0; + if( nO > 0 ) + { + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + sal_uLong nFmt = (sal_uLong)&aShareArr[ nM ]->GetOldFormat(); + if( nFmt == nIdx ) + { + if( pPos ) + *pPos = nM; + return sal_True; + } + else if( nFmt < nIdx ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pPos ) + *pPos = nU; + return sal_False; + } + else + nO = nM - 1; + } + } + if( pPos ) + *pPos = nU; + return sal_False; +} + + diff --git a/sw/source/core/doc/visiturl.cxx b/sw/source/core/doc/visiturl.cxx new file mode 100644 index 000000000000..b5ca141e1fa2 --- /dev/null +++ b/sw/source/core/doc/visiturl.cxx @@ -0,0 +1,139 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + + +#include <sfx2/docfile.hxx> +#include <svl/inethist.hxx> +#include <fmtinfmt.hxx> +#include <txtinet.hxx> +#include <doc.hxx> +#include <visiturl.hxx> +#include <hints.hxx> +#include <ndtxt.hxx> +#include <editsh.hxx> +#include <docsh.hxx> + + +SwURLStateChanged::SwURLStateChanged( const SwDoc* pD ) + : pDoc( pD ) +{ + StartListening( *INetURLHistory::GetOrCreate() ); +} + +SwURLStateChanged::~SwURLStateChanged() +{ + EndListening( *INetURLHistory::GetOrCreate() ); +} + +void SwURLStateChanged::Notify( SfxBroadcaster& , const SfxHint& rHint ) +{ + if( rHint.ISA( INetURLHistoryHint ) && pDoc->GetRootFrm() ) + { + // diese URL wurde veraendert: + const INetURLObject* pIURL = ((INetURLHistoryHint&)rHint).GetObject(); + String sURL( pIURL->GetMainURL( INetURLObject::NO_DECODE ) ), sBkmk; + + SwEditShell* pESh = pDoc->GetEditShell(); + + if( pDoc->GetDocShell() && pDoc->GetDocShell()->GetMedium() && + // falls das unser Doc ist, kann es auch lokale Spruenge geben! + sURL == pDoc->GetDocShell()->GetMedium()->GetName() ) + (sBkmk = pIURL->GetMark()).Insert( INET_MARK_TOKEN, 0 ); + + sal_Bool bAction = sal_False, bUnLockView = sal_False; + const SwFmtINetFmt* pItem; + const SwTxtINetFmt* pTxtAttr; + const SwTxtNode* pTxtNd; + sal_uInt32 n, nMaxItems = pDoc->GetAttrPool().GetItemCount2( RES_TXTATR_INETFMT ); + for( n = 0; n < nMaxItems; ++n ) + if( 0 != (pItem = (SwFmtINetFmt*)pDoc->GetAttrPool().GetItem2( + RES_TXTATR_INETFMT, n ) ) && + ( pItem->GetValue() == sURL || + ( sBkmk.Len() && pItem->GetValue() == sBkmk )) && + 0 != ( pTxtAttr = pItem->GetTxtINetFmt()) && + 0 != ( pTxtNd = pTxtAttr->GetpTxtNode() ) ) + { + if( !bAction && pESh ) + { + pESh->StartAllAction(); + bAction = sal_True; + bUnLockView = !pESh->IsViewLocked(); + pESh->LockView( sal_True ); + } + const_cast<SwTxtINetFmt*>(pTxtAttr)->SetVisitedValid( false ); + const SwTxtAttr* pAttr = pTxtAttr; + SwUpdateAttr aUpdateAttr( *pAttr->GetStart(), + *pAttr->GetEnd(), + RES_FMT_CHG ); + ((SwTxtNode*)pTxtNd)->Modify( &aUpdateAttr, &aUpdateAttr ); + } + + if( bAction ) + pESh->EndAllAction(); + if( bUnLockView ) + pESh->LockView( sal_False ); + } +} + + // erfrage ob die URL besucht war. Uebers Doc, falls nur ein Bookmark + // angegeben ist. Dann muss der Doc. Name davor gesetzt werden! +sal_Bool SwDoc::IsVisitedURL( const String& rURL ) const +{ +#if OSL_DEBUG_LEVEL > 1 + static long nTmp = 0; + ++nTmp; +#endif + + sal_Bool bRet = sal_False; + if( rURL.Len() ) + { + INetURLHistory *pHist = INetURLHistory::GetOrCreate(); + if( '#' == rURL.GetChar( 0 ) && pDocShell && pDocShell->GetMedium() ) + { + INetURLObject aIObj( pDocShell->GetMedium()->GetURLObject() ); + aIObj.SetMark( rURL.Copy( 1 ) ); + bRet = pHist->QueryUrl( aIObj ); + } + else + bRet = pHist->QueryUrl( rURL ); + + // dann wollen wird auch ueber Statusaenderungen in der History + // informiert werden! + if( !pURLStateChgd ) + { + SwDoc* pD = (SwDoc*)this; + pD->pURLStateChgd = new SwURLStateChanged( this ); + } + } + return bRet; +} + + + |