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 #include <DocumentFieldsManager.hxx>
20 #include <config_features.h>
21 #include <doc.hxx>
22 #include <IDocumentUndoRedo.hxx>
23 #include <IDocumentState.hxx>
24 #include <IDocumentRedlineAccess.hxx>
25 #include <redline.hxx>
26 #include <rootfrm.hxx>
27 #include <dbmgr.hxx>
28 #include <chpfld.hxx>
29 #include <dbfld.hxx>
30 #include <reffld.hxx>
31 #include <flddropdown.hxx>
32 #include <strings.hrc>
33 #include <SwUndoField.hxx>
34 #include <flddat.hxx>
35 #include <cntfrm.hxx>
36 #include <section.hxx>
37 #include <docufld.hxx>
38 #include <calbck.hxx>
39 #include <cellatr.hxx>
40 #include <swtable.hxx>
41 #include <frmfmt.hxx>
42 #include <fmtfld.hxx>
43 #include <ndtxt.hxx>
44 #include <txtfld.hxx>
45 #include <docfld.hxx>
46 #include <hints.hxx>
47 #include <docary.hxx>
48 #include <fldbas.hxx>
49 #include <expfld.hxx>
50 #include <ddefld.hxx>
51 #include <authfld.hxx>
52 #include <usrfld.hxx>
53 #include <ndindex.hxx>
54 #include <pam.hxx>
55 #include <o3tl/deleter.hxx>
56 #include <osl/diagnose.h>
57 #include <unotools/transliterationwrapper.hxx>
58 #include <comphelper/scopeguard.hxx>
59 #include <com/sun/star/uno/Any.hxx>
60
61 using namespace ::com::sun::star::uno;
62
63 namespace sw
64 {
IsFieldDeletedInModel(IDocumentRedlineAccess const & rIDRA,SwTextField const & rTextField)65 bool IsFieldDeletedInModel(IDocumentRedlineAccess const& rIDRA,
66 SwTextField const& rTextField)
67 {
68 SwRedlineTable::size_type tmp;
69 SwPosition const pos(rTextField.GetTextNode(),
70 rTextField.GetStart());
71 SwRangeRedline const*const pRedline(rIDRA.GetRedline(pos, &tmp));
72 return (pRedline
73 && pRedline->GetType() == RedlineType::Delete
74 && *pRedline->GetPoint() != *pRedline->GetMark());
75 }
76 }
77
78 namespace
79 {
80 #if HAVE_FEATURE_DBCONNECTIVITY
81
lcl_GetDBVarName(SwDoc & rDoc,SwDBNameInfField & rDBField)82 OUString lcl_GetDBVarName( SwDoc& rDoc, SwDBNameInfField& rDBField )
83 {
84 SwDBData aDBData( rDBField.GetDBData( &rDoc ));
85 OUString sDBNumNm;
86 SwDBData aDocData = rDoc.GetDBData();
87
88 if( aDBData != aDocData )
89 {
90 sDBNumNm = aDBData.sDataSource + OUStringChar(DB_DELIM)
91 + aDBData.sCommand + OUStringChar(DB_DELIM);
92 }
93 sDBNumNm += SwFieldType::GetTypeStr(SwFieldTypesEnum::DatabaseSetNumber);
94
95 return sDBNumNm;
96 }
97
98 #endif
99
IsFieldDeleted(IDocumentRedlineAccess const & rIDRA,SwRootFrame const & rLayout,SwTextField const & rTextField)100 bool IsFieldDeleted(IDocumentRedlineAccess const& rIDRA,
101 SwRootFrame const& rLayout, SwTextField const& rTextField)
102 {
103 SwTextNode const& rNode(rTextField.GetTextNode());
104 bool const isInBody(
105 rNode.GetNodes().GetEndOfExtras().GetIndex() < rNode.GetIndex());
106 if (!isInBody && nullptr == rNode.getLayoutFrame(&rLayout))
107 { // see SwDocUpdateField::GetBodyNode() - fields in hidden sections
108 // don't have layout frames but must be updated, so use the same
109 // check as there, but do it again because GetBodyNode() checks
110 // for *any* layout...
111 return true;
112 }
113 return sw::IsFieldDeletedInModel(rIDRA, rTextField);
114 }
115
lcl_CalcField(SwDoc & rDoc,SwCalc & rCalc,const SetGetExpField & rSGEField,SwDBManager * pMgr,SwRootFrame const * const pLayout)116 void lcl_CalcField( SwDoc& rDoc, SwCalc& rCalc, const SetGetExpField& rSGEField,
117 SwDBManager* pMgr, SwRootFrame const*const pLayout)
118 {
119 const SwTextField* pTextField = rSGEField.GetTextField();
120 if( !pTextField )
121 return ;
122
123 if (pLayout && pLayout->IsHideRedlines()
124 && IsFieldDeleted(rDoc.getIDocumentRedlineAccess(), *pLayout, *pTextField))
125 {
126 return;
127 }
128
129 const SwField* pField = pTextField->GetFormatField().GetField();
130 const SwFieldIds nFieldWhich = pField->GetTyp()->Which();
131
132 if( SwFieldIds::SetExp == nFieldWhich )
133 {
134 SwSbxValue aValue;
135 if( nsSwGetSetExpType::GSE_EXPR & pField->GetSubType() )
136 aValue.PutDouble( static_cast<const SwSetExpField*>(pField)->GetValue(pLayout) );
137 else
138 // Extension to calculate with Strings
139 aValue.PutString( static_cast<const SwSetExpField*>(pField)->GetExpStr(pLayout) );
140
141 // set the new value in Calculator
142 rCalc.VarChange( pField->GetTyp()->GetName(), aValue );
143 }
144 else if( pMgr )
145 {
146 #if !HAVE_FEATURE_DBCONNECTIVITY
147 (void) rDoc;
148 #else
149 switch( nFieldWhich )
150 {
151 case SwFieldIds::DbNumSet:
152 {
153 SwDBNumSetField* pDBField = const_cast<SwDBNumSetField*>(static_cast<const SwDBNumSetField*>(pField));
154
155 SwDBData aDBData(pDBField->GetDBData(&rDoc));
156
157 if( pDBField->IsCondValid() &&
158 pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
159 rCalc.VarChange( lcl_GetDBVarName( rDoc, *pDBField),
160 pDBField->GetFormat() );
161 }
162 break;
163 case SwFieldIds::DbNextSet:
164 {
165 SwDBNextSetField* pDBField = const_cast<SwDBNextSetField*>(static_cast<const SwDBNextSetField*>(pField));
166 SwDBData aDBData(pDBField->GetDBData(&rDoc));
167 if( !pDBField->IsCondValid() ||
168 !pMgr->OpenDataSource( aDBData.sDataSource, aDBData.sCommand ))
169 break;
170
171 OUString sDBNumNm(lcl_GetDBVarName( rDoc, *pDBField));
172 SwCalcExp* pExp = rCalc.VarLook( sDBNumNm );
173 if( pExp )
174 rCalc.VarChange( sDBNumNm, pExp->nValue.GetLong() + 1 );
175 }
176 break;
177
178 default: break;
179 }
180 #endif
181 }
182 }
183 }
184
185 namespace sw
186 {
187
DocumentFieldsManager(SwDoc & i_rSwdoc)188 DocumentFieldsManager::DocumentFieldsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ),
189 mbNewFieldLst(true),
190 mpUpdateFields(new SwDocUpdateField(m_rDoc)),
191 mpFieldTypes( new SwFieldTypes ),
192 mnLockExpField( 0 )
193 {
194 }
195
GetFieldTypes() const196 const SwFieldTypes* DocumentFieldsManager::GetFieldTypes() const
197 {
198 return mpFieldTypes.get();
199 }
200
201 /** Insert field types
202 *
203 * @param rFieldTyp ???
204 * @return Always returns a pointer to the type, if it's new or already added.
205 */
InsertFieldType(const SwFieldType & rFieldTyp)206 SwFieldType* DocumentFieldsManager::InsertFieldType(const SwFieldType &rFieldTyp)
207 {
208 const SwFieldTypes::size_type nSize = mpFieldTypes->size();
209 const SwFieldIds nFieldWhich = rFieldTyp.Which();
210
211 SwFieldTypes::size_type i = INIT_FLDTYPES;
212
213 switch( nFieldWhich )
214 {
215 case SwFieldIds::SetExp:
216 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
217 // Or we get doubble number circles!!
218 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
219 //constructing string pools and when reading SetExp fields
220 if( nsSwGetSetExpType::GSE_SEQ & static_cast<const SwSetExpFieldType&>(rFieldTyp).GetType() )
221 i -= INIT_SEQ_FLDTYPES;
222 [[fallthrough]];
223 case SwFieldIds::Database:
224 case SwFieldIds::User:
225 case SwFieldIds::Dde:
226 {
227 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
228 OUString sFieldNm( rFieldTyp.GetName() );
229 for( ; i < nSize; ++i )
230 if( nFieldWhich == (*mpFieldTypes)[i]->Which() &&
231 rSCmp.isEqual( sFieldNm, (*mpFieldTypes)[i]->GetName() ))
232 return (*mpFieldTypes)[i].get();
233 }
234 break;
235
236 case SwFieldIds::TableOfAuthorities:
237 for( ; i < nSize; ++i )
238 if( nFieldWhich == (*mpFieldTypes)[i]->Which() )
239 return (*mpFieldTypes)[i].get();
240 break;
241
242 default:
243 for( i = 0; i < nSize; ++i )
244 if( nFieldWhich == (*mpFieldTypes)[i]->Which() )
245 return (*mpFieldTypes)[i].get();
246 }
247
248 std::unique_ptr<SwFieldType> pNew = rFieldTyp.Copy();
249 switch( nFieldWhich )
250 {
251 case SwFieldIds::Dde:
252 static_cast<SwDDEFieldType*>(pNew.get())->SetDoc( &m_rDoc );
253 break;
254
255 case SwFieldIds::Database:
256 case SwFieldIds::Table:
257 case SwFieldIds::DateTime:
258 case SwFieldIds::GetExp:
259 static_cast<SwValueFieldType*>(pNew.get())->SetDoc( &m_rDoc );
260 break;
261
262 case SwFieldIds::User:
263 case SwFieldIds::SetExp:
264 static_cast<SwValueFieldType*>(pNew.get())->SetDoc( &m_rDoc );
265 // JP 29.07.96: Optionally prepare FieldList for Calculator:
266 mpUpdateFields->InsertFieldType( *pNew );
267 break;
268 case SwFieldIds::TableOfAuthorities :
269 static_cast<SwAuthorityFieldType*>(pNew.get())->SetDoc( &m_rDoc );
270 break;
271 default: break;
272 }
273
274 mpFieldTypes->insert( mpFieldTypes->begin() + nSize, std::move(pNew) );
275 m_rDoc.getIDocumentState().SetModified();
276
277 return (*mpFieldTypes)[ nSize ].get();
278 }
279
280 /// @returns the field type of the Doc
GetSysFieldType(const SwFieldIds eWhich) const281 SwFieldType *DocumentFieldsManager::GetSysFieldType( const SwFieldIds eWhich ) const
282 {
283 for( SwFieldTypes::size_type i = 0; i < INIT_FLDTYPES; ++i )
284 if( eWhich == (*mpFieldTypes)[i]->Which() )
285 return (*mpFieldTypes)[i].get();
286 return nullptr;
287 }
288
289 /// Find first type with ResId and name
GetFieldType(SwFieldIds nResId,const OUString & rName,bool bDbFieldMatching) const290 SwFieldType* DocumentFieldsManager::GetFieldType(
291 SwFieldIds nResId,
292 const OUString& rName,
293 bool bDbFieldMatching // used in some UNO calls for SwFieldIds::Database to use different string matching code #i51815#
294 ) const
295 {
296 const SwFieldTypes::size_type nSize = mpFieldTypes->size();
297 SwFieldTypes::size_type i {0};
298 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
299
300 switch( nResId )
301 {
302 case SwFieldIds::SetExp:
303 //JP 29.01.96: SequenceFields start at INIT_FLDTYPES - 3!!
304 // Or we get doubble number circles!!
305 //MIB 14.03.95: From now on also the SW3-Reader relies on this, when
306 //constructing string pools and when reading SetExp fields
307 i = INIT_FLDTYPES - INIT_SEQ_FLDTYPES;
308 break;
309
310 case SwFieldIds::Database:
311 case SwFieldIds::User:
312 case SwFieldIds::Dde:
313 case SwFieldIds::TableOfAuthorities:
314 i = INIT_FLDTYPES;
315 break;
316 default: break;
317 }
318
319 SwFieldType* pRet = nullptr;
320 for( ; i < nSize; ++i )
321 {
322 SwFieldType* pFieldType = (*mpFieldTypes)[i].get();
323
324 if (nResId == pFieldType->Which())
325 {
326 OUString aFieldName( pFieldType->GetName() );
327 if (bDbFieldMatching && nResId == SwFieldIds::Database) // #i51815#
328 aFieldName = aFieldName.replace(DB_DELIM, '.');
329
330 if (rSCmp.isEqual( rName, aFieldName ))
331 {
332 pRet = pFieldType;
333 break;
334 }
335 }
336 }
337 return pRet;
338 }
339
340 /// Remove field type
RemoveFieldType(size_t nField)341 void DocumentFieldsManager::RemoveFieldType(size_t nField)
342 {
343 OSL_ENSURE( INIT_FLDTYPES <= nField, "don't remove InitFields" );
344 /*
345 * Dependent fields present -> ErrRaise
346 */
347 if(nField >= mpFieldTypes->size())
348 return;
349
350 SwFieldType* pTmp = (*mpFieldTypes)[nField].get();
351
352 // JP 29.07.96: Optionally prepare FieldList for Calculator
353 SwFieldIds nWhich = pTmp->Which();
354 switch( nWhich )
355 {
356 case SwFieldIds::SetExp:
357 case SwFieldIds::User:
358 mpUpdateFields->RemoveFieldType( *pTmp );
359 [[fallthrough]];
360 case SwFieldIds::Dde:
361 if( pTmp->HasWriterListeners() && !m_rDoc.IsUsed( *pTmp ) )
362 {
363 if( SwFieldIds::SetExp == nWhich )
364 static_cast<SwSetExpFieldType*>(pTmp)->SetDeleted( true );
365 else if( SwFieldIds::User == nWhich )
366 static_cast<SwUserFieldType*>(pTmp)->SetDeleted( true );
367 else
368 static_cast<SwDDEFieldType*>(pTmp)->SetDeleted( true );
369 nWhich = SwFieldIds::Database;
370 }
371 break;
372 default: break;
373 }
374
375 if( nWhich != SwFieldIds::Database )
376 {
377 OSL_ENSURE( !pTmp->HasWriterListeners(), "Dependent fields present!" );
378 }
379 else
380 (*mpFieldTypes)[nField].release(); // DB fields are ref-counted and delete themselves
381
382 mpFieldTypes->erase( mpFieldTypes->begin() + nField );
383 m_rDoc.getIDocumentState().SetModified();
384 }
385
386 // All have to be re-evaluated.
UpdateFields(bool bCloseDB)387 void DocumentFieldsManager::UpdateFields( bool bCloseDB )
388 {
389 // Call Modify() for every field type,
390 // dependent SwTextField get notified ...
391
392 for( auto const & pFieldType : *mpFieldTypes )
393 {
394 switch( pFieldType->Which() )
395 {
396 // Update table fields second to last
397 // Update references last
398 case SwFieldIds::GetRef:
399 case SwFieldIds::Table:
400 case SwFieldIds::Database:
401 case SwFieldIds::JumpEdit:
402 case SwFieldIds::RefPageSet: // are never expanded!
403 break;
404
405 case SwFieldIds::Dde:
406 {
407 SwMsgPoolItem aUpdateDDE( RES_UPDATEDDETBL );
408 pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aUpdateDDE));
409 break;
410 }
411 case SwFieldIds::GetExp:
412 case SwFieldIds::SetExp:
413 case SwFieldIds::HiddenText:
414 case SwFieldIds::HiddenPara:
415 // Expression fields are treated separately
416 break;
417 default:
418 pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
419 }
420 }
421
422 if( !IsExpFieldsLocked() )
423 UpdateExpFields( nullptr, false ); // update expression fields
424
425 // Tables
426 UpdateTableFields(nullptr);
427
428 // References
429 UpdateRefFields();
430 if( bCloseDB )
431 {
432 #if HAVE_FEATURE_DBCONNECTIVITY
433 m_rDoc.GetDBManager()->CloseAll();
434 #endif
435 }
436 // Only evaluate on full update
437 m_rDoc.getIDocumentState().SetModified();
438 }
439
InsDeletedFieldType(SwFieldType & rFieldTyp)440 void DocumentFieldsManager::InsDeletedFieldType( SwFieldType& rFieldTyp )
441 {
442 // The FieldType was marked as deleted and removed from the array.
443 // One has to look this up again, now.
444 // - If it's not present, it can be re-inserted.
445 // - If the same type is found, the deleted one has to be renamed.
446
447 const SwFieldTypes::size_type nSize = mpFieldTypes->size();
448 const SwFieldIds nFieldWhich = rFieldTyp.Which();
449
450 OSL_ENSURE( SwFieldIds::SetExp == nFieldWhich ||
451 SwFieldIds::User == nFieldWhich ||
452 SwFieldIds::Dde == nFieldWhich, "Wrong FieldType" );
453
454 const ::utl::TransliterationWrapper& rSCmp = GetAppCmpStrIgnore();
455 const OUString& rFieldNm = rFieldTyp.GetName();
456
457 for( SwFieldTypes::size_type i = INIT_FLDTYPES; i < nSize; ++i )
458 {
459 SwFieldType* pFnd = (*mpFieldTypes)[i].get();
460 if( nFieldWhich == pFnd->Which() &&
461 rSCmp.isEqual( rFieldNm, pFnd->GetName() ) )
462 {
463 // find new name
464 SwFieldTypes::size_type nNum = 1;
465 do {
466 OUString sSrch = rFieldNm + OUString::number( nNum );
467 for( i = INIT_FLDTYPES; i < nSize; ++i )
468 {
469 pFnd = (*mpFieldTypes)[i].get();
470 if( nFieldWhich == pFnd->Which() &&
471 rSCmp.isEqual( sSrch, pFnd->GetName() ) )
472 break;
473 }
474 if( i >= nSize ) // not found
475 {
476 const_cast<OUString&>(rFieldNm) = sSrch;
477 break; // exit while loop
478 }
479 ++nNum;
480 } while( true );
481 break;
482 }
483 }
484
485 // not found, so insert, and updated deleted flag
486 mpFieldTypes->insert( mpFieldTypes->begin() + nSize, std::unique_ptr<SwFieldType>(&rFieldTyp) );
487 switch( nFieldWhich )
488 {
489 case SwFieldIds::SetExp:
490 static_cast<SwSetExpFieldType&>(rFieldTyp).SetDeleted( false );
491 break;
492 case SwFieldIds::User:
493 static_cast<SwUserFieldType&>(rFieldTyp).SetDeleted( false );
494 break;
495 case SwFieldIds::Dde:
496 static_cast<SwDDEFieldType&>(rFieldTyp).SetDeleted( false );
497 break;
498 default: break;
499 }
500 }
501
PutValueToField(const SwPosition & rPos,const Any & rVal,sal_uInt16 nWhich)502 void DocumentFieldsManager::PutValueToField(const SwPosition & rPos,
503 const Any& rVal, sal_uInt16 nWhich)
504 {
505 Any aOldVal;
506 SwField * pField = GetFieldAtPos(rPos);
507
508 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo() &&
509 pField->QueryValue(aOldVal, nWhich))
510 {
511 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
512 std::make_unique<SwUndoFieldFromAPI>(rPos, aOldVal, rVal, nWhich));
513 }
514
515 pField->PutValue(rVal, nWhich);
516 }
517
UpdateField(SwTextField * pDstTextField,SwField & rSrcField,SwMsgPoolItem * pMsgHint,bool bUpdateFields)518 bool DocumentFieldsManager::UpdateField(SwTextField * pDstTextField, SwField & rSrcField,
519 SwMsgPoolItem * pMsgHint,
520 bool bUpdateFields)
521 {
522 OSL_ENSURE(pDstTextField, "no field to update!");
523
524 bool bTableSelBreak = false;
525
526 SwFormatField * pDstFormatField = const_cast<SwFormatField*>(&pDstTextField->GetFormatField());
527 SwField * pDstField = pDstFormatField->GetField();
528 SwFieldIds nFieldWhich = rSrcField.GetTyp()->Which();
529 SwNodeIndex aTableNdIdx(pDstTextField->GetTextNode());
530
531 if (pDstField->GetTyp()->Which() ==
532 rSrcField.GetTyp()->Which())
533 {
534 if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
535 {
536 SwPosition aPosition( pDstTextField->GetTextNode() );
537 aPosition.nContent = pDstTextField->GetStart();
538
539 m_rDoc.GetIDocumentUndoRedo().AppendUndo(
540 std::make_unique<SwUndoFieldFromDoc>( aPosition, *pDstField, rSrcField, pMsgHint, bUpdateFields) );
541 }
542
543 pDstFormatField->SetField(rSrcField.CopyField());
544 SwField* pNewField = pDstFormatField->GetField();
545
546 switch( nFieldWhich )
547 {
548 case SwFieldIds::SetExp:
549 case SwFieldIds::GetExp:
550 case SwFieldIds::HiddenText:
551 case SwFieldIds::HiddenPara:
552 UpdateExpFields( pDstTextField, true );
553 break;
554
555 case SwFieldIds::Table:
556 {
557 const SwTableNode* pTableNd =
558 m_rDoc.IsIdxInTable(aTableNdIdx);
559 if( pTableNd )
560 {
561 SwTableFormulaUpdate aTableUpdate( &pTableNd->
562 GetTable() );
563 if (bUpdateFields)
564 UpdateTableFields( &aTableUpdate );
565 else
566 pNewField->GetTyp()->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aTableUpdate));
567
568 if (! bUpdateFields)
569 bTableSelBreak = true;
570 }
571 }
572 break;
573
574 case SwFieldIds::Macro:
575 if( bUpdateFields && pDstTextField->GetpTextNode() )
576 pDstTextField->GetpTextNode()->TriggerNodeUpdate(sw::LegacyModifyHint(nullptr, pDstFormatField));
577 break;
578
579 case SwFieldIds::DatabaseName:
580 case SwFieldIds::DbNextSet:
581 case SwFieldIds::DbNumSet:
582 case SwFieldIds::DbSetNumber:
583 m_rDoc.ChgDBData(static_cast<SwDBNameInfField*>( pNewField)->GetRealDBData());
584 pNewField->GetTyp()->UpdateFields();
585
586 break;
587
588 case SwFieldIds::Database:
589 #if HAVE_FEATURE_DBCONNECTIVITY
590 {
591 // JP 10.02.96: call ChgValue, so that the style change sets the
592 // ContentString correctly
593 SwDBField* pDBField = static_cast<SwDBField*>(pNewField);
594 if (pDBField->IsInitialized())
595 pDBField->ChgValue( pDBField->GetValue(), true );
596
597 pDBField->ClearInitialized();
598 pDBField->InitContent();
599 }
600 #endif
601 [[fallthrough]];
602
603 default:
604 pDstFormatField->UpdateTextNode(nullptr, pMsgHint);
605 }
606
607 // The fields we can calculate here are being triggered for an update
608 // here explicitly.
609 if( nFieldWhich == SwFieldIds::User )
610 UpdateUsrFields();
611 }
612
613 return bTableSelBreak;
614 }
615
616 /// Update reference and table fields
UpdateRefFields()617 void DocumentFieldsManager::UpdateRefFields()
618 {
619 for(auto const& pFieldType: *mpFieldTypes)
620 if(SwFieldIds::GetRef == pFieldType->Which())
621 static_cast<SwGetRefFieldType*>(pFieldType.get())->UpdateGetReferences();
622 }
623
UpdateTableFields(SfxPoolItem * pHt)624 void DocumentFieldsManager::UpdateTableFields( SfxPoolItem* pHt )
625 {
626 OSL_ENSURE( !pHt || RES_TABLEFML_UPDATE == pHt->Which(),
627 "What MessageItem is this?" );
628
629 auto pFieldType = GetFieldType( SwFieldIds::Table, OUString(), false );
630 if(pFieldType)
631 {
632 std::vector<SwFormatField*> vFields;
633 pFieldType->GatherFields(vFields);
634 SwTableFormulaUpdate* pUpdateField = nullptr;
635 if( pHt && RES_TABLEFML_UPDATE == pHt->Which() )
636 pUpdateField = static_cast<SwTableFormulaUpdate*>(pHt);
637 for(auto pFormatField : vFields)
638 {
639 SwTableField* pField = static_cast<SwTableField*>(pFormatField->GetField());
640 if( pUpdateField )
641 {
642 // table where this field is located
643 const SwTableNode* pTableNd;
644 const SwTextNode& rTextNd = pFormatField->GetTextField()->GetTextNode();
645 pTableNd = rTextNd.FindTableNode();
646 if (pTableNd == nullptr)
647 continue;
648
649 switch( pUpdateField->m_eFlags )
650 {
651 case TBL_CALC:
652 // re-set the value flag
653 // JP 17.06.96: internal representation of all formulas
654 // (reference to other table!!!)
655 if( nsSwExtendedSubType::SUB_CMD & pField->GetSubType() )
656 pField->PtrToBoxNm( pUpdateField->m_pTable );
657 else
658 pField->ChgValid( false );
659 break;
660 case TBL_BOXNAME:
661 // is this the wanted table?
662 if( &pTableNd->GetTable() == pUpdateField->m_pTable )
663 // to the external representation
664 pField->PtrToBoxNm( pUpdateField->m_pTable );
665 break;
666 case TBL_BOXPTR:
667 // to the internal representation
668 // JP 17.06.96: internal representation on all formulas
669 // (reference to other table!!!)
670 pField->BoxNmToPtr( &pTableNd->GetTable() );
671 break;
672 case TBL_RELBOXNAME:
673 // is this the wanted table?
674 if( &pTableNd->GetTable() == pUpdateField->m_pTable )
675 // to the relative representation
676 pField->ToRelBoxNm( pUpdateField->m_pTable );
677 break;
678 default:
679 break;
680 }
681 }
682 else
683 // reset the value flag for all
684 pField->ChgValid( false );
685 }
686 }
687 // process all table box formulas
688 for (const SfxPoolItem* pItem : m_rDoc.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
689 {
690 auto pBoxFormula = dynamic_cast<const SwTableBoxFormula*>(pItem);
691 if( pBoxFormula && pBoxFormula->GetDefinedIn() )
692 {
693 const_cast<SwTableBoxFormula*>(pBoxFormula)->ChangeState( pHt );
694 }
695 }
696
697 SwRootFrame const* pLayout(nullptr);
698 for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
699 {
700 assert(!pLayout || pLay->IsHideRedlines() == pLayout->IsHideRedlines()); // TODO
701 pLayout = pLay;
702 }
703
704 // all fields/boxes are now invalid, so we can start to calculate
705 if( pHt && ( RES_TABLEFML_UPDATE != pHt->Which() ||
706 TBL_CALC != static_cast<SwTableFormulaUpdate*>(pHt)->m_eFlags ))
707 return ;
708
709 std::unique_ptr<SwCalc, o3tl::default_delete<SwCalc>> pCalc;
710
711 if( pFieldType )
712 {
713 std::vector<SwFormatField*> vFields;
714 pFieldType->GatherFields(vFields);
715 for(SwFormatField* pFormatField: vFields)
716 {
717 // start calculation at the end
718 // new fields are inserted at the beginning of the modify chain
719 // that gives faster calculation on import
720 // mba: do we really need this "optimization"? Is it still valid?
721 SwTableField *const pField(static_cast<SwTableField*>(pFormatField->GetField()));
722 if (nsSwExtendedSubType::SUB_CMD & pField->GetSubType())
723 continue;
724
725 // needs to be recalculated
726 if( !pField->IsValid() )
727 {
728 // table where this field is located
729 const SwTextNode& rTextNd = pFormatField->GetTextField()->GetTextNode();
730 const SwTableNode* pTableNd = rTextNd.FindTableNode();
731 if( !pTableNd )
732 continue;
733
734 // if this field is not in the to-be-updated table, skip it
735 if( pHt && &pTableNd->GetTable() !=
736 static_cast<SwTableFormulaUpdate*>(pHt)->m_pTable )
737 continue;
738
739 if( !pCalc )
740 pCalc.reset(new SwCalc( m_rDoc ));
741
742 // get the values of all SetExpression fields that are valid
743 // until the table
744 SwFrame* pFrame = nullptr;
745 if( pTableNd->GetIndex() < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
746 {
747 // is in the special section, that's expensive!
748 Point aPt; // return the first frame of the layout - Tab.Headline!!
749 std::pair<Point, bool> const tmp(aPt, true);
750 pFrame = rTextNd.getLayoutFrame(pLayout, nullptr, &tmp);
751 if( pFrame )
752 {
753 SwPosition aPos( *pTableNd );
754 if( GetBodyTextNode( m_rDoc, aPos, *pFrame ) )
755 FieldsToCalc( *pCalc, SetGetExpField(
756 aPos.nNode, pFormatField->GetTextField(),
757 &aPos.nContent), pLayout);
758 else
759 pFrame = nullptr;
760 }
761 }
762 if( !pFrame )
763 {
764 // create index to determine the TextNode
765 SwNodeIndex aIdx( rTextNd );
766 FieldsToCalc( *pCalc,
767 SetGetExpField(aIdx, pFormatField->GetTextField()),
768 pLayout);
769 }
770
771 SwTableCalcPara aPara(*pCalc, pTableNd->GetTable(), pLayout);
772 pField->CalcField( aPara );
773 if( aPara.IsStackOverflow() )
774 {
775 bool const bResult = aPara.CalcWithStackOverflow();
776 if (bResult)
777 {
778 pField->CalcField( aPara );
779 }
780 OSL_ENSURE(bResult,
781 "the chained formula could no be calculated");
782 }
783 pCalc->SetCalcError( SwCalcError::NONE );
784 }
785 pFormatField->UpdateTextNode(nullptr, pHt);
786 }
787 }
788
789 // calculate the formula at the boxes
790 for (const SfxPoolItem* pItem : m_rDoc.GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
791 {
792 auto pFormula = const_cast<SwTableBoxFormula*>(dynamic_cast<const SwTableBoxFormula*>(pItem));
793 if( pFormula && pFormula->GetDefinedIn() && !pFormula->IsValid() )
794 {
795 SwTableBox* pBox = pFormula->GetTableBox();
796 if( pBox && pBox->GetSttNd() &&
797 pBox->GetSttNd()->GetNodes().IsDocNodes() )
798 {
799 const SwTableNode* pTableNd = pBox->GetSttNd()->FindTableNode();
800 if( !pHt || &pTableNd->GetTable() ==
801 static_cast<SwTableFormulaUpdate*>(pHt)->m_pTable )
802 {
803 double nValue;
804 if( !pCalc )
805 pCalc.reset(new SwCalc( m_rDoc ));
806
807 // get the values of all SetExpression fields that are valid
808 // until the table
809 SwFrame* pFrame = nullptr;
810 if( pTableNd->GetIndex() < m_rDoc.GetNodes().GetEndOfExtras().GetIndex() )
811 {
812 // is in the special section, that's expensive!
813 SwNodeIndex aCNdIdx( *pTableNd, +2 );
814 SwContentNode* pCNd = aCNdIdx.GetNode().GetContentNode();
815 if( !pCNd )
816 pCNd = m_rDoc.GetNodes().GoNext( &aCNdIdx );
817
818 if (pCNd)
819 {
820 Point aPt; // return the first frame of the layout - Tab.Headline!!
821 std::pair<Point, bool> const tmp(aPt, true);
822 pFrame = pCNd->getLayoutFrame(pLayout, nullptr, &tmp);
823 if( pFrame )
824 {
825 SwPosition aPos( *pCNd );
826 if( GetBodyTextNode( m_rDoc, aPos, *pFrame ) )
827 FieldsToCalc(*pCalc, SetGetExpField(aPos.nNode),
828 pLayout);
829 else
830 pFrame = nullptr;
831 }
832 }
833 }
834 if( !pFrame )
835 {
836 // create index to determine the TextNode
837 SwNodeIndex aIdx( *pTableNd );
838 FieldsToCalc(*pCalc, SetGetExpField(aIdx), pLayout);
839 }
840
841 SwTableCalcPara aPara(*pCalc, pTableNd->GetTable(), pLayout);
842 pFormula->Calc( aPara, nValue );
843
844 if( aPara.IsStackOverflow() )
845 {
846 bool const bResult = aPara.CalcWithStackOverflow();
847 if (bResult)
848 {
849 pFormula->Calc( aPara, nValue );
850 }
851 OSL_ENSURE(bResult,
852 "the chained formula could no be calculated");
853 }
854
855 SwFrameFormat* pFormat = pBox->ClaimFrameFormat();
856 SfxItemSet aTmp( m_rDoc.GetAttrPool(),
857 svl::Items<RES_BOXATR_BEGIN,RES_BOXATR_END-1>{} );
858
859 if( pCalc->IsCalcError() )
860 nValue = DBL_MAX;
861 aTmp.Put( SwTableBoxValue( nValue ));
862 if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT ))
863 aTmp.Put( SwTableBoxNumFormat( 0 ));
864 pFormat->SetFormatAttr( aTmp );
865
866 pCalc->SetCalcError( SwCalcError::NONE );
867 }
868 }
869 }
870 }
871 }
872
UpdateExpFields(SwTextField * pUpdateField,bool bUpdRefFields)873 void DocumentFieldsManager::UpdateExpFields( SwTextField* pUpdateField, bool bUpdRefFields )
874 {
875 if( IsExpFieldsLocked() || m_rDoc.IsInReading() )
876 return;
877
878 bool bOldInUpdateFields = mpUpdateFields->IsInUpdateFields();
879 mpUpdateFields->SetInUpdateFields( true );
880
881 mpUpdateFields->MakeFieldList( m_rDoc, true, GETFLD_ALL );
882 mbNewFieldLst = false;
883
884 if (mpUpdateFields->GetSortList()->empty())
885 {
886 if( bUpdRefFields )
887 UpdateRefFields();
888
889 mpUpdateFields->SetInUpdateFields( bOldInUpdateFields );
890 mpUpdateFields->SetFieldsDirty( false );
891 return ;
892 }
893
894 SwRootFrame const* pLayout(nullptr);
895 SwRootFrame const* pLayoutRLHidden(nullptr);
896 for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
897 {
898 if (pLay->IsHideRedlines())
899 {
900 pLayoutRLHidden = pLay;
901 }
902 else
903 {
904 pLayout = pLay;
905 }
906 }
907 if (pLayout || !pLayoutRLHidden) // always calc *something*...
908 {
909 UpdateExpFieldsImpl(pUpdateField, pLayout);
910 }
911 if (pLayoutRLHidden)
912 {
913 UpdateExpFieldsImpl(pUpdateField, pLayoutRLHidden);
914 }
915
916 // update reference fields
917 if( bUpdRefFields )
918 UpdateRefFields();
919
920 mpUpdateFields->SetInUpdateFields( bOldInUpdateFields );
921 mpUpdateFields->SetFieldsDirty( false );
922 }
923
UpdateExpFieldsImpl(SwTextField * pUpdateField,SwRootFrame const * const pLayout)924 void DocumentFieldsManager::UpdateExpFieldsImpl(
925 SwTextField * pUpdateField, SwRootFrame const*const pLayout)
926 {
927 SwFieldIds nWhich;
928
929 // Hash table for all string replacements is filled on-the-fly.
930 // Try to fabricate an uneven number.
931 const SwFieldTypes::size_type nHashSize {(( mpFieldTypes->size() / 7 ) + 1 ) * 7};
932 const sal_uInt16 nStrFormatCnt = o3tl::narrowing<sal_uInt16>(nHashSize);
933 OSL_ENSURE( nStrFormatCnt == nHashSize, "Downcasting to sal_uInt16 lost information!" );
934 SwHashTable<HashStr> aHashStrTable(nStrFormatCnt);
935
936 {
937 const SwFieldType* pFieldType;
938 // process separately:
939 for( auto n = mpFieldTypes->size(); n; )
940 {
941 pFieldType = (*mpFieldTypes)[ --n ].get();
942 switch( pFieldType->Which() )
943 {
944 case SwFieldIds::User:
945 {
946 // Entry present?
947 sal_uInt16 nPos;
948 const OUString& rNm = pFieldType->GetName();
949 OUString sExpand(const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFieldType))->Expand(nsSwGetSetExpType::GSE_STRING, 0, LANGUAGE_SYSTEM));
950 SwHash* pFnd = aHashStrTable.Find( rNm, &nPos );
951 if( pFnd )
952 // modify entry in the hash table
953 static_cast<HashStr*>(pFnd)->aSetStr = sExpand;
954 else
955 // insert the new entry
956 aHashStrTable[nPos].reset( new HashStr( rNm, sExpand,
957 aHashStrTable[nPos].release() ) );
958 }
959 break;
960 default: break;
961 }
962 }
963 }
964
965 // The array is filled with all fields; start calculation.
966 SwCalc aCalc( m_rDoc );
967
968 #if HAVE_FEATURE_DBCONNECTIVITY
969 OUString sDBNumNm( SwFieldType::GetTypeStr( SwFieldTypesEnum::DatabaseSetNumber ) );
970
971 // already set the current record number
972 SwDBManager* pMgr = m_rDoc.GetDBManager();
973 pMgr->CloseAll( false );
974
975 SvtSysLocale aSysLocale;
976 const LocaleDataWrapper* pLclData = &aSysLocale.GetLocaleData();
977 const LanguageType nLang = pLclData->getLanguageTag().getLanguageType();
978 bool bCanFill = pMgr->FillCalcWithMergeData( m_rDoc.GetNumberFormatter(), nLang, aCalc );
979 #endif
980
981 // Make sure we don't hide all content, which would lead to a crash. First, count how many visible sections we have.
982 int nShownSections = 0;
983 sal_uLong nContentStart = m_rDoc.GetNodes().GetEndOfContent().StartOfSectionIndex() + 1;
984 sal_uLong nContentEnd = m_rDoc.GetNodes().GetEndOfContent().GetIndex();
985 SwSectionFormats& rSectFormats = m_rDoc.GetSections();
986 for( SwSectionFormats::size_type n = 0; n<rSectFormats.size(); ++n )
987 {
988 SwSectionFormat& rSectFormat = *rSectFormats[ n ];
989 SwSectionNode* pSectionNode = rSectFormat.GetSectionNode();
990 SwSection* pSect = rSectFormat.GetSection();
991
992 // Usually some of the content is not in a section: count that as a virtual section, so that all real sections can be hidden.
993 // Only look for section gaps at the lowest level, ignoring sub-sections.
994 if ( pSectionNode && !rSectFormat.GetParent() )
995 {
996 SwNodeIndex aNextIdx( *pSectionNode->EndOfSectionNode(), 1 );
997 if ( n == 0 && pSectionNode->GetIndex() != nContentStart )
998 nShownSections++; //document does not start with a section
999 if ( n == rSectFormats.size() - 1 )
1000 {
1001 if ( aNextIdx.GetIndex() != nContentEnd )
1002 nShownSections++; //document does not end in a section
1003 }
1004 else if ( !aNextIdx.GetNode().IsSectionNode() )
1005 nShownSections++; //section is not immediately followed by another section
1006 }
1007
1008 // count only visible sections
1009 if ( pSect && !pSect->CalcHiddenFlag())
1010 nShownSections++;
1011 }
1012
1013 IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
1014 std::unordered_map<SwSetExpFieldType const*, SwTextNode const*> SetExpOutlineNodeMap;
1015
1016 for (std::unique_ptr<SetGetExpField> const& it : *mpUpdateFields->GetSortList())
1017 {
1018 SwSection* pSect = const_cast<SwSection*>(it->GetSection());
1019 if( pSect )
1020 {
1021 SwSbxValue aValue = aCalc.Calculate(
1022 pSect->GetCondition() );
1023 if(!aValue.IsVoidValue())
1024 {
1025 // Do we want to hide this one?
1026 bool bHide = aValue.GetBool();
1027 if (bHide && !pSect->IsCondHidden())
1028 {
1029 // This section will be hidden, but it wasn't before
1030 if (nShownSections == 1)
1031 {
1032 // This would be the last section, so set its condition to false, and avoid hiding it.
1033 pSect->SetCondition("0");
1034 bHide = false;
1035 }
1036 nShownSections--;
1037 }
1038 pSect->SetCondHidden( bHide );
1039 }
1040 continue;
1041 }
1042
1043 SwTextField* pTextField = const_cast<SwTextField*>(it->GetTextField());
1044 if( !pTextField )
1045 {
1046 OSL_ENSURE( false, "what's wrong now'" );
1047 continue;
1048 }
1049
1050 if (pLayout && pLayout->IsHideRedlines()
1051 && IsFieldDeleted(rIDRA, *pLayout, *pTextField))
1052 {
1053 continue;
1054 }
1055
1056 SwFormatField* pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
1057 const SwField* pField = pFormatField->GetField();
1058
1059 nWhich = pField->GetTyp()->Which();
1060 switch( nWhich )
1061 {
1062 case SwFieldIds::HiddenText:
1063 {
1064 SwHiddenTextField* pHField = const_cast<SwHiddenTextField*>(static_cast<const SwHiddenTextField*>(pField));
1065 SwSbxValue aValue = aCalc.Calculate( pHField->GetPar1() );
1066 bool bValue = !aValue.GetBool();
1067 if(!aValue.IsVoidValue())
1068 {
1069 pHField->SetValue( bValue );
1070 // evaluate field
1071 pHField->Evaluate(m_rDoc);
1072 }
1073 }
1074 break;
1075 case SwFieldIds::HiddenPara:
1076 {
1077 SwHiddenParaField* pHPField = const_cast<SwHiddenParaField*>(static_cast<const SwHiddenParaField*>(pField));
1078 SwSbxValue aValue = aCalc.Calculate( pHPField->GetPar1() );
1079 bool bValue = aValue.GetBool();
1080 if(!aValue.IsVoidValue())
1081 pHPField->SetHidden( bValue );
1082 }
1083 break;
1084 case SwFieldIds::DbSetNumber:
1085 #if HAVE_FEATURE_DBCONNECTIVITY
1086 {
1087 const_cast<SwDBSetNumberField*>(static_cast<const SwDBSetNumberField*>(pField))->Evaluate(m_rDoc);
1088 aCalc.VarChange( sDBNumNm, static_cast<const SwDBSetNumberField*>(pField)->GetSetNumber());
1089 pField->ExpandField(m_rDoc.IsClipBoard(), nullptr);
1090 }
1091 #endif
1092 break;
1093 case SwFieldIds::DbNextSet:
1094 case SwFieldIds::DbNumSet:
1095 #if HAVE_FEATURE_DBCONNECTIVITY
1096 {
1097 UpdateDBNumFields( *const_cast<SwDBNameInfField*>(static_cast<const SwDBNameInfField*>(pField)), aCalc );
1098 if( bCanFill )
1099 bCanFill = pMgr->FillCalcWithMergeData( m_rDoc.GetNumberFormatter(), nLang, aCalc );
1100 }
1101 #endif
1102 break;
1103 case SwFieldIds::Database:
1104 {
1105 #if HAVE_FEATURE_DBCONNECTIVITY
1106 // evaluate field
1107 const_cast<SwDBField*>(static_cast<const SwDBField*>(pField))->Evaluate();
1108
1109 SwDBData aTmpDBData(static_cast<const SwDBField*>(pField)->GetDBData());
1110
1111 if( pMgr->IsDataSourceOpen(aTmpDBData.sDataSource, aTmpDBData.sCommand, false))
1112 aCalc.VarChange( sDBNumNm, pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType));
1113
1114 const OUString& rName = pField->GetTyp()->GetName();
1115
1116 // Add entry to hash table
1117 // Entry present?
1118 sal_uInt16 nPos;
1119 HashStr* pFnd = aHashStrTable.Find( rName, &nPos );
1120 OUString const value(pField->ExpandField(m_rDoc.IsClipBoard(), nullptr));
1121 if( pFnd )
1122 {
1123 // Modify entry in the hash table
1124 pFnd->aSetStr = value;
1125 }
1126 else
1127 {
1128 // insert new entry
1129 aHashStrTable[nPos].reset( new HashStr( rName,
1130 value, aHashStrTable[nPos].release()) );
1131 }
1132 #endif
1133 }
1134 break;
1135 case SwFieldIds::GetExp:
1136 case SwFieldIds::SetExp:
1137 {
1138 if( nsSwGetSetExpType::GSE_STRING & pField->GetSubType() ) // replace String
1139 {
1140 if( SwFieldIds::GetExp == nWhich )
1141 {
1142 SwGetExpField* pGField = const_cast<SwGetExpField*>(static_cast<const SwGetExpField*>(pField));
1143
1144 if( (!pUpdateField || pUpdateField == pTextField )
1145 && pGField->IsInBodyText() )
1146 {
1147 OUString aNew = LookString( aHashStrTable, pGField->GetFormula() );
1148 pGField->ChgExpStr( aNew, pLayout );
1149 }
1150 }
1151 else
1152 {
1153 SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1154 // is the "formula" a field?
1155 OUString aNew = LookString( aHashStrTable, pSField->GetFormula() );
1156
1157 if( aNew.isEmpty() ) // nothing found then the formula is the new value
1158 aNew = pSField->GetFormula();
1159
1160 // only update one field
1161 if( !pUpdateField || pUpdateField == pTextField )
1162 pSField->ChgExpStr( aNew, pLayout );
1163
1164 // lookup the field's name
1165 aNew = static_cast<SwSetExpFieldType*>(pSField->GetTyp())->GetSetRefName();
1166 // Entry present?
1167 sal_uInt16 nPos;
1168 HashStr* pFnd = aHashStrTable.Find( aNew, &nPos );
1169 if( pFnd )
1170 // Modify entry in the hash table
1171 pFnd->aSetStr = pSField->GetExpStr(pLayout);
1172 else
1173 {
1174 // insert new entry
1175 aHashStrTable[nPos].reset( new HashStr( aNew,
1176 pSField->GetExpStr(pLayout),
1177 aHashStrTable[nPos].release() ) );
1178 pFnd = aHashStrTable[nPos].get();
1179 }
1180
1181 // Extension for calculation with Strings
1182 SwSbxValue aValue;
1183 aValue.PutString( pFnd->aSetStr );
1184 aCalc.VarChange( aNew, aValue );
1185 }
1186 }
1187 else // recalculate formula
1188 {
1189 if( SwFieldIds::GetExp == nWhich )
1190 {
1191 SwGetExpField* pGField = const_cast<SwGetExpField*>(static_cast<const SwGetExpField*>(pField));
1192
1193 if( (!pUpdateField || pUpdateField == pTextField )
1194 && pGField->IsInBodyText() )
1195 {
1196 SwSbxValue aValue = aCalc.Calculate(
1197 pGField->GetFormula());
1198 if(!aValue.IsVoidValue())
1199 pGField->SetValue(aValue.GetDouble(), pLayout);
1200 }
1201 }
1202 else
1203 {
1204 SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1205 SwSetExpFieldType* pSFieldTyp = static_cast<SwSetExpFieldType*>(pField->GetTyp());
1206 OUString aNew = pSFieldTyp->GetName();
1207
1208 SwNode* pSeqNd = nullptr;
1209
1210 if( pSField->IsSequenceField() )
1211 {
1212 const sal_uInt8 nLvl = pSFieldTyp->GetOutlineLvl();
1213 if( MAXLEVEL > nLvl )
1214 {
1215 // test if the Number needs to be updated
1216 pSeqNd = m_rDoc.GetNodes()[ it->GetNode() ];
1217
1218 const SwTextNode* pOutlNd = pSeqNd->
1219 FindOutlineNodeOfLevel(nLvl, pLayout);
1220 auto const iter(SetExpOutlineNodeMap.find(pSFieldTyp));
1221 if (iter == SetExpOutlineNodeMap.end()
1222 || iter->second != pOutlNd)
1223 {
1224 SetExpOutlineNodeMap[pSFieldTyp] = pOutlNd;
1225 aCalc.VarChange( aNew, 0 );
1226 }
1227 }
1228 }
1229
1230 aNew += "=" + pSField->GetFormula();
1231
1232 SwSbxValue aValue = aCalc.Calculate( aNew );
1233 if (!aCalc.IsCalcError())
1234 {
1235 double nErg = aValue.GetDouble();
1236 // only update one field
1237 if( !aValue.IsVoidValue() && (!pUpdateField || pUpdateField == pTextField) )
1238 {
1239 pSField->SetValue(nErg, pLayout);
1240
1241 if( pSeqNd )
1242 pSFieldTyp->SetChapter(*pSField, *pSeqNd, pLayout);
1243 }
1244 }
1245 }
1246 }
1247 }
1248 break;
1249 default: break;
1250 } // switch
1251
1252 {
1253 // avoid calling ReplaceText() for input fields, it is pointless
1254 // here and moves the cursor if it's inside the field ...
1255 SwTextInputField *const pInputField(
1256 pUpdateField == pTextField // ... except once, when the dialog
1257 ? nullptr // is used to change content via UpdateOneField()
1258 : dynamic_cast<SwTextInputField *>(pTextField));
1259 if (pInputField)
1260 {
1261 bool const tmp = pInputField->LockNotifyContentChange();
1262 (void) tmp;
1263 assert(tmp && "should not be locked here?");
1264 }
1265 ::comphelper::ScopeGuard g([pInputField]()
1266 {
1267 if (pInputField)
1268 {
1269 pInputField->UnlockNotifyContentChange();
1270 }
1271 });
1272 pFormatField->UpdateTextNode(nullptr, nullptr); // trigger formatting
1273 }
1274
1275 if (pUpdateField == pTextField) // if only this one is updated
1276 {
1277 if( SwFieldIds::GetExp == nWhich || // only GetField or
1278 SwFieldIds::HiddenText == nWhich || // HiddenText?
1279 SwFieldIds::HiddenPara == nWhich) // HiddenParaField?
1280 break; // quit
1281 pUpdateField = nullptr; // update all from here on
1282 }
1283 }
1284
1285 #if HAVE_FEATURE_DBCONNECTIVITY
1286 pMgr->CloseAll(false);
1287 #endif
1288 }
1289
1290 /// Insert field type that was marked as deleted
UpdateUsrFields()1291 void DocumentFieldsManager::UpdateUsrFields()
1292 {
1293 SwCalc* pCalc = nullptr;
1294 for( SwFieldTypes::size_type i = INIT_FLDTYPES; i < mpFieldTypes->size(); ++i )
1295 {
1296 const SwFieldType* pFieldType = (*mpFieldTypes)[i].get();
1297 if( SwFieldIds::User == pFieldType->Which() )
1298 {
1299 if( !pCalc )
1300 pCalc = new SwCalc( m_rDoc );
1301 const_cast<SwUserFieldType*>(static_cast<const SwUserFieldType*>(pFieldType))->GetValue( *pCalc );
1302 }
1303 }
1304
1305 if( pCalc )
1306 {
1307 delete pCalc;
1308 m_rDoc.getIDocumentState().SetModified();
1309 }
1310 }
1311
GetRecordsPerDocument() const1312 sal_Int32 DocumentFieldsManager::GetRecordsPerDocument() const
1313 {
1314 sal_Int32 nRecords = 1;
1315
1316 mpUpdateFields->MakeFieldList( m_rDoc, true, GETFLD_ALL );
1317 if (mpUpdateFields->GetSortList()->empty())
1318 return nRecords;
1319
1320 for (std::unique_ptr<SetGetExpField> const& it : *mpUpdateFields->GetSortList())
1321 {
1322 const SwTextField *pTextField = it->GetTextField();
1323 if( !pTextField )
1324 continue;
1325
1326 const SwFormatField &pFormatField = pTextField->GetFormatField();
1327 const SwField* pField = pFormatField.GetField();
1328
1329 switch( pField->GetTyp()->Which() )
1330 {
1331 case SwFieldIds::DbNextSet:
1332 case SwFieldIds::DbNumSet:
1333 nRecords++;
1334 break;
1335 default:
1336 break;
1337 }
1338 }
1339
1340 return nRecords;
1341 }
1342
UpdatePageFields(SfxPoolItem * pMsgHint)1343 void DocumentFieldsManager::UpdatePageFields( SfxPoolItem* pMsgHint )
1344 {
1345 for( SwFieldTypes::size_type i = 0; i < INIT_FLDTYPES; ++i )
1346 {
1347 SwFieldType* pFieldType = (*mpFieldTypes)[ i ].get();
1348 switch( pFieldType->Which() )
1349 {
1350 case SwFieldIds::PageNumber:
1351 case SwFieldIds::Chapter:
1352 case SwFieldIds::GetExp:
1353 case SwFieldIds::RefPageGet:
1354 pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, pMsgHint));
1355 break;
1356 case SwFieldIds::DocStat:
1357 pFieldType->CallSwClientNotify(sw::LegacyModifyHint(nullptr, nullptr));
1358 break;
1359 default: break;
1360 }
1361 }
1362 SetNewFieldLst(true);
1363 }
1364
LockExpFields()1365 void DocumentFieldsManager::LockExpFields()
1366 {
1367 ++mnLockExpField;
1368 }
1369
UnlockExpFields()1370 void DocumentFieldsManager::UnlockExpFields()
1371 {
1372 assert(mnLockExpField != 0);
1373 if( mnLockExpField )
1374 --mnLockExpField;
1375 }
1376
IsExpFieldsLocked() const1377 bool DocumentFieldsManager::IsExpFieldsLocked() const
1378 {
1379 return 0 != mnLockExpField;
1380 }
1381
GetUpdateFields() const1382 SwDocUpdateField& DocumentFieldsManager::GetUpdateFields() const
1383 {
1384 return *mpUpdateFields;
1385 }
1386
SetFieldsDirty(bool b,const SwNode * pChk,sal_uLong nLen)1387 bool DocumentFieldsManager::SetFieldsDirty( bool b, const SwNode* pChk, sal_uLong nLen )
1388 {
1389 // See if the supplied nodes actually contain fields.
1390 // If they don't, the flag doesn't need to be changed.
1391 bool bFieldsFnd = false;
1392 if( b && pChk && !GetUpdateFields().IsFieldsDirty() && !m_rDoc.IsInDtor()
1393 // ?? what's up with Undo, this is also wanted there!
1394 /*&& &pChk->GetNodes() == &GetNodes()*/ )
1395 {
1396 b = false;
1397 if( !nLen )
1398 ++nLen;
1399 sal_uLong nStt = pChk->GetIndex();
1400 const SwNodes& rNds = pChk->GetNodes();
1401 while( nLen-- )
1402 {
1403 const SwTextNode* pTNd = rNds[ nStt++ ]->GetTextNode();
1404 if( pTNd )
1405 {
1406 if( pTNd->GetAttrOutlineLevel() != 0 )
1407 // update chapter fields
1408 b = true;
1409 else if( pTNd->GetpSwpHints() && pTNd->GetSwpHints().Count() )
1410 {
1411 const size_t nEnd = pTNd->GetSwpHints().Count();
1412 for( size_t n = 0 ; n < nEnd; ++n )
1413 {
1414 const SwTextAttr* pAttr = pTNd->GetSwpHints().Get(n);
1415 if ( pAttr->Which() == RES_TXTATR_FIELD
1416 || pAttr->Which() == RES_TXTATR_INPUTFIELD)
1417 {
1418 b = true;
1419 break;
1420 }
1421 }
1422 }
1423
1424 if( b )
1425 break;
1426 }
1427 }
1428 bFieldsFnd = b;
1429 }
1430 GetUpdateFields().SetFieldsDirty( b );
1431 return bFieldsFnd;
1432 }
1433
SetFixFields(const DateTime * pNewDateTime)1434 void DocumentFieldsManager::SetFixFields( const DateTime* pNewDateTime )
1435 {
1436 bool bIsModified = m_rDoc.getIDocumentState().IsModified();
1437
1438 sal_Int32 nDate;
1439 sal_Int64 nTime;
1440 if( pNewDateTime )
1441 {
1442 nDate = pNewDateTime->GetDate();
1443 nTime = pNewDateTime->GetTime();
1444 }
1445 else
1446 {
1447 DateTime aDateTime( DateTime::SYSTEM );
1448 nDate = aDateTime.GetDate();
1449 nTime = aDateTime.GetTime();
1450 }
1451
1452 SwFieldIds const aTypes[] {
1453 /*0*/ SwFieldIds::DocInfo,
1454 /*1*/ SwFieldIds::Author,
1455 /*2*/ SwFieldIds::ExtUser,
1456 /*3*/ SwFieldIds::Filename,
1457 /*4*/ SwFieldIds::DateTime }; // MUST be at the end!
1458
1459 for(SwFieldIds aType : aTypes)
1460 {
1461 std::vector<SwFormatField*> vFields;
1462 GetSysFieldType(aType)->GatherFields(vFields);
1463 for(auto pFormatField: vFields)
1464 {
1465 if (pFormatField->GetTextField())
1466 {
1467 bool bChgd = false;
1468 switch( aType )
1469 {
1470 case SwFieldIds::DocInfo:
1471 if( static_cast<SwDocInfoField*>(pFormatField->GetField())->IsFixed() )
1472 {
1473 bChgd = true;
1474 SwDocInfoField* pDocInfField = static_cast<SwDocInfoField*>(pFormatField->GetField());
1475 pDocInfField->SetExpansion( static_cast<SwDocInfoFieldType*>(
1476 pDocInfField->GetTyp())->Expand(
1477 pDocInfField->GetSubType(),
1478 pDocInfField->GetFormat(),
1479 pDocInfField->GetLanguage(),
1480 pDocInfField->GetName() ) );
1481 }
1482 break;
1483
1484 case SwFieldIds::Author:
1485 if( static_cast<SwAuthorField*>(pFormatField->GetField())->IsFixed() )
1486 {
1487 bChgd = true;
1488 SwAuthorField* pAuthorField = static_cast<SwAuthorField*>(pFormatField->GetField());
1489 pAuthorField->SetExpansion( SwAuthorFieldType::Expand( pAuthorField->GetFormat() ) );
1490 }
1491 break;
1492
1493 case SwFieldIds::ExtUser:
1494 if( static_cast<SwExtUserField*>(pFormatField->GetField())->IsFixed() )
1495 {
1496 bChgd = true;
1497 SwExtUserField* pExtUserField = static_cast<SwExtUserField*>(pFormatField->GetField());
1498 pExtUserField->SetExpansion( SwExtUserFieldType::Expand(pExtUserField->GetSubType()) );
1499 }
1500 break;
1501
1502 case SwFieldIds::DateTime:
1503 if( static_cast<SwDateTimeField*>(pFormatField->GetField())->IsFixed() )
1504 {
1505 bChgd = true;
1506 static_cast<SwDateTimeField*>(pFormatField->GetField())->SetDateTime(
1507 DateTime(Date(nDate), tools::Time(nTime)) );
1508 }
1509 break;
1510
1511 case SwFieldIds::Filename:
1512 if( static_cast<SwFileNameField*>(pFormatField->GetField())->IsFixed() )
1513 {
1514 bChgd = true;
1515 SwFileNameField* pFileNameField =
1516 static_cast<SwFileNameField*>(pFormatField->GetField());
1517 pFileNameField->SetExpansion( static_cast<SwFileNameFieldType*>(
1518 pFileNameField->GetTyp())->Expand(
1519 pFileNameField->GetFormat() ) );
1520 }
1521 break;
1522 default: break;
1523 }
1524
1525 // Trigger formatting
1526 if( bChgd )
1527 pFormatField->UpdateTextNode(nullptr, nullptr);
1528 }
1529 }
1530 }
1531
1532 if( !bIsModified )
1533 m_rDoc.getIDocumentState().ResetModified();
1534 }
1535
FieldsToCalc(SwCalc & rCalc,const SetGetExpField & rToThisField,SwRootFrame const * const pLayout)1536 void DocumentFieldsManager::FieldsToCalc(SwCalc& rCalc,
1537 const SetGetExpField& rToThisField, SwRootFrame const*const pLayout)
1538 {
1539 // create the sorted list of all SetFields
1540 mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_CALC );
1541 mbNewFieldLst = false;
1542
1543 #if !HAVE_FEATURE_DBCONNECTIVITY
1544 SwDBManager* pMgr = NULL;
1545 #else
1546 SwDBManager* pMgr = m_rDoc.GetDBManager();
1547 pMgr->CloseAll(false);
1548 #endif
1549
1550 if (!mpUpdateFields->GetSortList()->empty())
1551 {
1552 SetGetExpFields::const_iterator const itLast =
1553 mpUpdateFields->GetSortList()->upper_bound(
1554 &rToThisField);
1555 for (auto it = mpUpdateFields->GetSortList()->begin(); it != itLast; ++it)
1556 {
1557 lcl_CalcField(m_rDoc, rCalc, **it, pMgr, pLayout);
1558 }
1559 }
1560 #if HAVE_FEATURE_DBCONNECTIVITY
1561 pMgr->CloseAll(false);
1562 #endif
1563 }
1564
FieldsToCalc(SwCalc & rCalc,sal_uLong const nLastNd,sal_Int32 const nLastCnt)1565 void DocumentFieldsManager::FieldsToCalc(SwCalc& rCalc,
1566 sal_uLong const nLastNd, sal_Int32 const nLastCnt)
1567 {
1568 // create the sorted list of all SetFields
1569 mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_CALC );
1570 mbNewFieldLst = false;
1571
1572 #if !HAVE_FEATURE_DBCONNECTIVITY
1573 SwDBManager* pMgr = NULL;
1574 #else
1575 SwDBManager* pMgr = m_rDoc.GetDBManager();
1576 pMgr->CloseAll(false);
1577 #endif
1578
1579 SwRootFrame const* pLayout(nullptr);
1580 SwRootFrame const* pLayoutRLHidden(nullptr);
1581 for (SwRootFrame const*const pLay : m_rDoc.GetAllLayouts())
1582 {
1583 if (pLay->IsHideRedlines())
1584 {
1585 pLayoutRLHidden = pLay;
1586 }
1587 else
1588 {
1589 pLayout = pLay;
1590 }
1591 }
1592
1593 // note this is not duplicate of the other FieldsToCalc because there is
1594 // (currently) no SetGetExpField that compares only a position
1595 for(auto it = mpUpdateFields->GetSortList()->begin();
1596 it != mpUpdateFields->GetSortList()->end() &&
1597 ( (*it)->GetNode() < nLastNd ||
1598 ( (*it)->GetNode() == nLastNd && (*it)->GetContent() <= nLastCnt )
1599 );
1600 ++it )
1601 {
1602 if (pLayout || !pLayoutRLHidden) // always calc *something*...
1603 {
1604 lcl_CalcField( m_rDoc, rCalc, **it, pMgr, pLayout );
1605 }
1606 if (pLayoutRLHidden)
1607 {
1608 lcl_CalcField( m_rDoc, rCalc, **it, pMgr, pLayoutRLHidden );
1609 }
1610 }
1611
1612 #if HAVE_FEATURE_DBCONNECTIVITY
1613 pMgr->CloseAll(false);
1614 #endif
1615 }
1616
FieldsToExpand(SwHashTable<HashStr> & rHashTable,const SetGetExpField & rToThisField,SwRootFrame const & rLayout)1617 void DocumentFieldsManager::FieldsToExpand( SwHashTable<HashStr> & rHashTable,
1618 const SetGetExpField& rToThisField, SwRootFrame const& rLayout)
1619 {
1620 // create the sorted list of all SetFields
1621 mpUpdateFields->MakeFieldList( m_rDoc, mbNewFieldLst, GETFLD_EXPAND );
1622 mbNewFieldLst = false;
1623
1624 IDocumentRedlineAccess const& rIDRA(m_rDoc.getIDocumentRedlineAccess());
1625
1626 // Hash table for all string replacements is filled on-the-fly.
1627 // Try to fabricate an uneven number.
1628 sal_uInt16 nTableSize = ((mpUpdateFields->GetSortList()->size() / 7) + 1) * 7;
1629 rHashTable.resize(nTableSize);
1630
1631 SetGetExpFields::const_iterator const itLast =
1632 mpUpdateFields->GetSortList()->upper_bound(&rToThisField);
1633
1634 for (auto it = mpUpdateFields->GetSortList()->begin(); it != itLast; ++it)
1635 {
1636 const SwTextField* pTextField = (*it)->GetTextField();
1637 if( !pTextField )
1638 continue;
1639
1640 if (rLayout.IsHideRedlines()
1641 && IsFieldDeleted(rIDRA, rLayout, *pTextField))
1642 {
1643 continue;
1644 }
1645
1646 const SwField* pField = pTextField->GetFormatField().GetField();
1647 switch( pField->GetTyp()->Which() )
1648 {
1649 case SwFieldIds::SetExp:
1650 if( nsSwGetSetExpType::GSE_STRING & pField->GetSubType() )
1651 {
1652 // set the new value in the hash table
1653 // is the formula a field?
1654 SwSetExpField* pSField = const_cast<SwSetExpField*>(static_cast<const SwSetExpField*>(pField));
1655 OUString aNew = LookString( rHashTable, pSField->GetFormula() );
1656
1657 if( aNew.isEmpty() ) // nothing found, then the formula is
1658 aNew = pSField->GetFormula(); // the new value
1659
1660 // #i3141# - update expression of field as in method
1661 // <SwDoc::UpdateExpFields(..)> for string/text fields
1662 pSField->ChgExpStr(aNew, &rLayout);
1663
1664 // look up the field's name
1665 aNew = static_cast<SwSetExpFieldType*>(pSField->GetTyp())->GetSetRefName();
1666 // Entry present?
1667 sal_uInt16 nPos;
1668 SwHash* pFnd = rHashTable.Find( aNew, &nPos );
1669 if( pFnd )
1670 // modify entry in the hash table
1671 static_cast<HashStr*>(pFnd)->aSetStr = pSField->GetExpStr(&rLayout);
1672 else
1673 // insert the new entry
1674 rHashTable[nPos].reset( new HashStr( aNew,
1675 pSField->GetExpStr(&rLayout), rHashTable[nPos].release()));
1676 }
1677 break;
1678 case SwFieldIds::Database:
1679 {
1680 const OUString& rName = pField->GetTyp()->GetName();
1681
1682 // Insert entry in the hash table
1683 // Entry present?
1684 sal_uInt16 nPos;
1685 HashStr* pFnd = rHashTable.Find( rName, &nPos );
1686 OUString const value(pField->ExpandField(m_rDoc.IsClipBoard(), nullptr));
1687 if( pFnd )
1688 {
1689 // modify entry in the hash table
1690 pFnd->aSetStr = value;
1691 }
1692 else
1693 {
1694 // insert the new entry
1695 rHashTable[nPos].reset( new HashStr( rName,
1696 value, rHashTable[nPos].release()) );
1697 }
1698 }
1699 break;
1700 default: break;
1701 }
1702 }
1703 }
1704
1705
IsNewFieldLst() const1706 bool DocumentFieldsManager::IsNewFieldLst() const
1707 {
1708 return mbNewFieldLst;
1709 }
1710
SetNewFieldLst(bool bFlag)1711 void DocumentFieldsManager::SetNewFieldLst(bool bFlag)
1712 {
1713 mbNewFieldLst = bFlag;
1714 }
1715
InsDelFieldInFieldLst(bool bIns,const SwTextField & rField)1716 void DocumentFieldsManager::InsDelFieldInFieldLst( bool bIns, const SwTextField& rField )
1717 {
1718 if (!mbNewFieldLst && !m_rDoc.IsInDtor())
1719 mpUpdateFields->InsDelFieldInFieldLst( bIns, rField );
1720 }
1721
GetFieldAtPos(const SwPosition & rPos)1722 SwField * DocumentFieldsManager::GetFieldAtPos(const SwPosition & rPos)
1723 {
1724 SwTextField * const pAttr = GetTextFieldAtPos(rPos);
1725
1726 return pAttr ? const_cast<SwField *>( pAttr->GetFormatField().GetField() ) : nullptr;
1727 }
1728
GetTextFieldAtPos(const SwPosition & rPos)1729 SwTextField * DocumentFieldsManager::GetTextFieldAtPos(const SwPosition & rPos)
1730 {
1731 SwTextNode * const pNode = rPos.nNode.GetNode().GetTextNode();
1732
1733 return (pNode != nullptr)
1734 ? pNode->GetFieldTextAttrAt( rPos.nContent.GetIndex(), true )
1735 : nullptr;
1736 }
1737
1738 /// @note For simplicity assume that all field types have updatable contents so
1739 /// optimization currently only available when no fields exist.
containsUpdatableFields()1740 bool DocumentFieldsManager::containsUpdatableFields()
1741 {
1742 std::vector<SwFormatField*> vFields;
1743 for (auto const& pFieldType: *mpFieldTypes)
1744 {
1745 pFieldType->GatherFields(vFields);
1746 if(vFields.size()>0)
1747 return true;
1748 }
1749 return false;
1750 }
1751
1752 /// Remove all unreferenced field types of a document
GCFieldTypes()1753 void DocumentFieldsManager::GCFieldTypes()
1754 {
1755 for( auto n = mpFieldTypes->size(); n > INIT_FLDTYPES; )
1756 if( !(*mpFieldTypes)[ --n ]->HasWriterListeners() )
1757 RemoveFieldType( n );
1758 }
1759
InitFieldTypes()1760 void DocumentFieldsManager::InitFieldTypes() // is being called by the CTOR
1761 {
1762 // Field types
1763 mpFieldTypes->emplace_back( new SwDateTimeFieldType(&m_rDoc) );
1764 mpFieldTypes->emplace_back( new SwChapterFieldType );
1765 mpFieldTypes->emplace_back( new SwPageNumberFieldType );
1766 mpFieldTypes->emplace_back( new SwAuthorFieldType );
1767 mpFieldTypes->emplace_back( new SwFileNameFieldType(m_rDoc) );
1768 mpFieldTypes->emplace_back( new SwDBNameFieldType(&m_rDoc) );
1769 mpFieldTypes->emplace_back( new SwGetExpFieldType(&m_rDoc) );
1770 mpFieldTypes->emplace_back( new SwGetRefFieldType(m_rDoc) );
1771 mpFieldTypes->emplace_back( new SwHiddenTextFieldType );
1772 mpFieldTypes->emplace_back( new SwPostItFieldType(m_rDoc) );
1773 mpFieldTypes->emplace_back( new SwDocStatFieldType(m_rDoc) );
1774 mpFieldTypes->emplace_back( new SwDocInfoFieldType(&m_rDoc) );
1775 mpFieldTypes->emplace_back( new SwInputFieldType( &m_rDoc ) );
1776 mpFieldTypes->emplace_back( new SwTableFieldType( &m_rDoc ) );
1777 mpFieldTypes->emplace_back( new SwMacroFieldType(m_rDoc) );
1778 mpFieldTypes->emplace_back( new SwHiddenParaFieldType );
1779 mpFieldTypes->emplace_back( new SwDBNextSetFieldType );
1780 mpFieldTypes->emplace_back( new SwDBNumSetFieldType );
1781 mpFieldTypes->emplace_back( new SwDBSetNumberFieldType );
1782 mpFieldTypes->emplace_back( new SwTemplNameFieldType(m_rDoc) );
1783 mpFieldTypes->emplace_back( new SwTemplNameFieldType(m_rDoc) );
1784 mpFieldTypes->emplace_back( new SwExtUserFieldType );
1785 mpFieldTypes->emplace_back( new SwRefPageSetFieldType );
1786 mpFieldTypes->emplace_back( new SwRefPageGetFieldType(m_rDoc) );
1787 mpFieldTypes->emplace_back( new SwJumpEditFieldType(m_rDoc) );
1788 mpFieldTypes->emplace_back( new SwScriptFieldType(m_rDoc) );
1789 mpFieldTypes->emplace_back( new SwCombinedCharFieldType );
1790 mpFieldTypes->emplace_back( new SwDropDownFieldType );
1791
1792 // Types have to be at the end!
1793 // We expect this in the InsertFieldType!
1794 // MIB 14.04.95: In Sw3StringPool::Setup (sw3imp.cxx) and
1795 // lcl_sw3io_InSetExpField (sw3field.cxx) now also
1796 mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1797 SwResId(STR_POOLCOLL_LABEL_ABB), nsSwGetSetExpType::GSE_SEQ) );
1798 mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1799 SwResId(STR_POOLCOLL_LABEL_TABLE), nsSwGetSetExpType::GSE_SEQ) );
1800 mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1801 SwResId(STR_POOLCOLL_LABEL_FRAME), nsSwGetSetExpType::GSE_SEQ) );
1802 mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1803 SwResId(STR_POOLCOLL_LABEL_DRAWING), nsSwGetSetExpType::GSE_SEQ) );
1804 mpFieldTypes->emplace_back( new SwSetExpFieldType(&m_rDoc,
1805 SwResId(STR_POOLCOLL_LABEL_FIGURE), nsSwGetSetExpType::GSE_SEQ) );
1806
1807 assert( mpFieldTypes->size() == INIT_FLDTYPES );
1808 }
1809
ClearFieldTypes()1810 void DocumentFieldsManager::ClearFieldTypes()
1811 {
1812 mpFieldTypes->erase( mpFieldTypes->begin() + INIT_FLDTYPES, mpFieldTypes->end() );
1813 }
1814
UpdateDBNumFields(SwDBNameInfField & rDBField,SwCalc & rCalc)1815 void DocumentFieldsManager::UpdateDBNumFields( SwDBNameInfField& rDBField, SwCalc& rCalc )
1816 {
1817 #if !HAVE_FEATURE_DBCONNECTIVITY
1818 (void) rDBField;
1819 (void) rCalc;
1820 #else
1821 SwDBManager* pMgr = m_rDoc.GetDBManager();
1822
1823 SwFieldIds nFieldType = rDBField.Which();
1824
1825 bool bPar1 = rCalc.Calculate( rDBField.GetPar1() ).GetBool();
1826
1827 if( SwFieldIds::DbNextSet == nFieldType )
1828 static_cast<SwDBNextSetField&>(rDBField).SetCondValid( bPar1 );
1829 else
1830 static_cast<SwDBNumSetField&>(rDBField).SetCondValid( bPar1 );
1831
1832 if( !rDBField.GetRealDBData().sDataSource.isEmpty() )
1833 {
1834 // Edit a certain database
1835 if( SwFieldIds::DbNextSet == nFieldType )
1836 static_cast<SwDBNextSetField&>(rDBField).Evaluate(m_rDoc);
1837 else
1838 static_cast<SwDBNumSetField&>(rDBField).Evaluate(m_rDoc);
1839
1840 SwDBData aTmpDBData( rDBField.GetDBData(&m_rDoc) );
1841
1842 if( pMgr->OpenDataSource( aTmpDBData.sDataSource, aTmpDBData.sCommand ))
1843 rCalc.VarChange( lcl_GetDBVarName( m_rDoc, rDBField),
1844 pMgr->GetSelectedRecordId(aTmpDBData.sDataSource, aTmpDBData.sCommand, aTmpDBData.nCommandType) );
1845 }
1846 else
1847 {
1848 OSL_FAIL("TODO: what should happen with unnamed DBFields?");
1849 }
1850 #endif
1851 }
1852
~DocumentFieldsManager()1853 DocumentFieldsManager::~DocumentFieldsManager()
1854 {
1855 mpUpdateFields.reset();
1856 mpFieldTypes.reset();
1857 }
1858
1859 }
1860
1861 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1862