File: | home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx |
Warning: | line 591, column 18 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <sal/config.h> | |||
21 | ||||
22 | #include <string_view> | |||
23 | ||||
24 | #include <float.h> | |||
25 | #include <hintids.hxx> | |||
26 | #include <hints.hxx> | |||
27 | #include <fmtfld.hxx> | |||
28 | #include <txtfld.hxx> | |||
29 | #include <frmfmt.hxx> | |||
30 | #include <layfrm.hxx> | |||
31 | #include <cntfrm.hxx> | |||
32 | #include <tabfrm.hxx> | |||
33 | #include <doc.hxx> | |||
34 | #include <IDocumentLayoutAccess.hxx> | |||
35 | #include <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 | ||||
74 | /** Get value of this box. | |||
75 | * | |||
76 | * The value is comes from the first TextNode. If it starts with a number/ | |||
77 | * formula then calculate it, if it starts with a field then get the value. | |||
78 | * All other conditions return 0 (and an error?). | |||
79 | */ | |||
80 | double SwTableBox::GetValue( SwTableCalcPara& rCalcPara ) const | |||
81 | { | |||
82 | double nRet = 0; | |||
83 | ||||
84 | if( rCalcPara.m_rCalc.IsCalcError() ) | |||
85 | return nRet; // stop if there is already an error set | |||
86 | ||||
87 | rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // default: error | |||
88 | ||||
89 | // no content box? | |||
90 | if( !m_pStartNode ) | |||
91 | return nRet; | |||
92 | ||||
93 | if( rCalcPara.IncStackCnt() ) | |||
94 | return nRet; | |||
95 | ||||
96 | rCalcPara.SetLastTableBox( this ); | |||
97 | ||||
98 | // Does it create a recursion? | |||
99 | SwTableBox* pBox = const_cast<SwTableBox*>(this); | |||
100 | if( rCalcPara.m_pBoxStack->find( pBox ) != rCalcPara.m_pBoxStack->end() ) | |||
101 | return nRet; // already on the stack: error | |||
102 | ||||
103 | // re-start with this box | |||
104 | rCalcPara.SetLastTableBox( this ); | |||
105 | ||||
106 | rCalcPara.m_pBoxStack->insert( pBox ); // add | |||
107 | do { // Middle-Check-Loop, so that we can jump from here. Used so that the box pointer | |||
108 | // will be removed from stack at the end. | |||
109 | SwDoc* pDoc = GetFrameFormat()->GetDoc(); | |||
110 | ||||
111 | const SfxPoolItem* pItem; | |||
112 | if( SfxItemState::SET == GetFrameFormat()->GetItemState( | |||
113 | RES_BOXATR_FORMULA, false, &pItem ) ) | |||
114 | { | |||
115 | rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status | |||
116 | if( !static_cast<const SwTableBoxFormula*>(pItem)->IsValid() ) | |||
117 | { | |||
118 | // calculate | |||
119 | const SwTable* pTmp = rCalcPara.m_pTable; | |||
120 | rCalcPara.m_pTable = &pBox->GetSttNd()->FindTableNode()->GetTable(); | |||
121 | const_cast<SwTableBoxFormula*>(static_cast<const SwTableBoxFormula*>(pItem))->Calc( rCalcPara, nRet ); | |||
122 | ||||
123 | if( !rCalcPara.IsStackOverflow() ) | |||
124 | { | |||
125 | SwFrameFormat* pFormat = pBox->ClaimFrameFormat(); | |||
126 | SfxItemSet aTmp( pDoc->GetAttrPool(), | |||
127 | svl::Items<RES_BOXATR_BEGIN,RES_BOXATR_END-1>{} ); | |||
128 | aTmp.Put( SwTableBoxValue( nRet ) ); | |||
129 | if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT )) | |||
130 | aTmp.Put( SwTableBoxNumFormat( 0 )); | |||
131 | pFormat->SetFormatAttr( aTmp ); | |||
132 | } | |||
133 | rCalcPara.m_pTable = pTmp; | |||
134 | } | |||
135 | else | |||
136 | nRet = GetFrameFormat()->GetTableBoxValue().GetValue(); | |||
137 | break; | |||
138 | } | |||
139 | else if( SfxItemState::SET == pBox->GetFrameFormat()->GetItemState( | |||
140 | RES_BOXATR_VALUE, false, &pItem ) ) | |||
141 | { | |||
142 | rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status | |||
143 | nRet = static_cast<const SwTableBoxValue*>(pItem)->GetValue(); | |||
144 | break; | |||
145 | } | |||
146 | ||||
147 | SwTextNode* pTextNd = pDoc->GetNodes()[ m_pStartNode->GetIndex() + 1 ]->GetTextNode(); | |||
148 | if( !pTextNd ) | |||
149 | break; | |||
150 | ||||
151 | sal_Int32 nSttPos = 0; | |||
152 | OUString sText = pTextNd->GetText(); | |||
153 | while ( nSttPos < sText.getLength() && ( sText[nSttPos]==' ' || sText[nSttPos]=='\t' ) ) | |||
154 | ++nSttPos; | |||
155 | ||||
156 | // if there is a calculation field at position 1, get the value of it | |||
157 | const bool bOK = nSttPos<sText.getLength(); | |||
158 | const sal_Unicode Char = bOK ? sText[nSttPos] : 0; | |||
159 | SwTextField * pTextField = nullptr; | |||
160 | if ( bOK && (Char==CH_TXTATR_BREAKWORDu'\x0001' || Char==CH_TXTATR_INWORDu'\xFFF9') ) | |||
161 | { | |||
162 | pTextField = static_txtattr_cast<SwTextField*>(pTextNd->GetTextAttrForCharAt(nSttPos, RES_TXTATR_FIELD)); | |||
163 | } | |||
164 | if ( pTextField != nullptr ) | |||
165 | { | |||
166 | rCalcPara.m_rCalc.SetCalcError( SwCalcError::NONE ); // reset status | |||
167 | ||||
168 | const SwField* pField = pTextField->GetFormatField().GetField(); | |||
169 | switch ( pField->GetTyp()->Which() ) | |||
170 | { | |||
171 | case SwFieldIds::SetExp: | |||
172 | nRet = static_cast<const SwSetExpField*>(pField)->GetValue(rCalcPara.m_pLayout); | |||
173 | break; | |||
174 | case SwFieldIds::User: | |||
175 | nRet = static_cast<const SwUserField*>(pField)->GetValue(); | |||
176 | break; | |||
177 | case SwFieldIds::Table: | |||
178 | { | |||
179 | SwTableField* pTableField = const_cast<SwTableField*>(static_cast<const SwTableField*>(pField)); | |||
180 | if( !pTableField->IsValid() ) | |||
181 | { | |||
182 | // use the right table! | |||
183 | const SwTable* pTmp = rCalcPara.m_pTable; | |||
184 | rCalcPara.m_pTable = &pTextNd->FindTableNode()->GetTable(); | |||
185 | pTableField->CalcField( rCalcPara ); | |||
186 | rCalcPara.m_pTable = pTmp; | |||
187 | } | |||
188 | nRet = pTableField->GetValue(); | |||
189 | } | |||
190 | break; | |||
191 | ||||
192 | case SwFieldIds::DateTime: | |||
193 | nRet = static_cast<const SwDateTimeField*>( pField )->GetValue(); | |||
194 | break; | |||
195 | ||||
196 | case SwFieldIds::JumpEdit: | |||
197 | //JP 14.09.98: Bug 56112 - placeholder never have the right content! | |||
198 | nRet = 0; | |||
199 | break; | |||
200 | ||||
201 | default: | |||
202 | nRet = rCalcPara.m_rCalc.Calculate( pField->ExpandField(true, nullptr) ).GetDouble(); | |||
203 | } | |||
204 | } | |||
205 | else if ( nSttPos < sText.getLength() | |||
206 | && Char == CH_TXT_ATR_INPUTFIELDSTARTu'\x0004' ) | |||
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_BREAKWORDu'\x0001' ) | |||
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_MAX1.7976931348623157e+308 == nRet ) | |||
255 | rCalcPara.m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error | |||
256 | ||||
257 | return nRet; | |||
258 | } | |||
259 | ||||
260 | // structure needed for calculation of tables | |||
261 | ||||
262 | SwTableCalcPara::SwTableCalcPara(SwCalc& rCalculator, const SwTable& rTable, | |||
263 | SwRootFrame const*const pLayout) | |||
264 | : m_pLastTableBox(nullptr) | |||
265 | , m_nStackCount( 0 ) | |||
266 | , m_nMaxSize( cMAXSTACKSIZE ) | |||
267 | , m_pLayout(pLayout) | |||
268 | , m_pBoxStack( new SwTableSortBoxes ) | |||
269 | , m_rCalc( rCalculator ) | |||
270 | , m_pTable( &rTable ) | |||
271 | { | |||
272 | } | |||
273 | ||||
274 | SwTableCalcPara::~SwTableCalcPara() | |||
275 | { | |||
276 | } | |||
277 | ||||
278 | bool SwTableCalcPara::CalcWithStackOverflow() | |||
279 | { | |||
280 | // If a stack overflow was detected, redo with last box. | |||
281 | sal_uInt16 nSaveMaxSize = m_nMaxSize; | |||
282 | ||||
283 | m_nMaxSize = cMAXSTACKSIZE - 5; | |||
284 | sal_uInt16 nCnt = 0; | |||
285 | SwTableBoxes aStackOverflows; | |||
286 | do { | |||
287 | SwTableBox* pBox = const_cast<SwTableBox*>(m_pLastTableBox); | |||
288 | m_nStackCount = 0; | |||
289 | m_rCalc.SetCalcError( SwCalcError::NONE ); | |||
290 | aStackOverflows.insert( aStackOverflows.begin() + nCnt++, pBox ); | |||
291 | ||||
292 | m_pBoxStack->erase( pBox ); | |||
293 | pBox->GetValue( *this ); | |||
294 | } while( IsStackOverflow() ); | |||
295 | ||||
296 | m_nMaxSize = cMAXSTACKSIZE - 3; // decrease at least one level | |||
297 | ||||
298 | // if recursion was detected | |||
299 | m_nStackCount = 0; | |||
300 | m_rCalc.SetCalcError( SwCalcError::NONE ); | |||
301 | m_pBoxStack->clear(); | |||
302 | ||||
303 | while( !m_rCalc.IsCalcError() && nCnt ) | |||
304 | { | |||
305 | aStackOverflows[ --nCnt ]->GetValue( *this ); | |||
306 | if( IsStackOverflow() && !CalcWithStackOverflow() ) | |||
307 | break; | |||
308 | } | |||
309 | ||||
310 | m_nMaxSize = nSaveMaxSize; | |||
311 | aStackOverflows.clear(); | |||
312 | return !m_rCalc.IsCalcError(); | |||
313 | } | |||
314 | ||||
315 | SwTableFormula::SwTableFormula( const OUString& rFormula ) | |||
316 | : m_sFormula( rFormula ) | |||
317 | , m_eNmType( EXTRNL_NAME ) | |||
318 | , m_bValidValue( false ) | |||
319 | { | |||
320 | } | |||
321 | ||||
322 | SwTableFormula::~SwTableFormula() | |||
323 | { | |||
324 | } | |||
325 | ||||
326 | void SwTableFormula::MakeFormula_( const SwTable& rTable, OUStringBuffer& rNewStr, | |||
327 | OUString& rFirstBox, OUString* pLastBox, void* pPara ) const | |||
328 | { | |||
329 | SwTableCalcPara* pCalcPara = static_cast<SwTableCalcPara*>(pPara); | |||
330 | if( pCalcPara->m_rCalc.IsCalcError() ) // stop if there is already an error set | |||
331 | return; | |||
332 | ||||
333 | SwTableBox *pEndBox = nullptr; | |||
334 | ||||
335 | rFirstBox = rFirstBox.copy(1); // erase label of this box | |||
336 | // a region in this area? | |||
337 | if( pLastBox ) | |||
338 | { | |||
339 | pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); | |||
340 | ||||
341 | // Is it actually a valid pointer? | |||
342 | if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) | |||
343 | pEndBox = nullptr; | |||
344 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
345 | } | |||
346 | SwTableBox* pSttBox = reinterpret_cast<SwTableBox*>( | |||
347 | sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); | |||
348 | // Is it actually a valid pointer? | |||
349 | if( rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) | |||
350 | pSttBox = nullptr; | |||
351 | ||||
352 | rNewStr.append(" "); | |||
353 | if( pEndBox && pSttBox ) // area? | |||
354 | { | |||
355 | // get all selected boxes via layout and calculate their values | |||
356 | SwSelBoxes aBoxes; | |||
357 | GetBoxes( *pSttBox, *pEndBox, aBoxes ); | |||
358 | ||||
359 | // don't use empty cells or cells with text content as zeroes in interoperability functions | |||
360 | sal_Int16 nUseOnlyNumber = -1; | |||
361 | ||||
362 | rNewStr.append("("); | |||
363 | bool bDelim = false; | |||
364 | for (size_t n = 0; n < aBoxes.size() && | |||
365 | !pCalcPara->m_rCalc.IsCalcError(); ++n) | |||
366 | { | |||
367 | const SwTableBox* pTableBox = aBoxes[n]; | |||
368 | if ( pTableBox->getRowSpan() >= 1 ) | |||
369 | { | |||
370 | double fVal = pTableBox->GetValue( *pCalcPara ); | |||
371 | ||||
372 | if ( pCalcPara->m_rCalc.IsCalcNotANumber() ) | |||
373 | { | |||
374 | if ( nUseOnlyNumber == -1 ) | |||
375 | { | |||
376 | OUString sFormula = rNewStr.toString().toAsciiUpperCase(); | |||
377 | nUseOnlyNumber = sal_Int16( | |||
378 | sFormula.lastIndexOf("AVERAGE") > -1 || | |||
379 | sFormula.lastIndexOf("COUNT") > -1 || | |||
380 | sFormula.lastIndexOf("PRODUCT") > -1 ); | |||
381 | } | |||
382 | if ( nUseOnlyNumber > 0 ) | |||
383 | continue; | |||
384 | } | |||
385 | ||||
386 | if( bDelim ) | |||
387 | rNewStr.append(cListDelim); | |||
388 | bDelim = true; | |||
389 | rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal )); | |||
390 | } | |||
391 | } | |||
392 | rNewStr.append(")"); | |||
393 | } | |||
394 | else if( pSttBox && !pLastBox ) // only the StartBox? | |||
395 | { | |||
396 | // JP 12.01.99: and no EndBox in the formula! | |||
397 | // calculate the value of the box | |||
398 | if ( pSttBox->getRowSpan() >= 1 ) | |||
399 | { | |||
400 | rNewStr.append("("); | |||
401 | double fVal = pSttBox->GetValue( *pCalcPara ); | |||
402 | // don't use empty cell or a cell with text content as zero in interoperability functions | |||
403 | // (except PRODUCT, where the result is correct anyway) | |||
404 | if ( !pCalcPara->m_rCalc.IsCalcNotANumber() || | |||
405 | ( rNewStr.toString().toAsciiUpperCase().lastIndexOf("AVERAGE") == -1 && | |||
406 | rNewStr.toString().toAsciiUpperCase().lastIndexOf("COUNT") == -1 ) ) | |||
407 | { | |||
408 | rNewStr.append(pCalcPara->m_rCalc.GetStrResult( fVal )); | |||
409 | } | |||
410 | rNewStr.append(")"); | |||
411 | } | |||
412 | } | |||
413 | else | |||
414 | pCalcPara->m_rCalc.SetCalcError( SwCalcError::Syntax ); // set error | |||
415 | rNewStr.append(" "); | |||
416 | } | |||
417 | ||||
418 | void SwTableFormula::RelNmsToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr, | |||
419 | OUString& rFirstBox, OUString* pLastBox, void* pPara ) const | |||
420 | { | |||
421 | // relative name w.r.t. box name (external presentation) | |||
422 | SwNode* pNd = static_cast<SwNode*>(pPara); | |||
423 | OSL_ENSURE( pNd, "Field isn't in any TextNode" )do { if (true && (!(pNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "423" ": "), "%s", "Field isn't in any TextNode"); } } while (false); | |||
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" )do { if (true && (!(pNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "456" ": "), "%s", "Field not placed in any Node"); } } while (false); | |||
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" )do { if (true && (!(pNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "488" ": "), "%s", "Field not placed in any Node"); } } while (false); | |||
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" )do { if (true && (!(pBox))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "496" ": "), "%s", "Field not placed in any Table"); } } while (false); | |||
497 | sRefBoxNm = pBox->GetName(); | |||
498 | } | |||
499 | ||||
500 | rNewStr.append(rFirstBox[0]); // get label for the box | |||
501 | rFirstBox = rFirstBox.copy(1); | |||
502 | if( pLastBox ) | |||
503 | { | |||
504 | rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, *pLastBox, | |||
505 | m_eNmType == EXTRNL_NAME )); | |||
506 | rNewStr.append(":"); | |||
507 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
508 | } | |||
509 | ||||
510 | rNewStr.append(lcl_BoxNmToRel( rTable, *pTableNd, sRefBoxNm, rFirstBox, | |||
511 | m_eNmType == EXTRNL_NAME )); | |||
512 | ||||
513 | // get label for the box | |||
514 | rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); | |||
515 | } | |||
516 | ||||
517 | void SwTableFormula::PtrToBoxNms( const SwTable& rTable, OUStringBuffer& rNewStr, | |||
518 | OUString& rFirstBox, OUString* pLastBox, void* ) const | |||
519 | { | |||
520 | // area in these parentheses? | |||
521 | SwTableBox* pBox; | |||
522 | ||||
523 | rNewStr.append(rFirstBox[0]); // get label for the box | |||
524 | rFirstBox = rFirstBox.copy(1); | |||
525 | if( pLastBox ) | |||
526 | { | |||
527 | pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); | |||
528 | ||||
529 | // Is it actually a valid pointer? | |||
530 | if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() ) | |||
531 | rNewStr.append(pBox->GetName()); | |||
532 | else | |||
533 | rNewStr.append("?"); | |||
534 | rNewStr.append(":"); | |||
535 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
536 | } | |||
537 | ||||
538 | pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); | |||
539 | // Is it actually a valid pointer? | |||
540 | if( rTable.GetTabSortBoxes().find( pBox ) != rTable.GetTabSortBoxes().end() ) | |||
541 | rNewStr.append(pBox->GetName()); | |||
542 | else | |||
543 | rNewStr.append("?"); | |||
544 | ||||
545 | // get label for the box | |||
546 | rNewStr.append(rFirstBox[ rFirstBox.getLength()-1 ]); | |||
547 | } | |||
548 | ||||
549 | void SwTableFormula::BoxNmsToPtr( const SwTable& rTable, OUStringBuffer& rNewStr, | |||
550 | OUString& rFirstBox, OUString* pLastBox, void* ) const | |||
551 | { | |||
552 | // area in these parentheses? | |||
553 | const SwTableBox* pBox; | |||
554 | ||||
555 | rNewStr.append(rFirstBox[0]); // get label for the box | |||
556 | rFirstBox = rFirstBox.copy(1); | |||
557 | if( pLastBox ) | |||
558 | { | |||
559 | pBox = rTable.GetTableBox( *pLastBox ); | |||
560 | rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pBox))) | |||
561 | .append(":"); | |||
562 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
563 | } | |||
564 | ||||
565 | pBox = rTable.GetTableBox( rFirstBox ); | |||
566 | rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pBox))) | |||
567 | .append(rFirstBox[ rFirstBox.getLength()-1 ]); // get label for the box | |||
568 | } | |||
569 | ||||
570 | /// create external formula (for UI) | |||
571 | void SwTableFormula::PtrToBoxNm( const SwTable* pTable ) | |||
572 | { | |||
573 | const SwNode* pNd = nullptr; | |||
574 | FnScanFormula fnFormula = nullptr; | |||
575 | switch (m_eNmType) | |||
| ||||
576 | { | |||
577 | case INTRNL_NAME: | |||
578 | if( pTable ) | |||
579 | fnFormula = &SwTableFormula::PtrToBoxNms; | |||
580 | break; | |||
581 | case REL_NAME: | |||
582 | if( pTable ) | |||
583 | { | |||
584 | fnFormula = &SwTableFormula::RelNmsToBoxNms; | |||
585 | pNd = GetNodeOfFormula(); | |||
586 | } | |||
587 | break; | |||
588 | case EXTRNL_NAME: | |||
589 | return; | |||
590 | } | |||
591 | m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); | |||
| ||||
592 | m_eNmType = EXTRNL_NAME; | |||
593 | } | |||
594 | ||||
595 | /// create internal formula (in CORE) | |||
596 | void SwTableFormula::BoxNmToPtr( const SwTable* pTable ) | |||
597 | { | |||
598 | const SwNode* pNd = nullptr; | |||
599 | FnScanFormula fnFormula = nullptr; | |||
600 | switch (m_eNmType) | |||
601 | { | |||
602 | case EXTRNL_NAME: | |||
603 | if( pTable ) | |||
604 | fnFormula = &SwTableFormula::BoxNmsToPtr; | |||
605 | break; | |||
606 | case REL_NAME: | |||
607 | if( pTable ) | |||
608 | { | |||
609 | fnFormula = &SwTableFormula::RelBoxNmsToPtr; | |||
610 | pNd = GetNodeOfFormula(); | |||
611 | } | |||
612 | break; | |||
613 | case INTRNL_NAME: | |||
614 | return; | |||
615 | } | |||
616 | m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); | |||
617 | m_eNmType = INTRNL_NAME; | |||
618 | } | |||
619 | ||||
620 | /// create relative formula (for copy) | |||
621 | void SwTableFormula::ToRelBoxNm( const SwTable* pTable ) | |||
622 | { | |||
623 | const SwNode* pNd = nullptr; | |||
624 | FnScanFormula fnFormula = nullptr; | |||
625 | switch (m_eNmType) | |||
626 | { | |||
627 | case INTRNL_NAME: | |||
628 | case EXTRNL_NAME: | |||
629 | if( pTable ) | |||
630 | { | |||
631 | fnFormula = &SwTableFormula::BoxNmsToRelNm; | |||
632 | pNd = GetNodeOfFormula(); | |||
633 | } | |||
634 | break; | |||
635 | case REL_NAME: | |||
636 | return; | |||
637 | } | |||
638 | m_sFormula = ScanString( fnFormula, *pTable, const_cast<void*>(static_cast<void const *>(pNd)) ); | |||
639 | m_eNmType = REL_NAME; | |||
640 | } | |||
641 | ||||
642 | OUString SwTableFormula::ScanString( FnScanFormula fnFormula, const SwTable& rTable, | |||
643 | void* pPara ) const | |||
644 | { | |||
645 | OUStringBuffer aStr; | |||
646 | sal_Int32 nFormula = 0; | |||
647 | sal_Int32 nEnd = 0; | |||
648 | ||||
649 | do { | |||
650 | // If the formula is preceded by a name, use this table! | |||
651 | const SwTable* pTable = &rTable; | |||
652 | ||||
653 | sal_Int32 nStt = m_sFormula.indexOf( '<', nFormula ); | |||
654 | if ( nStt>=0 ) | |||
655 | { | |||
656 | while ( nStt>=0 ) | |||
657 | { | |||
658 | const sal_Int32 nNxt = nStt+1; | |||
659 | if (nNxt>=m_sFormula.getLength()) | |||
660 | { | |||
661 | nStt = -1; | |||
662 | break; | |||
663 | } | |||
664 | if ( m_sFormula[nNxt]!=' ' && m_sFormula[nNxt]!='=' ) | |||
665 | break; | |||
666 | nStt = m_sFormula.indexOf( '<', nNxt ); | |||
667 | } | |||
668 | ||||
669 | if ( nStt>=0 ) | |||
670 | // Start searching from current position, which is valid for sure | |||
671 | nEnd = m_sFormula.indexOf( '>', nStt ); | |||
672 | } | |||
673 | if (nStt<0 || nEnd<0 ) | |||
674 | { | |||
675 | // set the rest and finish | |||
676 | aStr.append(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?" )do { if (true && (!(pFnd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "717" ": "), "%s", "No table found. What now?"); } } while (false); | |||
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" )do { if (true && (!(pCNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/fields/cellfml.cxx" ":" "767" ": "), "%s", "Box has no TextNode"); } } while (false ); | |||
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 | long nBox = SwTable::GetBoxNum( sTmp, true ); | |||
894 | nBox -= SwTable::GetBoxNum( sRefBoxNm, true ); | |||
895 | long nLine = SwTable::GetBoxNum( sTmp ); | |||
896 | nLine -= SwTable::GetBoxNum( sRefBoxNm ); | |||
897 | ||||
898 | const OUString sCpy = sTmp; //JP 01.11.95: add rest from box name | |||
899 | ||||
900 | sTmp = OUStringChar(cRelIdentifier) + OUString::number( nBox ) | |||
901 | + OUStringChar(cRelSeparator) + OUString::number( nLine ); | |||
902 | ||||
903 | if (!sCpy.isEmpty()) | |||
904 | { | |||
905 | sTmp += OUStringChar(cRelSeparator) + sCpy; | |||
906 | } | |||
907 | } | |||
908 | ||||
909 | if (sTmp.endsWith(">")) | |||
910 | return sTmp.copy(0, sTmp.getLength()-1 ); | |||
911 | ||||
912 | return sTmp; | |||
913 | } | |||
914 | ||||
915 | void SwTableFormula::GetBoxesOfFormula( const SwTable& rTable, | |||
916 | SwSelBoxes& rBoxes ) | |||
917 | { | |||
918 | rBoxes.clear(); | |||
919 | ||||
920 | BoxNmToPtr( &rTable ); | |||
921 | ScanString( &SwTableFormula::GetFormulaBoxes, rTable, &rBoxes ); | |||
922 | } | |||
923 | ||||
924 | void SwTableFormula::GetFormulaBoxes( const SwTable& rTable, OUStringBuffer& , | |||
925 | OUString& rFirstBox, OUString* pLastBox, void* pPara ) const | |||
926 | { | |||
927 | SwSelBoxes* pBoxes = static_cast<SwSelBoxes*>(pPara); | |||
928 | SwTableBox* pEndBox = nullptr; | |||
929 | ||||
930 | rFirstBox = rFirstBox.copy(1); // delete box label | |||
931 | // area in these parentheses? | |||
932 | if( pLastBox ) | |||
933 | { | |||
934 | pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); | |||
935 | ||||
936 | // Is it actually a valid pointer? | |||
937 | if( rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) | |||
938 | pEndBox = nullptr; | |||
939 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
940 | } | |||
941 | ||||
942 | SwTableBox *pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); | |||
943 | // Is it actually a valid pointer? | |||
944 | if( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) | |||
945 | return; | |||
946 | ||||
947 | if ( pEndBox ) // area? | |||
948 | { | |||
949 | // get all selected boxes via layout and calculate their values | |||
950 | SwSelBoxes aBoxes; | |||
951 | GetBoxes( *pSttBox, *pEndBox, aBoxes ); | |||
952 | pBoxes->insert( aBoxes ); | |||
953 | } | |||
954 | else // only the StartBox? | |||
955 | pBoxes->insert( pSttBox ); | |||
956 | } | |||
957 | ||||
958 | void SwTableFormula::GetBoxes( const SwTableBox& rSttBox, | |||
959 | const SwTableBox& rEndBox, | |||
960 | SwSelBoxes& rBoxes ) | |||
961 | { | |||
962 | // get all selected boxes via layout | |||
963 | const SwLayoutFrame *pStt, *pEnd; | |||
964 | const SwFrame* pFrame = lcl_GetBoxFrame( rSttBox ); | |||
965 | pStt = pFrame ? pFrame->GetUpper() : nullptr; | |||
966 | pFrame = lcl_GetBoxFrame( rEndBox ); | |||
967 | pEnd = pFrame ? pFrame->GetUpper() : nullptr; | |||
968 | if( !pStt || !pEnd ) | |||
969 | return ; // no valid selection | |||
970 | ||||
971 | GetTableSel( pStt, pEnd, rBoxes, nullptr ); | |||
972 | ||||
973 | const SwTable* pTable = pStt->FindTabFrame()->GetTable(); | |||
974 | ||||
975 | // filter headline boxes | |||
976 | if( pTable->GetRowsToRepeat() <= 0 ) | |||
977 | return; | |||
978 | ||||
979 | do { // middle-check loop | |||
980 | const SwTableLine* pLine = rSttBox.GetUpper(); | |||
981 | while( pLine->GetUpper() ) | |||
982 | pLine = pLine->GetUpper()->GetUpper(); | |||
983 | ||||
984 | if( pTable->IsHeadline( *pLine ) ) | |||
985 | break; // headline in this area! | |||
986 | ||||
987 | // maybe start and end are swapped | |||
988 | pLine = rEndBox.GetUpper(); | |||
989 | while ( pLine->GetUpper() ) | |||
990 | pLine = pLine->GetUpper()->GetUpper(); | |||
991 | ||||
992 | if( pTable->IsHeadline( *pLine ) ) | |||
993 | break; // headline in this area! | |||
994 | ||||
995 | const SwTabFrame *pStartTable = pStt->FindTabFrame(); | |||
996 | const SwTabFrame *pEndTable = pEnd->FindTabFrame(); | |||
997 | ||||
998 | if (pStartTable == pEndTable) // no split table | |||
999 | break; | |||
1000 | ||||
1001 | // then remove table headers | |||
1002 | for (size_t n = 0; n < rBoxes.size(); ++n) | |||
1003 | { | |||
1004 | pLine = rBoxes[n]->GetUpper(); | |||
1005 | while( pLine->GetUpper() ) | |||
1006 | pLine = pLine->GetUpper()->GetUpper(); | |||
1007 | ||||
1008 | if( pTable->IsHeadline( *pLine ) ) | |||
1009 | rBoxes.erase( rBoxes.begin() + n-- ); | |||
1010 | } | |||
1011 | } while( false ); | |||
1012 | } | |||
1013 | ||||
1014 | /// Are all boxes valid that are referenced by the formula? | |||
1015 | void SwTableFormula::HasValidBoxes_( const SwTable& rTable, OUStringBuffer& , | |||
1016 | OUString& rFirstBox, OUString* pLastBox, void* pPara ) const | |||
1017 | { | |||
1018 | bool* pBValid = static_cast<bool*>(pPara); | |||
1019 | if( !(*pBValid) ) // wrong is wrong | |||
1020 | return; | |||
1021 | ||||
1022 | SwTableBox* pSttBox = nullptr, *pEndBox = nullptr; | |||
1023 | rFirstBox = rFirstBox.copy(1); // delete identifier of box | |||
1024 | ||||
1025 | // area in this parenthesis? | |||
1026 | if( pLastBox ) | |||
1027 | rFirstBox = rFirstBox.copy( pLastBox->getLength()+1 ); | |||
1028 | ||||
1029 | switch (m_eNmType) | |||
1030 | { | |||
1031 | case INTRNL_NAME: | |||
1032 | if( pLastBox ) | |||
1033 | pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->toInt64())); | |||
1034 | pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.toInt64())); | |||
1035 | break; | |||
1036 | ||||
1037 | case REL_NAME: | |||
1038 | { | |||
1039 | const SwNode* pNd = GetNodeOfFormula(); | |||
1040 | const SwTableBox* pBox = !pNd ? nullptr | |||
1041 | : const_cast<SwTableBox *>(rTable.GetTableBox( | |||
1042 | pNd->FindTableBoxStartNode()->GetIndex() )); | |||
1043 | if( pLastBox ) | |||
1044 | pEndBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, *pLastBox )); | |||
1045 | pSttBox = const_cast<SwTableBox*>(lcl_RelToBox( rTable, pBox, rFirstBox )); | |||
1046 | } | |||
1047 | break; | |||
1048 | ||||
1049 | case EXTRNL_NAME: | |||
1050 | if( pLastBox ) | |||
1051 | pEndBox = const_cast<SwTableBox*>(rTable.GetTableBox( *pLastBox )); | |||
1052 | pSttBox = const_cast<SwTableBox*>(rTable.GetTableBox( rFirstBox )); | |||
1053 | break; | |||
1054 | } | |||
1055 | ||||
1056 | // Are these valid pointers? | |||
1057 | if( ( pLastBox && | |||
1058 | ( !pEndBox || rTable.GetTabSortBoxes().find( pEndBox ) == rTable.GetTabSortBoxes().end() ) ) || | |||
1059 | ( !pSttBox || rTable.GetTabSortBoxes().find( pSttBox ) == rTable.GetTabSortBoxes().end() ) ) | |||
1060 | *pBValid = false; | |||
1061 | } | |||
1062 | ||||
1063 | bool SwTableFormula::HasValidBoxes() const | |||
1064 | { | |||
1065 | bool bRet = true; | |||
1066 | const SwNode* pNd = GetNodeOfFormula(); | |||
1067 | if( pNd && nullptr != ( pNd = pNd->FindTableNode() ) ) | |||
1068 | ScanString( &SwTableFormula::HasValidBoxes_, | |||
1069 | static_cast<const SwTableNode*>(pNd)->GetTable(), &bRet ); | |||
1070 | return bRet; | |||
1071 | } | |||
1072 | ||||
1073 | sal_uInt16 SwTableFormula::GetLnPosInTable( const SwTable& rTable, const SwTableBox* pBox ) | |||
1074 | { | |||
1075 | sal_uInt16 nRet = USHRT_MAX(32767 *2 +1); | |||
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(32767 *2 +1) != nSttLnPos && USHRT_MAX(32767 *2 +1) != 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(32767 *2 +1) != 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(32767 *2 +1) != nSttLnPos && | |||
1200 | rTableUpd.m_nSplitLine <= nSttLnPos && | |||
1201 | pTable == rTableUpd.m_pTable; | |||
1202 | } | |||
1203 | ||||
1204 | // formula goes into new table | |||
1205 | if( rTableUpd.m_bBehindSplitLine ) | |||
1206 | { | |||
1207 | if( !bInNewTable ) | |||
1208 | { | |||
1209 | rTableUpd.m_bModified = true; | |||
1210 | rNewStr.append(rTableUpd.m_pTable->GetFrameFormat()->GetName()).append("."); | |||
1211 | } | |||
1212 | else if( !sTableNm.isEmpty() ) | |||
1213 | rNewStr.append(sTableNm).append("."); | |||
1214 | } | |||
1215 | else if( bInNewTable ) | |||
1216 | { | |||
1217 | rTableUpd.m_bModified = true; | |||
1218 | rNewStr.append(*rTableUpd.m_aData.pNewTableNm).append("."); | |||
1219 | } | |||
1220 | else if( !sTableNm.isEmpty() ) | |||
1221 | rNewStr.append(sTableNm).append("."); | |||
1222 | } | |||
1223 | ||||
1224 | if( pLastBox ) | |||
1225 | rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pEndBox))).append(":"); | |||
1226 | ||||
1227 | rNewStr.append(OUString::number(reinterpret_cast<sal_PtrDiff>(pSttBox))) | |||
1228 | .append(rFirstBox[ rFirstBox.getLength()-1] ); | |||
1229 | } | |||
1230 | ||||
1231 | /// Create external formula but remember that the formula is placed in a split/merged table | |||
1232 | void SwTableFormula::ToSplitMergeBoxNm( SwTableFormulaUpdate& rTableUpd ) | |||
1233 | { | |||
1234 | const SwTable* pTable; | |||
1235 | const SwNode* pNd = GetNodeOfFormula(); | |||
1236 | if( pNd && nullptr != ( pNd = pNd->FindTableNode() )) | |||
1237 | pTable = &static_cast<const SwTableNode*>(pNd)->GetTable(); | |||
1238 | else | |||
1239 | pTable = rTableUpd.m_pTable; | |||
1240 | ||||
1241 | m_sFormula = ScanString( &SwTableFormula::SplitMergeBoxNm_, *pTable, static_cast<void*>(&rTableUpd) ); | |||
1242 | m_eNmType = INTRNL_NAME; | |||
1243 | } | |||
1244 | ||||
1245 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |