1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 #include <editsh.hxx> 32 #include <doc.hxx> 33 #include <IDocumentUndoRedo.hxx> 34 #include <pam.hxx> 35 #include <docary.hxx> 36 #include <swundo.hxx> // fuer die UndoIds 37 #include <section.hxx> 38 #include <edimp.hxx> 39 #include <sectfrm.hxx> // SwSectionFrm 40 #include <cntfrm.hxx> // SwCntntFrm 41 #include <tabfrm.hxx> // SwTabFrm 42 #include <rootfrm.hxx> // SwRootFrm 43 44 45 SwSection const* 46 SwEditShell::InsertSection( 47 SwSectionData & rNewData, SfxItemSet const*const pAttr) 48 { 49 const SwSection* pRet = 0; 50 if( !IsTableMode() ) 51 { 52 StartAllAction(); 53 GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_INSSECTION, NULL ); 54 55 FOREACHPAM_START(this) 56 SwSection const*const pNew = 57 GetDoc()->InsertSwSection( *PCURCRSR, rNewData, 0, pAttr ); 58 if( !pRet ) 59 pRet = pNew; 60 FOREACHPAM_END() 61 62 GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_INSSECTION, NULL ); 63 EndAllAction(); 64 } 65 return pRet; 66 } 67 68 69 sal_Bool SwEditShell::IsInsRegionAvailable() const 70 { 71 if( IsTableMode() ) 72 return sal_False; 73 SwPaM* pCrsr = GetCrsr(); 74 if( pCrsr->GetNext() != pCrsr ) 75 return sal_False; 76 if( pCrsr->HasMark() ) 77 return 0 != GetDoc()->IsInsRegionAvailable( *pCrsr ); 78 79 return sal_True; 80 } 81 82 83 const SwSection* SwEditShell::GetCurrSection() const 84 { 85 if( IsTableMode() ) 86 return 0; 87 88 return GetDoc()->GetCurrSection( *GetCrsr()->GetPoint() ); 89 } 90 91 /*-----------------17.03.99 11:53------------------- 92 * SwEditShell::GetAnySection liefert den fuer Spalten 93 * zustaendigen Bereich, bei Fussnoten kann es nicht der 94 * Bereich innerhalb der Fussnote sein. 95 * --------------------------------------------------*/ 96 97 const SwSection* SwEditShell::GetAnySection( sal_Bool bOutOfTab, const Point* pPt ) const 98 { 99 SwFrm *pFrm; 100 if ( pPt ) 101 { 102 SwPosition aPos( *GetCrsr()->GetPoint() ); 103 Point aPt( *pPt ); 104 GetLayout()->GetCrsrOfst( &aPos, aPt ); 105 SwCntntNode *pNd = aPos.nNode.GetNode().GetCntntNode(); 106 pFrm = pNd->getLayoutFrm( GetLayout(), pPt ); 107 } 108 else 109 pFrm = GetCurrFrm( sal_False ); 110 111 if( bOutOfTab && pFrm ) 112 pFrm = pFrm->FindTabFrm(); 113 if( pFrm && pFrm->IsInSct() ) 114 { 115 SwSectionFrm* pSect = pFrm->FindSctFrm(); 116 ASSERT( pSect, "GetAnySection: Where's my Sect?" ); 117 if( pSect->IsInFtn() && pSect->GetUpper()->IsInSct() ) 118 { 119 pSect = pSect->GetUpper()->FindSctFrm(); 120 ASSERT( pSect, "GetAnySection: Where's my SectFrm?" ); 121 } 122 return pSect->GetSection(); 123 } 124 return NULL; 125 } 126 127 sal_uInt16 SwEditShell::GetSectionFmtCount() const 128 { 129 return GetDoc()->GetSections().Count(); 130 } 131 132 133 sal_Bool SwEditShell::IsAnySectionInDoc( sal_Bool bChkReadOnly, sal_Bool bChkHidden, sal_Bool bChkTOX ) const 134 { 135 const SwSectionFmts& rFmts = GetDoc()->GetSections(); 136 sal_uInt16 nCnt = rFmts.Count(); 137 sal_uInt16 n; 138 139 for( n = 0; n < nCnt; ++n ) 140 { 141 SectionType eTmpType; 142 const SwSectionFmt* pFmt = rFmts[ n ]; 143 if( pFmt->IsInNodesArr() && 144 (bChkTOX || 145 ( (eTmpType = pFmt->GetSection()->GetType()) != TOX_CONTENT_SECTION 146 && TOX_HEADER_SECTION != eTmpType ) ) ) 147 { 148 const SwSection& rSect = *rFmts[ n ]->GetSection(); 149 if( (!bChkReadOnly && !bChkHidden ) || 150 (bChkReadOnly && rSect.IsProtectFlag() ) || 151 (bChkHidden && rSect.IsHiddenFlag() ) ) 152 break; 153 } 154 } 155 return n != nCnt; 156 } 157 158 sal_uInt16 SwEditShell::GetSectionFmtPos( const SwSectionFmt& rFmt ) const 159 { 160 SwSectionFmt* pFmt = (SwSectionFmt*)&rFmt; 161 return GetDoc()->GetSections().GetPos( pFmt ); 162 } 163 164 const SwSectionFmt& SwEditShell::GetSectionFmt( sal_uInt16 nFmt ) const 165 { 166 return *GetDoc()->GetSections()[ nFmt ]; 167 } 168 169 170 void SwEditShell::DelSectionFmt( sal_uInt16 nFmt ) 171 { 172 StartAllAction(); 173 GetDoc()->DelSectionFmt( GetDoc()->GetSections()[ nFmt ] ); 174 // rufe das AttrChangeNotify auf der UI-Seite. 175 CallChgLnk(); 176 EndAllAction(); 177 } 178 179 180 void SwEditShell::UpdateSection(sal_uInt16 const nSect, 181 SwSectionData & rNewData, SfxItemSet const*const pAttr) 182 { 183 StartAllAction(); 184 GetDoc()->UpdateSection( nSect, rNewData, pAttr ); 185 // rufe das AttrChangeNotify auf der UI-Seite. 186 CallChgLnk(); 187 EndAllAction(); 188 } 189 190 String SwEditShell::GetUniqueSectionName( const String* pChkStr ) const 191 { 192 return GetDoc()->GetUniqueSectionName( pChkStr ); 193 } 194 195 void SwEditShell::SetSectionAttr( const SfxItemSet& rSet, 196 SwSectionFmt* pSectFmt ) 197 { 198 if( pSectFmt ) 199 _SetSectionAttr( *pSectFmt, rSet ); 200 else 201 { 202 // for all section in the selection 203 204 FOREACHPAM_START(this) 205 206 const SwPosition* pStt = PCURCRSR->Start(), 207 * pEnd = PCURCRSR->End(); 208 209 const SwSectionNode* pSttSectNd = pStt->nNode.GetNode().FindSectionNode(), 210 * pEndSectNd = pEnd->nNode.GetNode().FindSectionNode(); 211 212 if( pSttSectNd || pEndSectNd ) 213 { 214 if( pSttSectNd ) 215 _SetSectionAttr( *pSttSectNd->GetSection().GetFmt(), 216 rSet ); 217 if( pEndSectNd && pSttSectNd != pEndSectNd ) 218 _SetSectionAttr( *pEndSectNd->GetSection().GetFmt(), 219 rSet ); 220 221 if( pSttSectNd && pEndSectNd ) 222 { 223 SwNodeIndex aSIdx( pStt->nNode ); 224 SwNodeIndex aEIdx( pEnd->nNode ); 225 if( pSttSectNd->EndOfSectionIndex() < 226 pEndSectNd->GetIndex() ) 227 { 228 aSIdx = pSttSectNd->EndOfSectionIndex() + 1; 229 aEIdx = *pEndSectNd; 230 } 231 232 while( aSIdx < aEIdx ) 233 { 234 if( 0 != (pSttSectNd = aSIdx.GetNode().GetSectionNode()) 235 || ( aSIdx.GetNode().IsEndNode() && 236 0 != ( pSttSectNd = aSIdx.GetNode(). 237 StartOfSectionNode()->GetSectionNode())) ) 238 _SetSectionAttr( *pSttSectNd->GetSection().GetFmt(), 239 rSet ); 240 aSIdx++; 241 } 242 } 243 } 244 245 FOREACHPAM_END() 246 } 247 } 248 249 void SwEditShell::_SetSectionAttr( SwSectionFmt& rSectFmt, 250 const SfxItemSet& rSet ) 251 { 252 StartAllAction(); 253 if(SFX_ITEM_SET == rSet.GetItemState(RES_CNTNT, sal_False)) 254 { 255 SfxItemSet aSet(rSet); 256 aSet.ClearItem(RES_CNTNT); 257 GetDoc()->SetAttr( aSet, rSectFmt ); 258 } 259 else 260 GetDoc()->SetAttr( rSet, rSectFmt ); 261 262 // rufe das AttrChangeNotify auf der UI-Seite. 263 CallChgLnk(); 264 EndAllAction(); 265 } 266 267 // search inside the cursor selection for full selected sections. 268 // if any part of section in the selection return 0. 269 // if more than one in the selection return the count 270 sal_uInt16 SwEditShell::GetFullSelectedSectionCount() const 271 { 272 sal_uInt16 nRet = 0; 273 FOREACHPAM_START(this) 274 275 const SwPosition* pStt = PCURCRSR->Start(), 276 * pEnd = PCURCRSR->End(); 277 const SwCntntNode* pCNd; 278 // check the selection, if Start at Node begin and End at Node end 279 if( pStt->nContent.GetIndex() || 280 ( 0 == ( pCNd = pEnd->nNode.GetNode().GetCntntNode() )) || 281 pCNd->Len() != pEnd->nContent.GetIndex() ) 282 { 283 nRet = 0; 284 break; 285 } 286 287 // !!!!!!!!!!!!!!!!!!!!!!!!!! 288 // what about table at start or end ? 289 // There is no selection possible! 290 // What about only a table inside the section ? 291 // There is only a table selection possible! 292 293 SwNodeIndex aSIdx( pStt->nNode, -1 ), aEIdx( pEnd->nNode, +1 ); 294 if( !aSIdx.GetNode().IsSectionNode() || 295 !aEIdx.GetNode().IsEndNode() || 296 !aEIdx.GetNode().StartOfSectionNode()->IsSectionNode() ) 297 { 298 nRet = 0; 299 break; 300 } 301 302 ++nRet; 303 if( &aSIdx.GetNode() != aEIdx.GetNode().StartOfSectionNode() ) 304 ++nRet; 305 306 FOREACHPAM_END() 307 return nRet; 308 } 309 310 311 /** 312 * Find the suitable node for a special insert (alt-enter). 313 * This should enable inserting text before/after sections and tables. 314 * 315 * A node is found if: 316 * 1) the innermost table/section is not in a write-protected area 317 * 2) pCurrentPos is at or just before an end node 318 * (or at or just after a start node) 319 * 3) there are only start/end nodes between pCurrentPos and the innermost 320 * table/section 321 * 322 * If a suitable node is found, an SwNode* is returned; else it is NULL. 323 */ 324 const SwNode* lcl_SpecialInsertNode(const SwPosition* pCurrentPos) 325 { 326 const SwNode* pReturn = NULL; 327 328 // the current position 329 // const SwPosition* pCurrentPos = GetCrsr()->GetPoint(); 330 DBG_ASSERT( pCurrentPos != NULL, "Strange, we have no position!" ); 331 const SwNode& rCurrentNode = pCurrentPos->nNode.GetNode(); 332 333 334 // find innermost section or table. At the end of this scope, 335 // pInntermostNode contain the section/table before/after which we should 336 // insert our empty paragraph, or it will be NULL if none is found. 337 const SwNode* pInnermostNode = NULL; 338 { 339 const SwNode* pTableNode = rCurrentNode.FindTableNode(); 340 const SwNode* pSectionNode = rCurrentNode.FindSectionNode(); 341 342 // find the table/section which is close 343 if( pTableNode == NULL ) 344 pInnermostNode = pSectionNode; 345 else if ( pSectionNode == NULL ) 346 pInnermostNode = pTableNode; 347 else 348 { 349 // compare and choose the larger one 350 pInnermostNode = 351 ( pSectionNode->GetIndex() > pTableNode->GetIndex() ) 352 ? pSectionNode : pTableNode; 353 } 354 } 355 356 // The previous version had a check to skip empty read-only sections. Those 357 // shouldn't occur, so we only need to check whether our pInnermostNode is 358 // inside a protected area. 359 360 // Now, pInnermostNode is NULL or the innermost section or table node. 361 if( (pInnermostNode != NULL) && !pInnermostNode->IsProtect() ) 362 { 363 DBG_ASSERT( pInnermostNode->IsTableNode() || 364 pInnermostNode->IsSectionNode(), "wrong node found" ); 365 DBG_ASSERT( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&& 366 ( pInnermostNode->EndOfSectionNode()->GetIndex() >= 367 rCurrentNode.GetIndex() ), "wrong node found" ); 368 369 // we now need to find the possible start/end positions 370 371 // we found a start if 372 // - we're at or just before a start node 373 // - there are only start nodes between the current and pInnermostNode 374 SwNodeIndex aBegin( pCurrentPos->nNode ); 375 if( rCurrentNode.IsCntntNode() && 376 (pCurrentPos->nContent.GetIndex() == 0)) 377 aBegin--; 378 while( (aBegin != pInnermostNode->GetIndex()) && 379 aBegin.GetNode().IsStartNode() ) 380 aBegin--; 381 bool bStart = ( aBegin == pInnermostNode->GetIndex() ); 382 383 // we found an end if 384 // - we're at or just before an end node 385 // - there are only end nodes between the current node and 386 // pInnermostNode's end node 387 SwNodeIndex aEnd( pCurrentPos->nNode ); 388 if( rCurrentNode.IsCntntNode() && 389 ( pCurrentPos->nContent.GetIndex() == 390 rCurrentNode.GetCntntNode()->Len() ) ) 391 aEnd++; 392 while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) && 393 aEnd.GetNode().IsEndNode() ) 394 aEnd++; 395 bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() ); 396 397 // evalutate result: if both start + end, end is preferred 398 if( bEnd ) 399 pReturn = pInnermostNode->EndOfSectionNode(); 400 else if ( bStart ) 401 pReturn = pInnermostNode; 402 // else pReturn = NULL; 403 } 404 // else: pReturn = NULL 405 406 407 DBG_ASSERT( ( pReturn == NULL ) || pReturn->IsStartNode() || 408 pReturn->IsEndNode(), 409 "SpecialInsertNode failed" ); 410 return pReturn; 411 } 412 413 414 /** a node can be special-inserted (alt-Enter) whenever lcl_SpecialInsertNode 415 finds a suitable position 416 */ 417 bool SwEditShell::CanSpecialInsert() const 418 { 419 return NULL != lcl_SpecialInsertNode( GetCrsr()->GetPoint() ); 420 } 421 422 423 /** check whether a node cen be special-inserted (alt-Enter), and do so. Return 424 whether insertion was possible. 425 */ 426 bool SwEditShell::DoSpecialInsert() 427 { 428 bool bRet = false; 429 430 // get current node 431 SwPosition* pCursorPos = GetCrsr()->GetPoint(); 432 const SwNode* pInsertNode = lcl_SpecialInsertNode( pCursorPos ); 433 if( pInsertNode != NULL ) 434 { 435 StartAllAction(); 436 437 // adjust insert position to insert before start nodes and after end 438 // nodes 439 SwNodeIndex aInsertIndex( *pInsertNode, 440 pInsertNode->IsStartNode() ? -1 : 0 ); 441 SwPosition aInsertPos( aInsertIndex ); 442 443 // insert a new text node, and set the cursor 444 bRet = GetDoc()->AppendTxtNode( aInsertPos ); 445 *pCursorPos = aInsertPos; 446 447 // call AttrChangeNotify for the UI 448 CallChgLnk(); 449 450 EndAllAction(); 451 } 452 453 return bRet; 454 } 455 456