1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <sal/config.h> 21 22 #include <string_view> 23 24 #include <float.h> 25 #include <hintids.hxx> 26 #include <hints.hxx> 27 #include <fmtfld.hxx> 28 #include <txtfld.hxx> 29 #include <frmfmt.hxx> 30 #include <layfrm.hxx> 31 #include <cntfrm.hxx> 32 #include <tabfrm.hxx> 33 #include <doc.hxx> 34 #include <IDocumentLayoutAccess.hxx> 35 #include <ndtxt.hxx> 36 #include <swtable.hxx> 37 #include <tblsel.hxx> 38 #include <cellfml.hxx> 39 #include <calc.hxx> 40 #include <expfld.hxx> 41 #include <usrfld.hxx> 42 #include <flddat.hxx> 43 #include <cellatr.hxx> 44 #include <ndindex.hxx> 45 #include <frameformats.hxx> 46 #include <comphelper/string.hxx> 47 #include <o3tl/safeint.hxx> 48 #include <osl/diagnose.h> 49 50 namespace 51 { 52 53 const sal_Unicode cRelSeparator = ','; 54 const sal_Unicode cRelIdentifier = '\x12'; // CTRL-R 55 56 enum 57 { 58 cMAXSTACKSIZE = 50 59 }; 60 61 } 62 63 static const SwFrame* lcl_GetBoxFrame( const SwTableBox& rBox ); 64 static sal_Int32 lcl_GetLongBoxNum( OUString& rStr ); 65 static const SwTableBox* lcl_RelToBox( const SwTable& rTable, 66 const SwTableBox* pRefBox, 67 const OUString& sGetName); 68 static OUString lcl_BoxNmToRel( const SwTable& rTable, 69 const SwTableNode& rTableNd, 70 const OUString& sRefBoxNm, 71 const OUString& sGetStr, 72 bool bExtrnlNm); 73 74 /** Get value of this box. 75 * 76 * The value is comes from the first TextNode. If it starts with a number/ 77 * formula then calculate it, if it starts with a field then get the value. 78 * All other conditions return 0 (and an error?). 79 */ 80 double SwTableBox::GetValue( SwTableCalcPara& rCalcPara ) const 81 { 82 double nRet = 0; 83 84 if( rCalcPara.m_rCalc.IsCalcError() ) 85 return nRet; // stop if there is already an error set 86 87 rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // default: error 88 89 // no content box? 90 if( !m_pStartNode ) 91 return nRet; 92 93 if( rCalcPara.IncStackCnt() ) 94 return nRet; 95 96 rCalcPara.SetLastTableBox( this ); 97 98 // Does it create a recursion? 99 SwTableBox* pBox = const_cast<SwTableBox*>(this); 100 if( rCalcPara.m_pBoxStack->find( pBox ) != rCalcPara.m_pBoxStack->end() ) 101 return nRet; // already on the stack: error 102 103 // re-start with this box 104 rCalcPara.SetLastTableBox( this ); 105 106 rCalcPara.m_pBoxStack->insert( pBox ); // add 107 do { // Middle-Check-Loop, so that we can jump from here. Used so that the box pointer 108 // will be removed from stack at the end. 109 SwDoc* pDoc = GetFrameFormat()->GetDoc(); 110 111 const SfxPoolItem* pItem; 112 if( SfxItemState::SET == GetFrameFormat()->GetItemState( 113 RES_BOXATR_FORMULA, false, &pItem ) ) 114 { 115 rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status 116 if( !static_cast<const SwTableBoxFormula*>(pItem)->IsValid() ) 117 { 118 // calculate 119 const SwTable* pTmp = rCalcPara.m_pTable; 120 rCalcPara.m_pTable = &pBox->GetSttNd()->FindTableNode()->GetTable(); 121 const_cast<SwTableBoxFormula*>(static_cast<const SwTableBoxFormula*>(pItem))->Calc( rCalcPara, nRet ); 122 123 if( !rCalcPara.IsStackOverflow() ) 124 { 125 SwFrameFormat* pFormat = pBox->ClaimFrameFormat(); 126 SfxItemSet aTmp( pDoc->GetAttrPool(), 127 svl::Items<RES_BOXATR_BEGIN,RES_BOXATR_END-1>{} ); 128 aTmp.Put( SwTableBoxValue( nRet ) ); 129 if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT )) 130 aTmp.Put( SwTableBoxNumFormat( 0 )); 131 pFormat->SetFormatAttr( aTmp ); 132 } 133 rCalcPara.m_pTable = pTmp; 134 } 135 else 136 nRet = GetFrameFormat()->GetTableBoxValue().GetValue(); 137 break; 138 } 139 else if( SfxItemState::SET == pBox->GetFrameFormat()->GetItemState( 140 RES_BOXATR_VALUE, false, &pItem ) ) 141 { 142 rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status 143 nRet = static_cast<const SwTableBoxValue*>(pItem)->GetValue(); 144 break; 145 } 146 147 SwTextNode* pTextNd = pDoc->GetNodes()[ m_pStartNode->GetIndex() + 1 ]->GetTextNode(); 148 if( !pTextNd ) 149 break; 150 151 sal_Int32 nSttPos = 0; 152 OUString sText = pTextNd->GetText(); 153 while ( nSttPos < sText.getLength() && ( sText[nSttPos]==' ' || sText[nSttPos]=='\t' ) ) 154 ++nSttPos; 155 156 // if there is a calculation field at position 1, get the value of it 157 const bool bOK = nSttPos<sText.getLength(); 158 const sal_Unicode Char = bOK ? sText[nSttPos] : 0; 159 SwTextField * pTextField = nullptr; 160 if ( bOK && (Char==CH_TXTATR_BREAKWORD || Char==CH_TXTATR_INWORD) ) 161 { 162 pTextField = static_txtattr_cast<SwTextField*>(pTextNd->GetTextAttrForCharAt(nSttPos, RES_TXTATR_FIELD)); 163 } 164 if ( pTextField != nullptr ) 165 { 166 rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status 167 168 const SwField* pField = pTextField->GetFormatField().GetField(); 169 switch ( pField->GetTyp()->Which() ) 170 { 171 case SwFieldIds::SetExp: 172 nRet = static_cast<const SwSetExpField*>(pField)->GetValue(rCalcPara.m_pLayout); 173 break; 174 case SwFieldIds::User: 175 nRet = static_cast<const SwUserField*>(pField)->GetValue(); 176 break; 177 case SwFieldIds::Table: 178 { 179 SwTableField* pTableField = const_cast<SwTableField*>(static_cast<const SwTableField*>(pField)); 180 if( !pTableField->IsValid() ) 181 { 182 // use the right table! 183 const SwTable* pTmp = rCalcPara.m_pTable; 184 rCalcPara.m_pTable = &pTextNd->FindTableNode()->GetTable(); 185 pTableField->CalcField( rCalcPara ); 186 rCalcPara.m_pTable = pTmp; 187 } 188 nRet = pTableField->GetValue(); 189 } 190 break; 191 192 case SwFieldIds::DateTime: 193 nRet = static_cast<const SwDateTimeField*>( pField )->GetValue(); 194 break; 195 196 case SwFieldIds::JumpEdit: 197 //JP 14.09.98: Bug 56112 - placeholder never have the right content! 198 nRet = 0; 199 break; 200 201 default: 202 nRet = rCalcPara.m_rCalc.Calculate( pField->ExpandField(true, nullptr) ).GetDouble(); 203 } 204 } 205 else if ( nSttPos < sText.getLength() 206 && Char == CH_TXT_ATR_INPUTFIELDSTART ) 207 { 208 const SwTextInputField * pTextInputField = 209 dynamic_cast< const SwTextInputField* >( 210 pTextNd->GetTextAttrAt( nSttPos, RES_TXTATR_INPUTFIELD ) ); 211 if ( pTextInputField == nullptr ) 212 break; 213 nRet = rCalcPara.m_rCalc.Calculate( pTextInputField->GetFieldContent() ).GetDouble(); 214 } 215 else if ( Char != CH_TXTATR_BREAKWORD ) 216 { 217 // result is 0 but no error! 218 rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status 219 220 double aNum = 0.0; 221 sText = bOK ? sText.copy( nSttPos ) : OUString(); 222 sal_uInt32 nFormatIndex = GetFrameFormat()->GetTableBoxNumFormat().GetValue(); 223 224 SvNumberFormatter* pNumFormatr = pDoc->GetNumberFormatter(); 225 226 const SvNumFormatType nFormatType = pNumFormatr->GetType( nFormatIndex ); 227 if( nFormatType == SvNumFormatType::TEXT ) 228 nFormatIndex = 0; 229 // JP 22.04.98: Bug 49659 - special treatment for percentages 230 else if( !sText.isEmpty() && 231 SvNumFormatType::PERCENT == nFormatType) 232 { 233 sal_uInt32 nTmpFormat = 0; 234 if( pDoc->IsNumberFormat( sText, nTmpFormat, aNum ) && 235 SvNumFormatType::NUMBER == pNumFormatr->GetType( nTmpFormat )) 236 sText += "%"; 237 } 238 239 if( pDoc->IsNumberFormat( sText, nFormatIndex, aNum )) 240 nRet = aNum; 241 else 242 rCalcPara.m_rCalc.SetCalcError( SwCalcError::NaN ); // set for interoperability functions 243 } 244 // ?? otherwise it is an error 245 } while( false ); 246 247 if( !rCalcPara.IsStackOverflow() ) 248 { 249 rCalcPara.m_pBoxStack->erase( pBox ); // remove from stack 250 rCalcPara.DecStackCnt(); 251 } 252 253 //JP 12.01.99: error detection, Bug 60794 254 if( DBL_MAX == nRet ) 255 rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error 256 257 return nRet; 258 } 259 260 // structure needed for calculation of tables 261 262 SwTableCalcPara::SwTableCalcPara(SwCalc& rCalculator, const SwTable& rTable, 263 SwRootFrame const*const pLayout) 264 : m_pLastTableBox(nullptr) 265 , m_nStackCount( 0 ) 266 , m_nMaxSize( cMAXSTACKSIZE ) 267 , m_pLayout(pLayout) 268 , m_pBoxStack( new SwTableSortBoxes ) 269 , m_rCalc( rCalculator ) 270 , m_pTable( &rTable ) 271 { 272 } 273 274 SwTableCalcPara::~SwTableCalcPara() 275 { 276 } 277 278 bool SwTableCalcPara::CalcWithStackOverflow() 279 { 280 // If a stack overflow was detected, redo with last box. 281 sal_uInt16 nSaveMaxSize = m_nMaxSize; 282 283 m_nMaxSize = cMAXSTACKSIZE - 5; 284 sal_uInt16 nCnt = 0; 285 SwTableBoxes aStackOverflows; 286 do { 287 SwTableBox* pBox = const_cast<SwTableBox*>(m_pLastTableBox); 288 m_nStackCount = 0; 289 m_rCalc.SetCalcError( SwCalcError::NONE ); 290 aStackOverflows.insert( aStackOverflows.begin() + nCnt++, pBox ); 291 292 m_pBoxStack->erase( pBox ); 293 pBox->GetValue( *this ); 294 } while( IsStackOverflow() ); 295 296 m_nMaxSize = cMAXSTACKSIZE - 3; // decrease at least one level 297 298 // if recursion was detected 299 m_nStackCount = 0; 300 m_rCalc.SetCalcError( SwCalcError::NONE ); 301 m_pBoxStack->clear(); 302 303 while( !m_rCalc.IsCalcError() && nCnt ) 304 { 305 aStackOverflows[ --nCnt ]->GetValue( *this ); 306 if( IsStackOverflow() && !CalcWithStackOverflow() ) 307 break; 308 } 309 310 m_nMaxSize = nSaveMaxSize; 311 aStackOverflows.clear(); 312 return !m_rCalc.IsCalcError(); 313 } 314 315 SwTableFormula::SwTableFormula( const OUString& rFormula ) 316 : m_sFormula( rFormula ) 317 , m_eNmType( EXTRNL_NAME ) 318 , m_bValidValue( false ) 319 { 320 } 321 322 SwTableFormula::~SwTableFormula() 323 { 324 } 325 326 void SwTableFormula::MakeFormula_( const SwTable& rTable, OUStringBuffer& rNewStr, 327 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 328 { 329 SwTableCalcPara* pCalcPara = static_cast<SwTableCalcPara*>(pPara); 330 if( pCalcPara->m_rCalc.IsCalcError() ) // stop if there is already an error set 331 return; 332 333 SwTableBox *pEndBox = nullptr; 334 335 rFirstBox = rFirstBox.copy(1); // erase label of this box 336 // a region in this area? 337 if( pLastBox ) 338 { 339 pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); 340 341 // Is it actually a valid pointer? 342 if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) 343 pEndBox = nullptr; 344 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 345 } 346 SwTableBox* pSttBox = reinterpret_cast<SwTableBox*>( 347 sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); 348 // Is it actually a valid pointer? 349 if( rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) 350 pSttBox = nullptr; 351 352 rNewStr.append(" "); 353 if( pEndBox && pSttBox ) // area? 354 { 355 // get all selected boxes via layout and calculate their values 356 SwSelBoxes aBoxes; 357 GetBoxes( *pSttBox, *pEndBox, aBoxes ); 358 359 // don't use empty cells or cells with text content as zeroes in interoperability functions 360 sal_Int16 nUseOnlyNumber = -1; 361 362 rNewStr.append("("); 363 bool bDelim = false; 364 for (size_t n = 0; n < aBoxes.size() && 365 !pCalcPara->m_rCalc.IsCalcError(); ++n) 366 { 367 const SwTableBox* pTableBox = aBoxes[n]; 368 if ( pTableBox->getRowSpan() >= 1 ) 369 { 370 double fVal = pTableBox->GetValue( *pCalcPara ); 371 372 if ( pCalcPara->m_rCalc.IsCalcNotANumber() ) 373 { 374 if ( nUseOnlyNumber == -1 ) 375 { 376 OUString sFormula = rNewStr.toString().toAsciiUpperCase(); 377 nUseOnlyNumber = sal_Int16( 378 sFormula.lastIndexOf("AVERAGE") > -1 || 379 sFormula.lastIndexOf("COUNT") > -1 || 380 sFormula.lastIndexOf("PRODUCT") > -1 ); 381 } 382 if ( nUseOnlyNumber > 0 ) 383 continue; 384 } 385 386 if( bDelim ) 387 rNewStr.append(cListDelim); 388 bDelim = true; 389 rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal )); 390 } 391 } 392 rNewStr.append(")"); 393 } 394 else if( pSttBox && !pLastBox ) // only the StartBox? 395 { 396 // JP 12.01.99: and no EndBox in the formula! 397 // calculate the value of the box 398 if ( pSttBox->getRowSpan() >= 1 ) 399 { 400 rNewStr.append("("); 401 double fVal = pSttBox->GetValue( *pCalcPara ); 402 // don't use empty cell or a cell with text content as zero in interoperability functions 403 // (except PRODUCT, where the result is correct anyway) 404 if ( !pCalcPara->m_rCalc.IsCalcNotANumber() || 405 ( rNewStr.toString().toAsciiUpperCase().lastIndexOf("AVERAGE") == -1 && 406 rNewStr.toString().toAsciiUpperCase().lastIndexOf("COUNT") == -1 ) ) 407 { 408 rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal )); 409 } 410 rNewStr.append(")"); 411 } 412 } 413 else 414 pCalcPara->m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error 415 rNewStr.append(" "); 416 } 417 418 void SwTableFormula::RelNmsToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr, 419 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 420 { 421 // relative name w.r.t. box name (external presentation) 422 SwNode* pNd = static_cast<SwNode*>(pPara); 423 OSL_ENSURE( pNd, "Field isn't in any TextNode" ); 424 const SwTableBox *pBox = rTable.GetTableBox( 425 pNd->FindTableBoxStartNode()->GetIndex() ); 426 427 rNewStr.append(rFirstBox[0]); // get label for the box 428 rFirstBox = rFirstBox.copy(1); 429 if( pLastBox ) 430 { 431 const SwTableBox *pRelLastBox = lcl_RelToBox( rTable, pBox, *pLastBox ); 432 if ( pRelLastBox ) 433 rNewStr.append(pRelLastBox->GetName()); 434 else 435 rNewStr.append("A1"); 436 rNewStr.append(":"); 437 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 438 } 439 440 const SwTableBox *pRelFirstBox = lcl_RelToBox( rTable, pBox, rFirstBox ); 441 442 if (pRelFirstBox) 443 rNewStr.append(pRelFirstBox->GetName()); 444 else 445 rNewStr.append("A1"); 446 447 // get label for the box 448 rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); 449 } 450 451 void SwTableFormula::RelBoxNmsToPtr( const SwTable& rTable, OUStringBuffer& rNewStr, 452 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 453 { 454 // relative name w.r.t. box name (internal presentation) 455 SwNode* pNd = static_cast<SwNode*>(pPara); 456 OSL_ENSURE( pNd, "Field not placed in any Node" ); 457 const SwTableBox *pBox = rTable.GetTableBox( 458 pNd->FindTableBoxStartNode()->GetIndex() ); 459 460 rNewStr.append(rFirstBox[0]); // get label for the box 461 rFirstBox = rFirstBox.copy(1); 462 if( pLastBox ) 463 { 464 const SwTableBox *pRelLastBox = lcl_RelToBox( rTable, pBox, *pLastBox ); 465 if ( pRelLastBox ) 466 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pRelLastBox))); 467 else 468 rNewStr.append("0"); 469 rNewStr.append(":"); 470 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 471 } 472 473 const SwTableBox *pRelFirstBox = lcl_RelToBox( rTable, pBox, rFirstBox ); 474 if ( pRelFirstBox ) 475 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pRelFirstBox))); 476 else 477 rNewStr.append("0"); 478 479 // get label for the box 480 rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); 481 } 482 483 void SwTableFormula::BoxNmsToRelNm( const SwTable& rTable, OUStringBuffer& rNewStr, 484 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 485 { 486 // box name (external presentation) w.r.t. relative name 487 SwNode* pNd = static_cast<SwNode*>(pPara); 488 OSL_ENSURE( pNd, "Field not placed in any Node" ); 489 const SwTableNode* pTableNd = pNd->FindTableNode(); 490 491 OUString sRefBoxNm; 492 if( &pTableNd->GetTable() == &rTable ) 493 { 494 const SwTableBox *pBox = rTable.GetTableBox( 495 pNd->FindTableBoxStartNode()->GetIndex() ); 496 OSL_ENSURE( pBox, "Field not placed in any Table" ); 497 sRefBoxNm = pBox->GetName(); 498 } 499 500 rNewStr.append(rFirstBox[0]); // get label for the box 501 rFirstBox = rFirstBox.copy(1); 502 if( pLastBox ) 503 { 504 rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, *pLastBox, 505 m_eNmType == EXTRNL_NAME )); 506 rNewStr.append(":"); 507 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 508 } 509 510 rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, rFirstBox, 511 m_eNmType == EXTRNL_NAME )); 512 513 // get label for the box 514 rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); 515 } 516 517 void SwTableFormula::PtrToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr, 518 OUString& rFirstBox, OUString* pLastBox, void* ) const 519 { 520 // area in these parentheses? 521 SwTableBox* pBox; 522 523 rNewStr.append(rFirstBox[0]); // get label for the box 524 rFirstBox = rFirstBox.copy(1); 525 if( pLastBox ) 526 { 527 pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); 528 529 // Is it actually a valid pointer? 530 if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() ) 531 rNewStr.append(pBox->GetName()); 532 else 533 rNewStr.append("?"); 534 rNewStr.append(":"); 535 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 536 } 537 538 pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); 539 // Is it actually a valid pointer? 540 if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() ) 541 rNewStr.append(pBox->GetName()); 542 else 543 rNewStr.append("?"); 544 545 // get label for the box 546 rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); 547 } 548 549 void SwTableFormula::BoxNmsToPtr( const SwTable& rTable, OUStringBuffer& rNewStr, 550 OUString& rFirstBox, OUString* pLastBox, void* ) const 551 { 552 // area in these parentheses? 553 const SwTableBox* pBox; 554 555 rNewStr.append(rFirstBox[0]); // get label for the box 556 rFirstBox = rFirstBox.copy(1); 557 if( pLastBox ) 558 { 559 pBox = rTable.GetTableBox( *pLastBox ); 560 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pBox))) 561 .append(":"); 562 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 563 } 564 565 pBox = rTable.GetTableBox( rFirstBox ); 566 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pBox))) 567 .append(rFirstBox[ rFirstBox.getLength()-1 ]); // get label for the box 568 } 569 570 /// create external formula (for UI) 571 void SwTableFormula::PtrToBoxNm( const SwTable* pTable ) 572 { 573 const SwNode* pNd = nullptr; 574 FnScanFormula fnFormula = nullptr; 575 switch (m_eNmType) 576 { 577 case INTRNL_NAME: 578 if( pTable ) 579 fnFormula = &SwTableFormula::PtrToBoxNms; 580 break; 581 case REL_NAME: 582 if( pTable ) 583 { 584 fnFormula = &SwTableFormula::RelNmsToBoxNms; 585 pNd = GetNodeOfFormula(); 586 } 587 break; 588 case EXTRNL_NAME: 589 return; 590 } 591 m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); 592 m_eNmType = EXTRNL_NAME; 593 } 594 595 /// create internal formula (in CORE) 596 void SwTableFormula::BoxNmToPtr( const SwTable* pTable ) 597 { 598 const SwNode* pNd = nullptr; 599 FnScanFormula fnFormula = nullptr; 600 switch (m_eNmType) 601 { 602 case EXTRNL_NAME: 603 if( pTable ) 604 fnFormula = &SwTableFormula::BoxNmsToPtr; 605 break; 606 case REL_NAME: 607 if( pTable ) 608 { 609 fnFormula = &SwTableFormula::RelBoxNmsToPtr; 610 pNd = GetNodeOfFormula(); 611 } 612 break; 613 case INTRNL_NAME: 614 return; 615 } 616 m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); 617 m_eNmType = INTRNL_NAME; 618 } 619 620 /// create relative formula (for copy) 621 void SwTableFormula::ToRelBoxNm( const SwTable* pTable ) 622 { 623 const SwNode* pNd = nullptr; 624 FnScanFormula fnFormula = nullptr; 625 switch (m_eNmType) 626 { 627 case INTRNL_NAME: 628 case EXTRNL_NAME: 629 if( pTable ) 630 { 631 fnFormula = &SwTableFormula::BoxNmsToRelNm; 632 pNd = GetNodeOfFormula(); 633 } 634 break; 635 case REL_NAME: 636 return; 637 } 638 m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); 639 m_eNmType = REL_NAME; 640 } 641 642 OUString SwTableFormula::ScanString( FnScanFormula fnFormula, const SwTable& rTable, 643 void* pPara ) const 644 { 645 OUStringBuffer aStr; 646 sal_Int32 nFormula = 0; 647 sal_Int32 nEnd = 0; 648 649 do { 650 // If the formula is preceded by a name, use this table! 651 const SwTable* pTable = &rTable; 652 653 sal_Int32 nStt = m_sFormula.indexOf( '<', nFormula ); 654 if ( nStt>=0 ) 655 { 656 while ( nStt>=0 ) 657 { 658 const sal_Int32 nNxt = nStt+1; 659 if (nNxt>=m_sFormula.getLength()) 660 { 661 nStt = -1; 662 break; 663 } 664 if ( m_sFormula[nNxt]!=' ' && m_sFormula[nNxt]!='=' ) 665 break; 666 nStt = m_sFormula.indexOf( '<', nNxt ); 667 } 668 669 if ( nStt>=0 ) 670 // Start searching from current position, which is valid for sure 671 nEnd = m_sFormula.indexOf( '>', nStt ); 672 } 673 if (nStt<0 || nEnd<0 ) 674 { 675 // set the rest and finish 676 aStr.append(m_sFormula.subView(nFormula)); 677 break; 678 } 679 680 // write beginning 681 aStr.append(m_sFormula.subView(nFormula, nStt - nFormula)); 682 683 if (fnFormula) 684 { 685 sal_Int32 nSeparator = 0; 686 // Is a table name preceded? 687 // JP 16.02.99: SplitMergeBoxNm take care of the name themself 688 // JP 22.02.99: Linux compiler needs cast 689 // JP 28.06.99: rel. BoxName has no preceding tablename! 690 if( fnFormula != &SwTableFormula::SplitMergeBoxNm_ && 691 m_sFormula.getLength()>(nStt+1) && cRelIdentifier != m_sFormula[nStt+1] && 692 (nSeparator = m_sFormula.indexOf( '.', nStt ))>=0 693 && nSeparator < nEnd ) 694 { 695 OUString sTableNm( m_sFormula.copy( nStt, nEnd - nStt )); 696 697 // If there are dots in the name, then they appear in pairs (e.g. A1.1.1)! 698 if( (comphelper::string::getTokenCount(sTableNm, '.') - 1) & 1 ) 699 { 700 sTableNm = sTableNm.copy( 0, nSeparator - nStt ); 701 702 // when creating a formula the table name is unwanted 703 if( fnFormula != &SwTableFormula::MakeFormula_ ) 704 aStr.append(sTableNm); 705 nStt = nSeparator; 706 707 sTableNm = sTableNm.copy( 1 ); // delete separator 708 if( sTableNm != rTable.GetFrameFormat()->GetName() ) 709 { 710 // then search for table 711 const SwTable* pFnd = FindTable( 712 *rTable.GetFrameFormat()->GetDoc(), 713 sTableNm ); 714 if( pFnd ) 715 pTable = pFnd; 716 // ?? 717 OSL_ENSURE( pFnd, "No table found. What now?" ); 718 } 719 } 720 } 721 722 OUString sBox( m_sFormula.copy( nStt, nEnd - nStt + 1 )); 723 // area in these parentheses? 724 nSeparator = m_sFormula.indexOf( ':', nStt ); 725 if ( nSeparator>=0 && nSeparator<nEnd ) 726 { 727 // without opening parenthesis 728 OUString aFirstBox( m_sFormula.copy( nStt+1, nSeparator - nStt - 1 )); 729 (this->*fnFormula)( *pTable, aStr, sBox, &aFirstBox, pPara ); 730 } 731 else 732 (this->*fnFormula)( *pTable, aStr, sBox, nullptr, pPara ); 733 } 734 735 nFormula = nEnd+1; 736 } while( true ); 737 return aStr.makeStringAndClear(); 738 } 739 740 const SwTable* SwTableFormula::FindTable( SwDoc& rDoc, std::u16string_view rNm ) 741 { 742 const SwFrameFormats& rTableFormats = *rDoc.GetTableFrameFormats(); 743 const SwTable* pTmpTable = nullptr, *pRet = nullptr; 744 for( auto nFormatCnt = rTableFormats.size(); nFormatCnt; ) 745 { 746 SwFrameFormat* pFormat = rTableFormats[ --nFormatCnt ]; 747 // if we are called from Sw3Writer, a number is dependent on the format name 748 SwTableBox* pFBox; 749 if ( rNm == pFormat->GetName().getToken(0, 0x0a) && 750 nullptr != ( pTmpTable = SwTable::FindTable( pFormat ) ) && 751 nullptr != (pFBox = pTmpTable->GetTabSortBoxes()[0] ) && 752 pFBox->GetSttNd() && 753 pFBox->GetSttNd()->GetNodes().IsDocNodes() ) 754 { 755 // a table in the normal NodesArr 756 pRet = pTmpTable; 757 break; 758 } 759 } 760 return pRet; 761 } 762 763 static const SwFrame* lcl_GetBoxFrame( const SwTableBox& rBox ) 764 { 765 SwNodeIndex aIdx( *rBox.GetSttNd() ); 766 SwContentNode* pCNd = aIdx.GetNodes().GoNext( &aIdx ); 767 OSL_ENSURE( pCNd, "Box has no TextNode" ); 768 Point aPt; // get the first frame of the layout - table headline 769 std::pair<Point, bool> const tmp(aPt, false); 770 return pCNd->getLayoutFrame(pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp); 771 } 772 773 static sal_Int32 lcl_GetLongBoxNum( OUString& rStr ) 774 { 775 sal_Int32 nRet; 776 const sal_Int32 nPos = rStr.indexOf( cRelSeparator ); 777 if ( nPos<0 ) 778 { 779 nRet = rStr.toInt32(); 780 rStr.clear(); 781 } 782 else 783 { 784 nRet = rStr.copy( 0, nPos ).toInt32(); 785 rStr = rStr.copy( nPos+1 ); 786 } 787 return nRet; 788 } 789 790 static const SwTableBox* lcl_RelToBox( const SwTable& rTable, 791 const SwTableBox* pRefBox, 792 const OUString& _sGetName ) 793 { 794 // get line 795 const SwTableBox* pBox = nullptr; 796 OUString sGetName = _sGetName; 797 798 // Is it really a relative value? 799 if ( cRelIdentifier == sGetName[0] ) // yes 800 { 801 if( !pRefBox ) 802 return nullptr; 803 804 sGetName = sGetName.copy( 1 ); 805 806 const SwTableLines* pLines = &rTable.GetTabLines(); 807 const SwTableBoxes* pBoxes; 808 const SwTableLine* pLine; 809 810 // determine starting values of the box,... 811 pBox = pRefBox; 812 pLine = pBox->GetUpper(); 813 while( pLine->GetUpper() ) 814 { 815 pBox = pLine->GetUpper(); 816 pLine = pBox->GetUpper(); 817 } 818 sal_uInt16 nSttBox = pLine->GetBoxPos( pBox ); 819 sal_uInt16 nSttLine = rTable.GetTabLines().GetPos( pLine ); 820 821 const sal_Int32 nBoxOffset = lcl_GetLongBoxNum( sGetName ) + nSttBox; 822 const sal_Int32 nLineOffset = lcl_GetLongBoxNum( sGetName ) + nSttLine; 823 824 if( nBoxOffset < 0 || 825 nLineOffset < 0 ) 826 return nullptr; 827 828 if( o3tl::make_unsigned(nLineOffset) >= pLines->size() ) 829 return nullptr; 830 831 pLine = (*pLines)[ nLineOffset ]; 832 833 // ... then search the box 834 pBoxes = &pLine->GetTabBoxes(); 835 if( o3tl::make_unsigned(nBoxOffset) >= pBoxes->size() ) 836 return nullptr; 837 pBox = (*pBoxes)[ nBoxOffset ]; 838 839 while (!sGetName.isEmpty()) 840 { 841 nSttBox = SwTable::GetBoxNum( sGetName ); 842 pLines = &pBox->GetTabLines(); 843 if( nSttBox ) 844 --nSttBox; 845 846 nSttLine = SwTable::GetBoxNum( sGetName ); 847 848 // determine line 849 if( !nSttLine || nSttLine > pLines->size() ) 850 break; 851 pLine = (*pLines)[ nSttLine-1 ]; 852 853 // determine box 854 pBoxes = &pLine->GetTabBoxes(); 855 if( nSttBox >= pBoxes->size() ) 856 break; 857 pBox = (*pBoxes)[ nSttBox ]; 858 } 859 860 if( pBox ) 861 { 862 if( !pBox->GetSttNd() ) 863 // "bubble up" to first box 864 while( !pBox->GetTabLines().empty() ) 865 pBox = pBox->GetTabLines().front()->GetTabBoxes().front(); 866 } 867 } 868 else 869 { 870 // otherwise it is an absolute external presentation 871 pBox = rTable.GetTableBox( sGetName ); 872 } 873 return pBox; 874 } 875 876 static OUString lcl_BoxNmToRel( const SwTable& rTable, const SwTableNode& rTableNd, 877 const OUString& _sRefBoxNm, const OUString& _sTmp, bool bExtrnlNm ) 878 { 879 OUString sTmp = _sTmp; 880 OUString sRefBoxNm = _sRefBoxNm; 881 if( !bExtrnlNm ) 882 { 883 // convert into external presentation 884 SwTableBox* pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(sTmp.toInt64())); 885 if( rTable.GetTabSortBoxes().find( pBox ) == rTable.GetTabSortBoxes().end() ) 886 return OUString('?'); 887 sTmp = pBox->GetName(); 888 } 889 890 // If the formula is spanning over a table then keep external presentation 891 if( &rTable == &rTableNd.GetTable() ) 892 { 893 tools::Long nBox = SwTable::GetBoxNum( sTmp, true ); 894 nBox -= SwTable::GetBoxNum( sRefBoxNm, true ); 895 tools::Long nLine = SwTable::GetBoxNum( sTmp ); 896 nLine -= SwTable::GetBoxNum( sRefBoxNm ); 897 898 const OUString sCpy = sTmp; //JP 01.11.95: add rest from box name 899 900 sTmp = OUStringChar(cRelIdentifier) + OUString::number( nBox ) 901 + OUStringChar(cRelSeparator) + OUString::number( nLine ); 902 903 if (!sCpy.isEmpty()) 904 { 905 sTmp += OUStringChar(cRelSeparator) + sCpy; 906 } 907 } 908 909 if (sTmp.endsWith(">")) 910 return sTmp.copy(0, sTmp.getLength()-1 ); 911 912 return sTmp; 913 } 914 915 void SwTableFormula::GetBoxesOfFormula( const SwTable& rTable, 916 SwSelBoxes& rBoxes ) 917 { 918 rBoxes.clear(); 919 920 BoxNmToPtr( &rTable ); 921 ScanString( &SwTableFormula::GetFormulaBoxes, rTable, &rBoxes ); 922 } 923 924 void SwTableFormula::GetFormulaBoxes( const SwTable& rTable, OUStringBuffer& , 925 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 926 { 927 SwSelBoxes* pBoxes = static_cast<SwSelBoxes*>(pPara); 928 SwTableBox* pEndBox = nullptr; 929 930 rFirstBox = rFirstBox.copy(1); // delete box label 931 // area in these parentheses? 932 if( pLastBox ) 933 { 934 pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); 935 936 // Is it actually a valid pointer? 937 if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) 938 pEndBox = nullptr; 939 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 940 } 941 942 SwTableBox *pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); 943 // Is it actually a valid pointer? 944 if( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) 945 return; 946 947 if ( pEndBox ) // area? 948 { 949 // get all selected boxes via layout and calculate their values 950 SwSelBoxes aBoxes; 951 GetBoxes( *pSttBox, *pEndBox, aBoxes ); 952 pBoxes->insert( aBoxes ); 953 } 954 else // only the StartBox? 955 pBoxes->insert( pSttBox ); 956 } 957 958 void SwTableFormula::GetBoxes( const SwTableBox& rSttBox, 959 const SwTableBox& rEndBox, 960 SwSelBoxes& rBoxes ) 961 { 962 // get all selected boxes via layout 963 const SwLayoutFrame *pStt, *pEnd; 964 const SwFrame* pFrame = lcl_GetBoxFrame( rSttBox ); 965 pStt = pFrame ? pFrame->GetUpper() : nullptr; 966 pFrame = lcl_GetBoxFrame( rEndBox ); 967 pEnd = pFrame ? pFrame->GetUpper() : nullptr; 968 if( !pStt || !pEnd ) 969 return ; // no valid selection 970 971 GetTableSel( pStt, pEnd, rBoxes, nullptr ); 972 973 const SwTable* pTable = pStt->FindTabFrame()->GetTable(); 974 975 // filter headline boxes 976 if( pTable->GetRowsToRepeat() <= 0 ) 977 return; 978 979 do { // middle-check loop 980 const SwTableLine* pLine = rSttBox.GetUpper(); 981 while( pLine->GetUpper() ) 982 pLine = pLine->GetUpper()->GetUpper(); 983 984 if( pTable->IsHeadline( *pLine ) ) 985 break; // headline in this area! 986 987 // maybe start and end are swapped 988 pLine = rEndBox.GetUpper(); 989 while ( pLine->GetUpper() ) 990 pLine = pLine->GetUpper()->GetUpper(); 991 992 if( pTable->IsHeadline( *pLine ) ) 993 break; // headline in this area! 994 995 const SwTabFrame *pStartTable = pStt->FindTabFrame(); 996 const SwTabFrame *pEndTable = pEnd->FindTabFrame(); 997 998 if (pStartTable == pEndTable) // no split table 999 break; 1000 1001 // then remove table headers 1002 for (size_t n = 0; n < rBoxes.size(); ++n) 1003 { 1004 pLine = rBoxes[n]->GetUpper(); 1005 while( pLine->GetUpper() ) 1006 pLine = pLine->GetUpper()->GetUpper(); 1007 1008 if( pTable->IsHeadline( *pLine ) ) 1009 rBoxes.erase( rBoxes.begin() + n-- ); 1010 } 1011 } while( false ); 1012 } 1013 1014 /// Are all boxes valid that are referenced by the formula? 1015 void SwTableFormula::HasValidBoxes_( const SwTable& rTable, OUStringBuffer& , 1016 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 1017 { 1018 bool* pBValid = static_cast<bool*>(pPara); 1019 if( !(*pBValid) ) // wrong is wrong 1020 return; 1021 1022 SwTableBox* pSttBox = nullptr, *pEndBox = nullptr; 1023 rFirstBox = rFirstBox.copy(1); // delete identifier of box 1024 1025 // area in this parenthesis? 1026 if( pLastBox ) 1027 rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); 1028 1029 switch (m_eNmType) 1030 { 1031 case INTRNL_NAME: 1032 if( pLastBox ) 1033 pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); 1034 pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); 1035 break; 1036 1037 case REL_NAME: 1038 { 1039 const SwNode* pNd = GetNodeOfFormula(); 1040 const SwTableBox* pBox = !pNd ? nullptr 1041 : const_cast<SwTableBox *>(rTable.GetTableBox( 1042 pNd->FindTableBoxStartNode()->GetIndex() )); 1043 if( pLastBox ) 1044 pEndBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, *pLastBox )); 1045 pSttBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, rFirstBox )); 1046 } 1047 break; 1048 1049 case EXTRNL_NAME: 1050 if( pLastBox ) 1051 pEndBox = const_cast<SwTableBox*>(rTable.GetTableBox( *pLastBox )); 1052 pSttBox = const_cast<SwTableBox*>(rTable.GetTableBox( rFirstBox )); 1053 break; 1054 } 1055 1056 // Are these valid pointers? 1057 if( ( pLastBox && 1058 ( !pEndBox || rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) ) || 1059 ( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) ) 1060 *pBValid = false; 1061 } 1062 1063 bool SwTableFormula::HasValidBoxes() const 1064 { 1065 bool bRet = true; 1066 const SwNode* pNd = GetNodeOfFormula(); 1067 if( pNd && nullptr != ( pNd = pNd->FindTableNode() ) ) 1068 ScanString( &SwTableFormula::HasValidBoxes_, 1069 static_cast<const SwTableNode*>(pNd)->GetTable(), &bRet ); 1070 return bRet; 1071 } 1072 1073 sal_uInt16 SwTableFormula::GetLnPosInTable( const SwTable& rTable, const SwTableBox* pBox ) 1074 { 1075 sal_uInt16 nRet = USHRT_MAX; 1076 if( pBox ) 1077 { 1078 const SwTableLine* pLn = pBox->GetUpper(); 1079 while( pLn->GetUpper() ) 1080 pLn = pLn->GetUpper()->GetUpper(); 1081 nRet = rTable.GetTabLines().GetPos( pLn ); 1082 } 1083 return nRet; 1084 } 1085 1086 void SwTableFormula::SplitMergeBoxNm_( const SwTable& rTable, OUStringBuffer& rNewStr, 1087 OUString& rFirstBox, OUString* pLastBox, void* pPara ) const 1088 { 1089 SwTableFormulaUpdate& rTableUpd = *static_cast<SwTableFormulaUpdate*>(pPara); 1090 1091 rNewStr.append(rFirstBox[0]); // get label for the box 1092 rFirstBox = rFirstBox.copy(1); 1093 1094 OUString sTableNm; 1095 const SwTable* pTable = &rTable; 1096 1097 OUString* pTableNmBox = pLastBox ? pLastBox : &rFirstBox; 1098 1099 const sal_Int32 nLastBoxLen = pTableNmBox->getLength(); 1100 const sal_Int32 nSeparator = pTableNmBox->indexOf('.'); 1101 if ( nSeparator>=0 && 1102 // If there are dots in the name, then these appear in pairs (e.g. A1.1.1)! 1103 (comphelper::string::getTokenCount(*pTableNmBox, '.') - 1) & 1 ) 1104 { 1105 sTableNm = pTableNmBox->copy( 0, nSeparator ); 1106 *pTableNmBox = pTableNmBox->copy( nSeparator + 1); // remove dot 1107 const SwTable* pFnd = FindTable( *rTable.GetFrameFormat()->GetDoc(), sTableNm ); 1108 if( pFnd ) 1109 pTable = pFnd; 1110 1111 if( TBL_MERGETBL == rTableUpd.m_eFlags ) 1112 { 1113 if( pFnd ) 1114 { 1115 if( pFnd == rTableUpd.m_aData.pDelTable ) 1116 { 1117 if( rTableUpd.m_pTable != &rTable ) // not the current one 1118 rNewStr.append(rTableUpd.m_pTable->GetFrameFormat()->GetName()).append("."); // set new table name 1119 rTableUpd.m_bModified = true; 1120 } 1121 else if( pFnd != rTableUpd.m_pTable || 1122 ( rTableUpd.m_pTable != &rTable && &rTable != rTableUpd.m_aData.pDelTable)) 1123 rNewStr.append(sTableNm).append("."); // keep table name 1124 else 1125 rTableUpd.m_bModified = true; 1126 } 1127 else 1128 rNewStr.append(sTableNm).append("."); // keep table name 1129 } 1130 } 1131 if( pTableNmBox == pLastBox ) 1132 rFirstBox = rFirstBox.copy( nLastBoxLen + 1 ); 1133 1134 SwTableBox* pSttBox = nullptr, *pEndBox = nullptr; 1135 switch (m_eNmType) 1136 { 1137 case INTRNL_NAME: 1138 if( pLastBox ) 1139 pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); 1140 pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); 1141 break; 1142 1143 case REL_NAME: 1144 { 1145 const SwNode* pNd = GetNodeOfFormula(); 1146 const SwTableBox* pBox = pNd ? pTable->GetTableBox( 1147 pNd->FindTableBoxStartNode()->GetIndex() ) : nullptr; 1148 if( pLastBox ) 1149 pEndBox = const_cast<SwTableBox*>(lcl_RelToBox( *pTable, pBox, *pLastBox )); 1150 pSttBox = const_cast<SwTableBox*>(lcl_RelToBox( *pTable, pBox, rFirstBox )); 1151 } 1152 break; 1153 1154 case EXTRNL_NAME: 1155 if( pLastBox ) 1156 pEndBox = const_cast<SwTableBox*>(pTable->GetTableBox( *pLastBox )); 1157 pSttBox = const_cast<SwTableBox*>(pTable->GetTableBox( rFirstBox )); 1158 break; 1159 } 1160 1161 if( pLastBox && pTable->GetTabSortBoxes().find( pEndBox ) == pTable->GetTabSortBoxes().end() ) 1162 pEndBox = nullptr; 1163 if( pTable->GetTabSortBoxes().find( pSttBox ) == pTable->GetTabSortBoxes().end() ) 1164 pSttBox = nullptr; 1165 1166 if( TBL_SPLITTBL == rTableUpd.m_eFlags ) 1167 { 1168 // Where are the boxes - in the old or in the new table? 1169 bool bInNewTable = false; 1170 if( pLastBox ) 1171 { 1172 // It is the "first" box in this selection. It determines if the formula is placed in 1173 // the new or the old table. 1174 sal_uInt16 nEndLnPos = SwTableFormula::GetLnPosInTable( *pTable, pEndBox ), 1175 nSttLnPos = SwTableFormula::GetLnPosInTable( *pTable, pSttBox ); 1176 1177 if( USHRT_MAX != nSttLnPos && USHRT_MAX != nEndLnPos && 1178 ((rTableUpd.m_nSplitLine <= nSttLnPos) == 1179 (rTableUpd.m_nSplitLine <= nEndLnPos)) ) 1180 { 1181 // stay in same table 1182 bInNewTable = rTableUpd.m_nSplitLine <= nEndLnPos && 1183 pTable == rTableUpd.m_pTable; 1184 } 1185 else 1186 { 1187 // this is definitely an invalid formula, also mark as modified for Undo 1188 rTableUpd.m_bModified = true; 1189 if( pEndBox ) 1190 bInNewTable = USHRT_MAX != nEndLnPos && 1191 rTableUpd.m_nSplitLine <= nEndLnPos && 1192 pTable == rTableUpd.m_pTable; 1193 } 1194 } 1195 else 1196 { 1197 sal_uInt16 nSttLnPos = SwTableFormula::GetLnPosInTable( *pTable, pSttBox ); 1198 // Put it in the new table? 1199 bInNewTable = USHRT_MAX != nSttLnPos && 1200 rTableUpd.m_nSplitLine <= nSttLnPos && 1201 pTable == rTableUpd.m_pTable; 1202 } 1203 1204 // formula goes into new table 1205 if( rTableUpd.m_bBehindSplitLine ) 1206 { 1207 if( !bInNewTable ) 1208 { 1209 rTableUpd.m_bModified = true; 1210 rNewStr.append(rTableUpd.m_pTable->GetFrameFormat()->GetName()).append("."); 1211 } 1212 else if( !sTableNm.isEmpty() ) 1213 rNewStr.append(sTableNm).append("."); 1214 } 1215 else if( bInNewTable ) 1216 { 1217 rTableUpd.m_bModified = true; 1218 rNewStr.append(*rTableUpd.m_aData.pNewTableNm).append("."); 1219 } 1220 else if( !sTableNm.isEmpty() ) 1221 rNewStr.append(sTableNm).append("."); 1222 } 1223 1224 if( pLastBox ) 1225 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pEndBox))).append(":"); 1226 1227 rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pSttBox))) 1228 .append(rFirstBox[ rFirstBox.getLength()-1] ); 1229 } 1230 1231 /// Create external formula but remember that the formula is placed in a split/merged table 1232 void SwTableFormula::ToSplitMergeBoxNm( SwTableFormulaUpdate& rTableUpd ) 1233 { 1234 const SwTable* pTable; 1235 const SwNode* pNd = GetNodeOfFormula(); 1236 if( pNd && nullptr != ( pNd = pNd->FindTableNode() )) 1237 pTable = &static_cast<const SwTableNode*>(pNd)->GetTable(); 1238 else 1239 pTable = rTableUpd.m_pTable; 1240 1241 m_sFormula = ScanString( &SwTableFormula::SplitMergeBoxNm_, *pTable, static_cast<void*>(&rTableUpd) ); 1242 m_eNmType = INTRNL_NAME; 1243 } 1244 1245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1246
