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 #include <hintids.hxx> 27 28 #include <vcl/svapp.hxx> 29 #include <editeng/protitem.hxx> 30 #include <crsrsh.hxx> 31 #include <doc.hxx> 32 #include <cntfrm.hxx> 33 #include <editsh.hxx> //EndAllAction gibts nur an der EditShell 34 #include <pam.hxx> 35 #include <swtable.hxx> 36 #include <docary.hxx> 37 #include <frmatr.hxx> 38 #include <frmfmt.hxx> 39 #include <viscrs.hxx> 40 #include <callnk.hxx> 41 #include <tabfrm.hxx> 42 #include <ndtxt.hxx> 43 #include <shellres.hxx> 44 #include <cellatr.hxx> 45 #include <cellfrm.hxx> 46 #include <rowfrm.hxx> 47 48 49 // setze Crsr in die naechsten/vorherigen Celle 50 sal_Bool SwCrsrShell::GoNextCell( sal_Bool bAppendLine ) 51 { 52 sal_Bool bRet = sal_False; 53 const SwTableNode* pTblNd = 0; 54 55 if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() )) 56 { 57 SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; 58 SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, 59 bRet = sal_True; 60 61 // Check if we have to move the cursor to a covered cell before 62 // proceeding: 63 const SwNode* pTableBoxStartNode = pCrsr->GetNode()->FindTableBoxStartNode(); 64 const SwTableBox* pTableBox = 0; 65 66 if ( pCrsr->GetCrsrRowSpanOffset() ) 67 { 68 pTableBox = pTableBoxStartNode->GetTblBox(); 69 if ( pTableBox->getRowSpan() > 1 ) 70 { 71 if ( !pTblNd ) 72 pTblNd = IsCrsrInTbl(); 73 pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(), 74 (sal_uInt16)(pTableBox->getRowSpan() + pCrsr->GetCrsrRowSpanOffset() ) ); 75 pTableBoxStartNode = pTableBox->GetSttNd(); 76 } 77 } 78 79 SwNodeIndex aCellStt( *pTableBoxStartNode->EndOfSectionNode(), 1 ); 80 81 // folgt nach dem EndNode der Cell ein weiterer StartNode, dann 82 // gibt es auch eine naechste Celle 83 84 if( !aCellStt.GetNode().IsStartNode() ) 85 { 86 if( pCrsr->HasMark() || !bAppendLine ) 87 bRet = sal_False; 88 else 89 { 90 // auf besonderen Wunsch: keine Line mehr vorhanden, dann 91 // mache doch eine neue: 92 if ( !pTableBox ) 93 pTableBox = pTblNd->GetTable().GetTblBox( 94 pCrsr->GetPoint()->nNode.GetNode(). 95 StartOfSectionIndex() ); 96 97 ASSERT( pTableBox, "Box steht nicht in dieser Tabelle" ); 98 SwSelBoxes aBoxes; 99 100 //Das Dokument veraendert sich evtl. ohne Action wuerden die Sichten 101 //nichts mitbekommen. 102 ((SwEditShell*)this)->StartAllAction(); 103 bRet = pDoc->InsertRow( pTblNd->GetTable(). 104 SelLineFromBox( pTableBox, aBoxes, sal_False )); 105 ((SwEditShell*)this)->EndAllAction(); 106 } 107 } 108 if( bRet && 0 != ( bRet = pCrsr->GoNextCell() )) 109 UpdateCrsr(); // und den akt. Updaten 110 } 111 return bRet; 112 } 113 114 115 sal_Bool SwCrsrShell::GoPrevCell() 116 { 117 sal_Bool bRet = sal_False; 118 const SwTableNode* pTblNd; 119 if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() )) 120 { 121 SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; 122 SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, 123 bRet = pCrsr->GoPrevCell(); 124 if( bRet ) 125 UpdateCrsr(); // und den akt. Updaten 126 } 127 return bRet; 128 } 129 130 const SwFrm* lcl_FindMostUpperCellFrm( const SwFrm* pFrm ) 131 { 132 while ( pFrm && 133 ( !pFrm->IsCellFrm() || 134 !pFrm->GetUpper()->GetUpper()->IsTabFrm() || 135 pFrm->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) ) 136 { 137 pFrm = pFrm->GetUpper(); 138 } 139 return pFrm; 140 } 141 142 sal_Bool SwCrsrShell::_SelTblRowOrCol( bool bRow, bool bRowSimple ) 143 { 144 // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen 145 SwFrm *pFrm = GetCurrFrm(); 146 if( !pFrm->IsInTab() ) 147 return sal_False; 148 149 const SwTabFrm* pTabFrm = pFrm->FindTabFrm(); 150 const SwTabFrm* pMasterTabFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm; 151 const SwTable* pTable = pTabFrm->GetTable(); 152 153 SET_CURR_SHELL( this ); 154 155 const SwTableBox* pStt = 0; 156 const SwTableBox* pEnd = 0; 157 158 // lasse ueber das Layout die Boxen suchen 159 SwSelBoxes aBoxes; 160 SwTblSearchType eType = bRow ? nsSwTblSearchType::TBLSEARCH_ROW : nsSwTblSearchType::TBLSEARCH_COL; 161 const bool bCheckProtected = !IsReadOnlyAvailable(); 162 163 if( bCheckProtected ) 164 eType = (SwTblSearchType)(eType | nsSwTblSearchType::TBLSEARCH_PROTECT); 165 166 if ( !bRowSimple ) 167 { 168 GetTblSel( *this, aBoxes, eType ); 169 170 if( !aBoxes.Count() ) 171 return sal_False; 172 173 pStt = aBoxes[0]; 174 pEnd = aBoxes[aBoxes.Count() - 1]; 175 } 176 // --> FME 2004-07-30 #i32329# Enhanced table selection 177 else if ( pTable->IsNewModel() ) 178 { 179 const SwShellCrsr *pCrsr = _GetCrsr(); 180 SwTable::SearchType eSearchType = bRow ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL; 181 pTable->CreateSelection( *pCrsr, aBoxes, eSearchType, bCheckProtected ); 182 if( !aBoxes.Count() ) 183 return sal_False; 184 185 pStt = aBoxes[0]; 186 pEnd = aBoxes[aBoxes.Count() - 1]; 187 } 188 else 189 { 190 const SwShellCrsr *pCrsr = _GetCrsr(); 191 const SwFrm* pStartFrm = pFrm; 192 const SwCntntNode *pCNd = pCrsr->GetCntntNode( sal_False ); 193 const SwFrm* pEndFrm = pCNd ? pCNd->getLayoutFrm( GetLayout(), &pCrsr->GetMkPos() ) : 0; 194 195 if ( bRow ) 196 { 197 pStartFrm = lcl_FindMostUpperCellFrm( pStartFrm ); 198 pEndFrm = lcl_FindMostUpperCellFrm( pEndFrm ); 199 } 200 201 if ( !pStartFrm || !pEndFrm ) 202 return sal_False; 203 204 const bool bVert = pFrm->ImplFindTabFrm()->IsVertical(); 205 206 // If we select upwards it is sufficient to set pStt and pEnd 207 // to the first resp. last box of the selection obtained from 208 // GetTblSel. However, selecting downwards requires the frames 209 // located at the corners of the selection. This does not work 210 // for column selections in vertical tables: 211 const bool bSelectUp = ( bVert && !bRow ) || 212 *pCrsr->GetPoint() <= *pCrsr->GetMark(); 213 SwCellFrms aCells; 214 GetTblSel( static_cast<const SwCellFrm*>(pStartFrm), 215 static_cast<const SwCellFrm*>(pEndFrm), 216 aBoxes, bSelectUp ? 0 : &aCells, eType ); 217 218 if( !aBoxes.Count() || ( !bSelectUp && 4 != aCells.Count() ) ) 219 return sal_False; 220 221 if ( bSelectUp ) 222 { 223 pStt = aBoxes[0]; 224 pEnd = aBoxes[aBoxes.Count() - 1]; 225 } 226 else 227 { 228 pStt = aCells[ bVert ? (bRow ? 0 : 3) : (bRow ? 2 : 1) ]->GetTabBox(); // will become point of table cursor 229 pEnd = aCells[ bVert ? (bRow ? 3 : 0) : (bRow ? 1 : 2) ]->GetTabBox(); // will become mark of table cursor 230 } 231 } 232 // <-- 233 234 // noch kein Tabellen-Cursor vorhanden, dann erzeuge einen 235 if( !pTblCrsr ) 236 { 237 pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); 238 pCurCrsr->DeleteMark(); 239 pCurCrsr->SwSelPaintRects::Hide(); 240 } 241 242 pTblCrsr->DeleteMark(); 243 244 // dann setze mal Anfang und Ende der Spalte 245 pTblCrsr->GetPoint()->nNode = *pEnd->GetSttNd(); 246 pTblCrsr->Move( fnMoveForward, fnGoCntnt ); 247 pTblCrsr->SetMark(); 248 pTblCrsr->GetPoint()->nNode = *pStt->GetSttNd()->EndOfSectionNode(); 249 pTblCrsr->Move( fnMoveBackward, fnGoCntnt ); 250 251 // set PtPos 'close' to the reference table, otherwise we might get problems with the 252 // repeated headlines check in UpdateCrsr(): 253 if ( !bRow ) 254 pTblCrsr->GetPtPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft(); 255 256 UpdateCrsr(); // und den akt. Updaten 257 return sal_True; 258 } 259 260 sal_Bool SwCrsrShell::SelTbl() 261 { 262 // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen 263 SwFrm *pFrm = GetCurrFrm(); 264 if( !pFrm->IsInTab() ) 265 return sal_False; 266 267 const SwTabFrm *pTblFrm = pFrm->ImplFindTabFrm(); 268 const SwTabFrm* pMasterTabFrm = pTblFrm->IsFollow() ? pTblFrm->FindMaster( true ) : pTblFrm; 269 const SwTableNode* pTblNd = pTblFrm->GetTable()->GetTableNode(); 270 271 SET_CURR_SHELL( this ); 272 273 if( !pTblCrsr ) 274 { 275 pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); 276 pCurCrsr->DeleteMark(); 277 pCurCrsr->SwSelPaintRects::Hide(); 278 } 279 280 pTblCrsr->DeleteMark(); 281 pTblCrsr->GetPoint()->nNode = *pTblNd; 282 pTblCrsr->Move( fnMoveForward, fnGoCntnt ); 283 pTblCrsr->SetMark(); 284 // set MkPos 'close' to the master table, otherwise we might get problems with the 285 // repeated headlines check in UpdateCrsr(): 286 pTblCrsr->GetMkPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft(); 287 pTblCrsr->GetPoint()->nNode = *pTblNd->EndOfSectionNode(); 288 pTblCrsr->Move( fnMoveBackward, fnGoCntnt ); 289 UpdateCrsr(); // und den akt. Updaten 290 return sal_True; 291 } 292 293 294 sal_Bool SwCrsrShell::SelTblBox() 295 { 296 // if we're in a table, create a table cursor, and select the cell 297 // that the current cursor's point resides in 298 299 // search for start node of our table box. If not found, exit realy 300 const SwStartNode* pStartNode = 301 pCurCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 302 303 #ifdef DBG_UTIL 304 // the old code checks whether we're in a table by asking the 305 // frame. This should yield the same result as searching for the 306 // table box start node, right? 307 SwFrm *pFrm = GetCurrFrm(); 308 DBG_ASSERT( !pFrm->IsInTab() == !(pStartNode != NULL), 309 "Schroedinger's table: We're in a box, and also we aren't." ); 310 #endif 311 312 if( pStartNode == NULL ) 313 return sal_False; 314 315 316 SET_CURR_SHELL( this ); 317 318 // create a table cursor, if there isn't one already 319 if( !pTblCrsr ) 320 { 321 pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); 322 pCurCrsr->DeleteMark(); 323 pCurCrsr->SwSelPaintRects::Hide(); 324 } 325 326 // select the complete box with our shiny new pTblCrsr 327 // 1. delete mark, and move point to first content node in box 328 // 2. set mark, and move point to last content node in box 329 // 3. exchange 330 331 pTblCrsr->DeleteMark(); 332 *(pTblCrsr->GetPoint()) = SwPosition( *pStartNode ); 333 pTblCrsr->Move( fnMoveForward, fnGoNode ); 334 335 pTblCrsr->SetMark(); 336 *(pTblCrsr->GetPoint()) = SwPosition( *(pStartNode->EndOfSectionNode()) ); 337 pTblCrsr->Move( fnMoveBackward, fnGoNode ); 338 339 pTblCrsr->Exchange(); 340 341 // with some luck, UpdateCrsr() will now update everything that 342 // needs updateing 343 UpdateCrsr(); 344 345 return sal_True; 346 } 347 348 // return the next non-protected cell inside a table 349 // rIdx - is on a table node 350 // return: 351 // true - Idx points to content in a suitable cell 352 // false - could not find a suitable cell 353 bool lcl_FindNextCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly ) 354 { 355 // ueberpruefe geschuetzte Zellen 356 SwNodeIndex aTmp( rIdx, 2 ); // TableNode + StartNode 357 358 // the resulting cell should be in that table: 359 const SwTableNode* pTblNd = rIdx.GetNode().GetTableNode(); 360 361 if ( !pTblNd ) 362 { 363 ASSERT( false, "lcl_FindNextCell not celled with table start node!" ) 364 return false; 365 } 366 367 const SwNode* pTableEndNode = pTblNd->EndOfSectionNode(); 368 369 SwNodes& rNds = aTmp.GetNode().GetNodes(); 370 SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode(); 371 372 // no content node => go to next content node 373 if( !pCNd ) 374 pCNd = rNds.GoNext( &aTmp ); 375 376 // robust 377 if ( !pCNd ) 378 return false; 379 380 SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ); 381 382 if ( 0 == pFrm || pCNd->FindTableNode() != pTblNd || 383 (!bInReadOnly && pFrm->IsProtected() ) ) 384 { 385 // we are not located inside a 'valid' cell. We have to continue searching... 386 387 // skip behind current section. This might be the end of the table cell 388 // or behind a inner section or or or... 389 aTmp.Assign( *pCNd->EndOfSectionNode(), 1 ); 390 391 // loop to find a suitable cell... 392 for( ;; ) 393 { 394 SwNode* pNd = &aTmp.GetNode(); 395 396 // we break this loop if we reached the end of the table. 397 // to make this code even more robust, we also break if we are 398 // already behind the table end node: 399 if( pNd == pTableEndNode || /*robust: */ pNd->GetIndex() > pTableEndNode->GetIndex() ) 400 return false; 401 402 // ok, get the next content node: 403 pCNd = aTmp.GetNode().GetCntntNode(); 404 if( 0 == pCNd ) 405 pCNd = rNds.GoNext( &aTmp ); 406 407 // robust: 408 if ( !pCNd ) 409 return false; 410 411 // check if we have found a suitable table cell: 412 pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ); 413 414 if ( 0 != pFrm && pCNd->FindTableNode() == pTblNd && 415 (bInReadOnly || !pFrm->IsProtected() ) ) 416 { 417 // finally, we have found a suitable table cell => set index and return 418 rIdx = *pCNd; 419 return true; 420 } 421 422 // continue behind the current section: 423 aTmp.Assign( *pCNd->EndOfSectionNode(), +1 ); 424 } 425 } 426 427 rIdx = *pCNd; 428 return true; 429 } 430 431 // comments see lcl_FindNextCell 432 bool lcl_FindPrevCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly ) 433 { 434 SwNodeIndex aTmp( rIdx, -2 ); // TableNode + EndNode 435 436 const SwNode* pTableEndNode = &rIdx.GetNode(); 437 const SwTableNode* pTblNd = pTableEndNode->StartOfSectionNode()->GetTableNode(); 438 439 if ( !pTblNd ) 440 { 441 ASSERT( false, "lcl_FindPrevCell not celled with table start node!" ) 442 return false; 443 } 444 445 SwNodes& rNds = aTmp.GetNode().GetNodes(); 446 SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode(); 447 448 if( !pCNd ) 449 pCNd = rNds.GoPrevious( &aTmp ); 450 451 if ( !pCNd ) 452 return false; 453 454 SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ); 455 456 if( 0 == pFrm || pCNd->FindTableNode() != pTblNd || 457 (!bInReadOnly && pFrm->IsProtected() )) 458 { 459 // skip before current section 460 aTmp.Assign( *pCNd->StartOfSectionNode(), -1 ); 461 for( ;; ) 462 { 463 SwNode* pNd = &aTmp.GetNode(); 464 465 if( pNd == pTblNd || pNd->GetIndex() < pTblNd->GetIndex() ) 466 return false; 467 468 pCNd = aTmp.GetNode().GetCntntNode(); 469 if( 0 == pCNd ) 470 pCNd = rNds.GoPrevious( &aTmp ); 471 472 if ( !pCNd ) 473 return false; 474 475 pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ); 476 477 if( 0 != pFrm && pCNd->FindTableNode() == pTblNd && 478 (bInReadOnly || !pFrm->IsProtected() ) ) 479 { 480 rIdx = *pCNd; 481 return true; // Ok, nicht geschuetzt 482 } 483 aTmp.Assign( *pCNd->StartOfSectionNode(), - 1 ); 484 } 485 } 486 487 rIdx = *pCNd; 488 return true; 489 } 490 491 492 sal_Bool GotoPrevTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, 493 sal_Bool bInReadOnly ) 494 { 495 SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); 496 497 SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); 498 if( pTblNd ) 499 { 500 // #i26532#: If we are inside a table, we may not go backward 501 // to the table start node, because we would miss any tables 502 // inside this table. 503 SwTableNode* pInnerTblNd = 0; 504 SwNodeIndex aTmpIdx( aIdx ); 505 while( aTmpIdx.GetIndex() && 506 0 == ( pInnerTblNd = aTmpIdx.GetNode().StartOfSectionNode()->GetTableNode()) ) 507 aTmpIdx--; 508 509 if( pInnerTblNd == pTblNd ) 510 aIdx.Assign( *pTblNd, - 1 ); 511 } 512 513 do { 514 while( aIdx.GetIndex() && 515 0 == ( pTblNd = aIdx.GetNode().StartOfSectionNode()->GetTableNode()) ) 516 aIdx--; 517 518 if( pTblNd ) // gibt einen weiteren TableNode ? 519 { 520 if( fnPosTbl == fnMoveForward ) // an Anfang ? 521 { 522 aIdx = *aIdx.GetNode().StartOfSectionNode(); 523 if( !lcl_FindNextCell( aIdx, bInReadOnly )) 524 { 525 // Tabelle ueberspringen 526 aIdx.Assign( *pTblNd, -1 ); 527 continue; 528 } 529 } 530 else 531 { 532 // ueberpruefe geschuetzte Zellen 533 if( !lcl_FindNextCell( aIdx, bInReadOnly )) 534 { 535 // Tabelle ueberspringen 536 aIdx.Assign( *pTblNd, -1 ); 537 continue; 538 } 539 } 540 541 SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode(); 542 if ( pTxtNode ) 543 { 544 rCurCrsr.GetPoint()->nNode = *pTxtNode; 545 rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? 546 pTxtNode->Len() : 547 0 ); 548 } 549 return sal_True; 550 } 551 } while( pTblNd ); 552 553 return sal_False; 554 } 555 556 557 sal_Bool GotoNextTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, 558 sal_Bool bInReadOnly ) 559 { 560 SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode ); 561 SwTableNode* pTblNd = aIdx.GetNode().FindTableNode(); 562 563 if( pTblNd ) 564 aIdx.Assign( *pTblNd->EndOfSectionNode(), 1 ); 565 566 sal_uLong nLastNd = rCurCrsr.GetDoc()->GetNodes().Count() - 1; 567 do { 568 while( aIdx.GetIndex() < nLastNd && 569 0 == ( pTblNd = aIdx.GetNode().GetTableNode()) ) 570 aIdx++; 571 if( pTblNd ) // gibt einen weiteren TableNode ? 572 { 573 if( fnPosTbl == fnMoveForward ) // an Anfang ? 574 { 575 if( !lcl_FindNextCell( aIdx, bInReadOnly )) 576 { 577 // Tabelle ueberspringen 578 aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 ); 579 continue; 580 } 581 } 582 else 583 { 584 aIdx = *aIdx.GetNode().EndOfSectionNode(); 585 // ueberpruefe geschuetzte Zellen 586 if( !lcl_FindNextCell( aIdx, bInReadOnly )) 587 { 588 // Tabelle ueberspringen 589 aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 ); 590 continue; 591 } 592 } 593 594 SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode(); 595 if ( pTxtNode ) 596 { 597 rCurCrsr.GetPoint()->nNode = *pTxtNode; 598 rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? 599 pTxtNode->Len() : 600 0 ); 601 } 602 return sal_True; 603 } 604 } while( pTblNd ); 605 606 return sal_False; 607 } 608 609 610 sal_Bool GotoCurrTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl, 611 sal_Bool bInReadOnly ) 612 { 613 SwTableNode* pTblNd = rCurCrsr.GetPoint()->nNode.GetNode().FindTableNode(); 614 if( !pTblNd ) 615 return sal_False; 616 617 SwTxtNode* pTxtNode = 0; 618 if( fnPosTbl == fnMoveBackward ) // ans Ende der Tabelle 619 { 620 SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() ); 621 if( !lcl_FindPrevCell( aIdx, bInReadOnly )) 622 return sal_False; 623 pTxtNode = aIdx.GetNode().GetTxtNode(); 624 } 625 else 626 { 627 SwNodeIndex aIdx( *pTblNd ); 628 if( !lcl_FindNextCell( aIdx, bInReadOnly )) 629 return sal_False; 630 pTxtNode = aIdx.GetNode().GetTxtNode(); 631 } 632 633 if ( pTxtNode ) 634 { 635 rCurCrsr.GetPoint()->nNode = *pTxtNode; 636 rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ? 637 pTxtNode->Len() : 638 0 ); 639 } 640 641 return sal_True; 642 } 643 644 645 sal_Bool SwCursor::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl ) 646 { 647 sal_Bool bRet = sal_False; 648 SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this); 649 650 if( pTblCrsr || !HasMark() ) // nur wenn kein Mark oder ein TblCrsr 651 { 652 SwCrsrSaveState aSaveState( *this ); 653 bRet = (*fnWhichTbl)( *this, fnPosTbl, IsReadOnlyAvailable() ) && 654 !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION | 655 nsSwCursorSelOverFlags::SELOVER_TOGGLE ); 656 } 657 return bRet; 658 } 659 660 sal_Bool SwCrsrShell::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl ) 661 { 662 SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, evt. Link callen 663 664 SwShellCrsr* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr; 665 sal_Bool bCheckPos, bRet; 666 sal_uLong nPtNd = 0; 667 xub_StrLen nPtCnt = 0; 668 669 if( !pTblCrsr && pCurCrsr->HasMark() ) // wenn Mark und kein TblCrsr, 670 { 671 // dann auf jedenfall in den Tabellen-Modus schalten 672 pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() ); 673 pCurCrsr->DeleteMark(); 674 pCurCrsr->SwSelPaintRects::Hide(); 675 pTblCrsr->SetMark(); 676 pCrsr = pTblCrsr; 677 bCheckPos = sal_False; 678 } 679 else 680 { 681 bCheckPos = sal_True; 682 nPtNd = pCrsr->GetPoint()->nNode.GetIndex(); 683 nPtCnt = pCrsr->GetPoint()->nContent.GetIndex(); 684 } 685 686 bRet = pCrsr->MoveTable( fnWhichTbl, fnPosTbl ); 687 688 if( bRet ) 689 { 690 //JP 28.10.97: Bug 45028 - die "oberste" Position setzen fuer 691 // wiederholte Kopfzeilen 692 pCrsr->GetPtPos() = Point(); 693 694 UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY); 695 696 if( bCheckPos && 697 pCrsr->GetPoint()->nNode.GetIndex() == nPtNd && 698 pCrsr->GetPoint()->nContent.GetIndex() == nPtCnt ) 699 bRet = sal_False; 700 } 701 return bRet; 702 } 703 704 705 sal_Bool SwCrsrShell::IsTblComplex() const 706 { 707 SwFrm *pFrm = GetCurrFrm( sal_False ); 708 if ( pFrm && pFrm->IsInTab() ) 709 return pFrm->FindTabFrm()->GetTable()->IsTblComplex(); 710 return sal_False; 711 } 712 713 714 sal_Bool SwCrsrShell::IsTblComplexForChart() 715 { 716 sal_Bool bRet = sal_False; 717 718 StartAction(); // IsTblComplexForChart() may trigger table formatting 719 // we better do that inside an action 720 721 const SwTableNode* pTNd = pCurCrsr->GetPoint()->nNode.GetNode().FindTableNode(); 722 if( pTNd ) 723 { 724 // wir stehen in der Tabelle, dann teste mal, ob die Tabelle oder die 725 // Selektion ausgeglichen ist. 726 String sSel; 727 if( pTblCrsr ) 728 sSel = GetBoxNms(); 729 bRet = pTNd->GetTable().IsTblComplexForChart( sSel ); 730 } 731 732 EndAction(); 733 734 return bRet; 735 } 736 737 String SwCrsrShell::GetBoxNms() const 738 { 739 String sNm; 740 const SwPosition* pPos; 741 SwFrm* pFrm; 742 743 if( IsTableMode() ) 744 { 745 SwCntntNode *pCNd = pTblCrsr->Start()->nNode.GetNode().GetCntntNode(); 746 pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0; 747 if( !pFrm ) 748 return sNm; 749 750 do { 751 pFrm = pFrm->GetUpper(); 752 } while ( pFrm && !pFrm->IsCellFrm() ); 753 754 ASSERT( pFrm, "kein Frame zur Box" ); 755 sNm = ((SwCellFrm*)pFrm)->GetTabBox()->GetName(); 756 sNm += ':'; 757 pPos = pTblCrsr->End(); 758 } 759 else 760 { 761 const SwTableNode* pTblNd = IsCrsrInTbl(); 762 if( !pTblNd ) 763 return sNm; 764 pPos = GetCrsr()->GetPoint(); 765 } 766 767 SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode(); 768 pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0; 769 770 if( pFrm ) 771 { 772 do { 773 pFrm = pFrm->GetUpper(); 774 } while ( pFrm && !pFrm->IsCellFrm() ); 775 776 if( pFrm ) 777 sNm += ((SwCellFrm*)pFrm)->GetTabBox()->GetName(); 778 } 779 return sNm; 780 } 781 782 783 sal_Bool SwCrsrShell::GotoTable( const String& rName ) 784 { 785 SwCallLink aLk( *this ); // Crsr-Moves ueberwachen, 786 sal_Bool bRet = !pTblCrsr && pCurCrsr->GotoTable( rName ); 787 if( bRet ) 788 { 789 pCurCrsr->GetPtPos() = Point(); 790 UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE | 791 SwCrsrShell::READONLY ); // und den akt. Updaten 792 } 793 return bRet; 794 } 795 796 797 sal_Bool SwCrsrShell::CheckTblBoxCntnt( const SwPosition* pPos ) 798 { 799 if( !pBoxIdx || !pBoxPtr || IsSelTblCells() || !IsAutoUpdateCells() ) 800 return sal_False; 801 802 // ueberpruefe, ob der Box Inhalt mit dem angegebenen Format der Box 803 // ueber einstimmt. Wenn nicht, setze neu 804 SwTableBox* pChkBox = 0; 805 SwStartNode* pSttNd = 0; 806 if( !pPos ) 807 { 808 // gesicherte Position heraus holen. 809 if( pBoxIdx && pBoxPtr && 810 0 != ( pSttNd = pBoxIdx->GetNode().GetStartNode() ) && 811 SwTableBoxStartNode == pSttNd->GetStartNodeType() && 812 pBoxPtr == pSttNd->FindTableNode()->GetTable(). 813 GetTblBox( pBoxIdx->GetIndex() ) ) 814 pChkBox = pBoxPtr; 815 } 816 else if( 0 != ( pSttNd = pPos->nNode.GetNode(). 817 FindSttNodeByType( SwTableBoxStartNode )) ) 818 { 819 pChkBox = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() ); 820 } 821 822 823 // Box mehr als 1 Absatz? 824 if( pChkBox && pSttNd->GetIndex() + 2 != pSttNd->EndOfSectionIndex() ) 825 pChkBox = 0; 826 827 // jetzt sollten wir mal die Pointer zerstoeren, bevor eine erneute 828 // Actionklammerung kommt. 829 if( !pPos && !pChkBox ) 830 ClearTblBoxCntnt(); 831 832 // liegt der Cursor nicht mehr in dem Bereich ? 833 if( pChkBox && !pPos && 834 ( pCurCrsr->HasMark() || pCurCrsr->GetNext() != pCurCrsr || 835 pSttNd->GetIndex() + 1 == pCurCrsr->GetPoint()->nNode.GetIndex() )) 836 pChkBox = 0; 837 838 //JP 12.01.99: hat sich der Inhalt der Box ueberhaupt veraendert? 839 // Ist wichtig, wenn z.B. Undo nicht den richtigen Inhalt wieder 840 // herstellen konnte. 841 if( pChkBox ) 842 { 843 const SwTxtNode* pNd = GetDoc()->GetNodes()[ 844 pSttNd->GetIndex() + 1 ]->GetTxtNode(); 845 if( !pNd || 846 ( pNd->GetTxt() == ViewShell::GetShellRes()->aCalc_Error && 847 SFX_ITEM_SET == pChkBox->GetFrmFmt()-> 848 GetItemState( RES_BOXATR_FORMULA )) ) 849 pChkBox = 0; 850 } 851 852 if( pChkBox ) 853 { 854 // jetzt sollten wir mal die Pointer zerstoeren, bevor ein weiterer 855 // aufruf kommt. 856 ClearTblBoxCntnt(); 857 StartAction(); 858 GetDoc()->ChkBoxNumFmt( *pChkBox, sal_True ); 859 EndAction(); 860 } 861 862 return 0 != pChkBox; 863 } 864 865 866 void SwCrsrShell::SaveTblBoxCntnt( const SwPosition* pPos ) 867 { 868 if( IsSelTblCells() || !IsAutoUpdateCells() ) 869 return ; 870 871 if( !pPos ) 872 pPos = pCurCrsr->GetPoint(); 873 874 SwStartNode* pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode ); 875 876 sal_Bool bCheckBox = sal_False; 877 if( pSttNd && pBoxIdx ) 878 { 879 if( pSttNd == &pBoxIdx->GetNode() ) 880 pSttNd = 0; // die haben wir schon 881 else 882 bCheckBox = sal_True; 883 } 884 else 885 bCheckBox = 0 != pBoxIdx; 886 887 if( bCheckBox ) 888 { 889 // pBoxIdx Checken 890 SwPosition aPos( *pBoxIdx ); 891 CheckTblBoxCntnt( &aPos ); 892 } 893 894 if( pSttNd ) 895 { 896 pBoxPtr = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() ); 897 898 if( pBoxIdx ) 899 *pBoxIdx = *pSttNd; 900 else 901 pBoxIdx = new SwNodeIndex( *pSttNd ); 902 } 903 } 904 905 906 void SwCrsrShell::ClearTblBoxCntnt() 907 { 908 delete pBoxIdx, pBoxIdx = 0; 909 pBoxPtr = 0; 910 } 911 912 sal_Bool SwCrsrShell::EndAllTblBoxEdit() 913 { 914 sal_Bool bRet = sal_False; 915 ViewShell *pSh = this; 916 do { 917 if( pSh->IsA( TYPE( SwCrsrShell ) ) ) 918 bRet |= ((SwCrsrShell*)pSh)->CheckTblBoxCntnt( 919 ((SwCrsrShell*)pSh)->pCurCrsr->GetPoint() ); 920 921 } while( this != (pSh = (ViewShell *)pSh->GetNext()) ); 922 return bRet; 923 } 924 925 926 927 928