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