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