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 <docary.hxx>
36 #include <ndtxt.hxx>
37 #include <swtable.hxx>
38 #include <tblsel.hxx>
39 #include <cellfml.hxx>
40 #include <calc.hxx>
41 #include <expfld.hxx>
42 #include <usrfld.hxx>
43 #include <flddat.hxx>
44 #include <cellatr.hxx>
45 #include <ndindex.hxx>
46 #include <frameformats.hxx>
47 #include <comphelper/string.hxx>
48 #include <o3tl/safeint.hxx>
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 
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(),
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  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 
193  nRet = static_cast<const SwDateTimeField*>( pField )->GetValue();
194  break;
195 
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 
275 {
276 }
277 
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;
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;
301  m_pBoxStack->clear();
302 
303  while( !m_rCalc.IsCalcError() && nCnt )
304  {
305  aStackOverflows[ --nCnt ]->GetValue( *this );
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 
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 
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)) );
593 }
594 
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)) );
618 }
619 
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)) );
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(std::u16string_view(m_sFormula).substr(nFormula));
677  break;
678  }
679 
680  // write beginning
681  aStr.append(std::u16string_view(m_sFormula).substr(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, const OUString& 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 
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 
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 
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 
1064 {
1065  bool bRet = true;
1066  const SwNode* pNd = GetNodeOfFormula();
1067  if( pNd && nullptr != ( pNd = pNd->FindTableNode() ) )
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 
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) );
1243 }
1244 
1245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwTableBoxNumFormat & GetTableBoxNumFormat(bool=true) const
TableBox attributes - implemented in cellatr.hxx.
Definition: cellatr.hxx:105
Base class of the Writer layout elements.
Definition: frame.hxx:298
bool CalcWithStackOverflow()
Definition: cellfml.cxx:278
Definition: calc.hxx:191
sal_uLong GetIndex() const
Definition: node.hxx:290
void CalcField(SwTableCalcPara &rCalcPara)
Definition: tblcalc.cxx:44
SwTableCalcPara(SwCalc &rCalculator, const SwTable &rTable, SwRootFrame const *pLayout)
Definition: cellfml.cxx:262
static const SwTableBox * lcl_RelToBox(const SwTable &rTable, const SwTableBox *pRefBox, const OUString &sGetName)
Definition: cellfml.cxx:790
void SetLastTableBox(const SwTableBox *pBox)
Definition: cellfml.hxx:55
const SwField * GetField() const
Definition: fmtfld.hxx:111
const SwTableBox * GetTableBox(const OUString &rName, const bool bPerformValidCheck=false) const
Definition: swtable.cxx:1327
union SwTableFormulaUpdate::@26 m_aData
void RelNmsToBoxNms(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:418
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
const OUString & GetText() const
Definition: ndtxt.hxx:212
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1409
constexpr TypedWhichId< SwTableBoxValue > RES_BOXATR_VALUE(150)
const SwFrameFormats * GetTableFrameFormats() const
Definition: doc.hxx:810
const SwTable * GetTable() const
Definition: tabfrm.hxx:144
long Long
const SwTable * m_pTable
current table
Definition: cellfml.hxx:46
Base class of all fields.
Definition: fldbas.hxx:289
bool IsCalcError() const
Definition: calc.hxx:246
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
const SwTableBox * m_pLastTableBox
Definition: cellfml.hxx:39
sal_Int64 n
Definition: doc.hxx:186
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:351
bool IsCalcNotANumber() const
Definition: calc.hxx:247
sal_uInt16 GetRowsToRepeat() const
Definition: swtable.hxx:195
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:1694
SwTableLine * front() const
Definition: swtable.hxx:80
The root element of a Writer document layout.
Definition: rootfrm.hxx:82
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:203
sal_Int32 getTokenCount(const OString &rIn, char cTok)
size_type size() const
Definition: swtable.hxx:75
OUString m_sFormula
current formula
Definition: cellfml.hxx:92
sal_Int32 getRowSpan() const
Definition: swtable.cxx:74
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:3022
#define CH_TXTATR_BREAKWORD
Definition: hintids.hxx:169
bool HasValidBoxes() const
Definition: cellfml.cxx:1063
sal_uInt16 sal_Unicode
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
void BoxNmToPtr(const SwTable *pTable)
create from the external formula the internal
Definition: cellfml.cxx:596
sal_uInt16 m_nMaxSize
Definition: cellfml.hxx:40
sal_uInt16 m_nStackCount
Definition: cellfml.hxx:40
#define CH_TXT_ATR_INPUTFIELDSTART
Definition: hintids.hxx:173
const OUString & GetName() const
Definition: format.hxx:111
const SwTable * m_pTable
Pointer to the current table.
Definition: hints.hxx:239
SwTableFormula(const OUString &rFormula)
Definition: cellfml.cxx:315
const SwTable & GetTable() const
Definition: node.hxx:500
OUString ScanString(FnScanFormula fnFormula, const SwTable &rTable, void *) const
Definition: cellfml.cxx:642
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
size_type size() const
static sal_uInt16 GetLnPosInTable(const SwTable &rTable, const SwTableBox *pBox)
Definition: cellfml.cxx:1073
void PtrToBoxNms(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:517
SW_DLLPUBLIC void PtrToBoxNm(const SwTable *pTable)
create from the internal formula (for CORE) the external formula (for UI)
Definition: cellfml.cxx:571
Specific frame formats (frames, DrawObjects).
const SwStartNode * m_pStartNode
Definition: swtable.hxx:403
void DecStackCnt()
Definition: cellfml.hxx:54
SwTableSortBoxes & GetTabSortBoxes()
Definition: swtable.hxx:261
double GetValue(SwTableCalcPara &rPara) const
Get value of this box.
Definition: cellfml.cxx:80
NameType m_eNmType
current display method
Definition: cellfml.hxx:93
OUString GetName() const
Definition: swtable.cxx:1812
bool IncStackCnt()
Definition: cellfml.hxx:53
OUString GetFieldContent() const
Definition: atrfld.cxx:646
static SwTable * FindTable(SwFrameFormat const *const pFormat)
Definition: swtable.cxx:1905
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
Style of a layout element.
Definition: frmfmt.hxx:58
The non-shared part of a user field.
Definition: usrfld.hxx:103
void GetTableSel(const SwCursorShell &rShell, SwSelBoxes &rBoxes, const SwTableSearchType eSearchType)
Definition: tblsel.cxx:149
bool IsValid() const
Definition: cellfml.hxx:133
bool empty() const
Definition: swtable.hxx:74
SwRootFrame const *const m_pLayout
layout to access text field results
Definition: cellfml.hxx:43
constexpr sal_uInt16 RES_BOXATR_END(151)
SwLayoutFrame * GetUpper()
Definition: frame.hxx:661
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
virtual ~SwTableFormula()
Definition: cellfml.cxx:322
void SetCalcError(SwCalcError eErr)
Definition: calc.hxx:245
SvNumFormatType
static const SwTable * FindTable(SwDoc &rDoc, const OUString &rNm)
Definition: cellfml.cxx:740
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:399
static void GetBoxes(const SwTableBox &rStt, const SwTableBox &rEnd, SwSelBoxes &rBoxes)
Definition: cellfml.cxx:958
constexpr sal_uInt16 RES_BOXATR_BEGIN(RES_GRFATR_END)
Marks a node in the document model.
Definition: ndindex.hxx:31
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:432
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:696
bool IsStackOverflow() const
Definition: cellfml.hxx:52
void ToSplitMergeBoxNm(SwTableFormulaUpdate &rTableUpd)
gets called before/after merging/splitting of tables
Definition: cellfml.cxx:1232
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:237
void GetBoxesOfFormula(const SwTable &rTable, SwSelBoxes &rBoxes)
Definition: cellfml.cxx:915
const_iterator end() const
void MakeFormula_(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:326
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:119
void GetFormulaBoxes(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:924
static sal_uInt16 GetBoxNum(OUString &rStr, bool bFirst=false, const bool bPerformValidCheck=false)
Definition: swtable.cxx:1267
void BoxNmsToRelNm(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:483
sal_uInt16 GetBoxPos(const SwTableBox *pBox) const
Definition: swtable.hxx:363
SwTableLines & GetTabLines()
Definition: swtable.hxx:200
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:111
std::unique_ptr< SwTableSortBoxes > m_pBoxStack
stack for recognizing recursion
Definition: cellfml.hxx:44
SwTableLines & GetTabLines()
Definition: swtable.hxx:425
SwFieldType * GetTyp() const
Definition: fldbas.hxx:392
const_iterator begin() const
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:461
void RelBoxNmsToPtr(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:451
const SwTableBoxValue & GetTableBoxValue(bool=true) const
Definition: cellatr.hxx:109
SwSbxValue Calculate(const OUString &rStr)
Definition: calc.cxx:358
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:80
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:361
static sal_Int32 lcl_GetLongBoxNum(OUString &rStr)
Definition: cellfml.cxx:773
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:455
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:104
constexpr TypedWhichId< SwTableBoxFormula > RES_BOXATR_FORMULA(149)
void Calc(SwTableCalcPara &rCalcPara, double &rValue)
Definition: cellatr.cxx:186
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:446
void(SwTableFormula::* FnScanFormula)(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *) const
Definition: cellfml.hxx:60
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:254
void HasValidBoxes_(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Are all boxes valid that are referenced by the formula?
Definition: cellfml.cxx:1015
void BoxNmsToPtr(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:549
SwNodes & GetNodes()
Definition: doc.hxx:405
void ToRelBoxNm(const SwTable *pTable)
create from the external/internal formula the relative formula
Definition: cellfml.cxx:621
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:393
static const SwFrame * lcl_GetBoxFrame(const SwTableBox &rBox)
Definition: cellfml.cxx:763
OUString GetStrResult(const SwSbxValue &rValue)
Definition: calc.cxx:386
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1689
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
const SwStartNode * FindTableBoxStartNode() const
Definition: node.hxx:196
bool IsHeadline(const SwTableLine &rLine) const
Definition: tabfrm.cxx:5565
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:355
SwTableBox * GetUpper()
Definition: swtable.hxx:369
bool IsNumberFormat(const OUString &rString, sal_uInt32 &F_Index, double &fOutNumber)
Definition: ndtbl.cxx:4016
void SplitMergeBoxNm_(const SwTable &, OUStringBuffer &, OUString &, OUString *, void *pPara) const
Definition: cellfml.cxx:1086
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:2320
sal_uInt16 GetPos(const SwTableLine *pBox) const
Definition: swtable.hxx:97
virtual const SwNode * GetNodeOfFormula() const =0
size_t size() const
const SwTable * pDelTable
Merge: Pointer to the table to be removed.
Definition: hints.hxx:241
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:40
TableFormulaUpdateFlags m_eFlags
Definition: hints.hxx:246
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:876
const OUString * pNewTableNm
Split: the name of the new table.
Definition: hints.hxx:242
SwTableLine * GetUpper()
Definition: swtable.hxx:428
SwFieldIds Which() const
Definition: fldbas.hxx:272
virtual double GetValue() const
Definition: fldbas.cxx:716
aStr
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1284
SwCalc & m_rCalc
current Calculator
Definition: cellfml.hxx:45
sal_uInt16 nPos
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1317
sal_uInt16 m_nSplitLine
Split: from this BaseLine on will be split.
Definition: hints.hxx:245
size_type erase(const Value &x)
SwTabFrame * FindTabFrame()
Definition: frame.hxx:1080
Base class of the Writer document model elements.
Definition: node.hxx:79