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